diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cl_console.c | 2 | ||||
-rw-r--r-- | src/cl_main.c | 2 | ||||
-rw-r--r-- | src/cmd.c | 2 | ||||
-rw-r--r-- | src/files.c | 256 | ||||
-rw-r--r-- | src/files.h | 19 | ||||
-rw-r--r-- | src/sv_ccmds.c | 2 | ||||
-rw-r--r-- | src/sys_public.h | 4 | ||||
-rw-r--r-- | src/sys_unix.c | 220 | ||||
-rw-r--r-- | src/sys_win.c | 231 | ||||
-rw-r--r-- | src/ui_demos.c | 2 |
10 files changed, 322 insertions, 418 deletions
diff --git a/src/cl_console.c b/src/cl_console.c index a275889..c65f174 100644 --- a/src/cl_console.c +++ b/src/cl_console.c @@ -188,7 +188,7 @@ static void Con_Clear_f( void ) { static void Con_Dump_c( genctx_t *ctx, int argnum ) { if( argnum == 1 ) { - FS_File_g( "condumps", ".txt", 0x80000000, ctx ); + FS_File_g( "condumps", ".txt", FS_SEARCH_STRIPEXT, ctx ); } } diff --git a/src/cl_main.c b/src/cl_main.c index 9d64a73..f4cb53e 100644 --- a/src/cl_main.c +++ b/src/cl_main.c @@ -1625,7 +1625,7 @@ Moved here from sound code so that command is always registered. ================= */ static void CL_PlaySound_c( genctx_t *ctx, int state ) { - FS_File_g( "sound", "*.wav", FS_SEARCH_SAVEPATH | FS_SEARCH_BYFILTER | 0x80000000, ctx ); + FS_File_g( "sound", "*.wav", FS_SEARCH_SAVEPATH | FS_SEARCH_BYFILTER | FS_SEARCH_STRIPEXT, ctx ); } static void CL_PlaySound_f( void ) { @@ -1552,7 +1552,7 @@ finish: } void Cmd_Config_g( genctx_t *ctx ) { - FS_File_g( "", "*.cfg", FS_SEARCH_SAVEPATH | FS_SEARCH_BYFILTER | 0x80000000, ctx ); + FS_File_g( "", "*.cfg", FS_SEARCH_SAVEPATH | FS_SEARCH_BYFILTER | FS_SEARCH_STRIPEXT, ctx ); } static void Cmd_Exec_c( genctx_t *ctx, int argnum ) { diff --git a/src/files.c b/src/files.c index 92fa2d5..097874a 100644 --- a/src/files.c +++ b/src/files.c @@ -1979,23 +1979,23 @@ alphacmp: } static void load_pack_files( unsigned mode, const char *ext, pack_t *(loadfunc)( const char * ) ) { - int i; searchpath_t *search; pack_t *pack; - void **list; - int num_files; + void *files[MAX_LISTED_FILES]; + int i, count; char path[MAX_OSPATH]; size_t len; - list = Sys_ListFiles( fs_gamedir, ext, FS_SEARCH_NOSORT, 0, &num_files ); - if( !list ) { + count = 0; + Sys_ListFiles_r( fs_gamedir, ext, 0, 0, &count, files, 0 ); + if( !count ) { return; } - qsort( list, num_files, sizeof( list[0] ), pakcmp ); + qsort( files, count, sizeof( files[0] ), pakcmp ); - for( i = 0; i < num_files; i++ ) { - len = Q_concat( path, sizeof( path ), fs_gamedir, "/", list[i], NULL ); + for( i = 0; i < count; i++ ) { + len = Q_concat( path, sizeof( path ), fs_gamedir, "/", files[i], NULL ); if( len >= sizeof( path ) ) { Com_EPrintf( "%s: refusing oversize path\n", __func__ ); continue; @@ -2011,7 +2011,9 @@ static void load_pack_files( unsigned mode, const char *ext, pack_t *(loadfunc)( fs_searchpaths = search; } - FS_FreeList( list ); + for( i = 0; i < count; i++ ) { + Z_Free( files[i] ); + } } // Sets fs_gamedir, adds the directory to the head of the path, @@ -2086,6 +2088,10 @@ void **FS_CopyList( void **list, int count ) { void **out; int i; + if( !count ) { + return NULL; + } + out = FS_Malloc( sizeof( void * ) * ( count + 1 ) ); for( i = 0; i < count; i++ ) { out[i] = list[i]; @@ -2215,33 +2221,22 @@ FS_ListFiles ================= */ void **FS_ListFiles( const char *path, - const char *extension, - int flags, - int *numFiles ) + const char *filter, + unsigned flags, + int *count_p ) { searchpath_t *search; - void *listedFiles[MAX_LISTED_FILES]; - int count, total; + packfile_t *file; + void *files[MAX_LISTED_FILES], *info; + int i, count, total; char buffer[MAX_OSPATH]; - void **dirlist; - int dircount; void **list; - int i; size_t len, pathlen; - char *s; - int valid = -1; - - if( flags & FS_SEARCH_BYFILTER ) { - if( !extension ) { - Com_Error( ERR_FATAL, "FS_ListFiles: NULL filter" ); - } - } + char *s, *p; + int valid; count = 0; - - if( numFiles ) { - *numFiles = 0; - } + valid = -1; if( !path ) { path = ""; @@ -2261,80 +2256,79 @@ void **FS_ListFiles( const char *path, } if( search->pack ) { if( ( flags & FS_TYPE_MASK ) == FS_TYPE_REAL ) { - // don't search in paks - continue; + continue; // don't search in paks } // TODO: add directory search support for pak files - if( ( flags & FS_SEARCHDIRS_MASK ) == FS_SEARCHDIRS_ONLY ) { + if( flags & FS_SEARCH_DIRSONLY ) { continue; } - if( flags & FS_SEARCH_BYFILTER ) { - for( i = 0; i < search->pack->num_files; i++ ) { - s = search->pack->files[i].name; - - // check path - if( pathlen ) { - if( FS_pathcmpn( s, path, pathlen ) ) { - continue; - } - s += pathlen + 1; - } + for( i = 0; i < search->pack->num_files; i++ ) { + file = &search->pack->files[i]; + s = file->name; - // check filter - if( !FS_WildCmp( extension, s ) ) { + // check path + if( pathlen ) { + if( FS_pathcmpn( s, path, pathlen ) ) { continue; } - - // copy filename - if( count == MAX_LISTED_FILES ) { - break; + if( s[pathlen] != '/' ) { + continue; // matched prefix must be a directory } - - if( !( flags & FS_SEARCH_SAVEPATH ) ) { - s = COM_SkipPath( s ); + if( flags & FS_SEARCH_BYFILTER ) { + s += pathlen + 1; } - if( flags & FS_SEARCH_EXTRAINFO ) { - listedFiles[count++] = FS_CopyInfo( s, - search->pack->files[i].filelen, 0, 0 ); + } + + // check filter + if( filter ) { + if( flags & FS_SEARCH_BYFILTER ) { + if( !FS_WildCmp( filter, s ) ) { + continue; + } } else { - listedFiles[count++] = FS_CopyString( s ); + if( !FS_ExtCmp( filter, s ) ) { + continue; + } } } - } else { - for( i = 0; i < search->pack->num_files; i++ ) { - s = search->pack->files[i].name; - - // check path - if( pathlen && FS_pathcmpn( s, path, pathlen ) ) { - continue; - } - // check extension - if( extension && !FS_ExtCmp( extension, s ) ) { - continue; - } - - // copy filename - if( count == MAX_LISTED_FILES ) { - break; - } - if( !( flags & FS_SEARCH_SAVEPATH ) ) { - s = COM_SkipPath( s ); - } - if( flags & FS_SEARCH_EXTRAINFO ) { - listedFiles[count++] = FS_CopyInfo( s, - search->pack->files[i].filelen, 0, 0 ); - } else { - listedFiles[count++] = FS_CopyString( s ); + // strip path + if( !( flags & FS_SEARCH_SAVEPATH ) ) { + s = COM_SkipPath( s ); + } + + // strip extension + if( flags & FS_SEARCH_STRIPEXT ) { + p = COM_FileExtension( s ); + if( *p ) { + len = p - s; + s = memcpy( buffer, s, len ); + s[len] = 0; } } + + if( !*s ) { + continue; + } + + // copy info off + if( flags & FS_SEARCH_EXTRAINFO ) { + info = FS_CopyInfo( s, file->filelen, 0, 0 ); + } else { + info = FS_CopyString( s ); + } + + files[count++] = info; + + if( count >= MAX_LISTED_FILES ) { + break; + } } } else { if( ( flags & FS_TYPE_MASK ) == FS_TYPE_PAK ) { - // don't search in OS filesystem - continue; + continue; // don't search in filesystem } len = strlen( search->filename ); @@ -2353,10 +2347,9 @@ void **FS_ListFiles( const char *path, if( valid == 0 ) { continue; } - memcpy( buffer, search->filename, len ); - buffer[len++] = '/'; - memcpy( buffer + len, path, pathlen + 1 ); - s = buffer; + s = memcpy( buffer, search->filename, len ); + s[len++] = '/'; + memcpy( s + len, path, pathlen + 1 ); } else { s = search->filename; } @@ -2365,45 +2358,35 @@ void **FS_ListFiles( const char *path, len += pathlen + 1; } - dirlist = Sys_ListFiles( s, extension, - flags|FS_SEARCH_NOSORT, len, &dircount ); - if( !dirlist ) { - continue; - } - - if( count + dircount > MAX_LISTED_FILES ) { - dircount = MAX_LISTED_FILES - count; - } - for( i = 0; i < dircount; i++ ) { - listedFiles[count++] = dirlist[i]; - } - - Z_Free( dirlist ); - + Sys_ListFiles_r( s, filter, flags, len, &count, files, 0 ); } - if( count == MAX_LISTED_FILES ) { + + if( count >= MAX_LISTED_FILES ) { break; } } if( !count ) { + if( count_p ) { + *count_p = 0; + } return NULL; } if( flags & FS_SEARCH_EXTRAINFO ) { // TODO - qsort( listedFiles, count, sizeof( listedFiles[0] ), infocmp ); + qsort( files, count, sizeof( files[0] ), infocmp ); total = count; } else { - // sort alphabetically (ignoring FS_SEARCH_NOSORT) - qsort( listedFiles, count, sizeof( listedFiles[0] ), alphacmp ); + // sort alphabetically + qsort( files, count, sizeof( files[0] ), alphacmp ); // remove duplicates total = 1; for( i = 1; i < count; i++ ) { - if( !FS_pathcmp( listedFiles[ i - 1 ], listedFiles[i] ) ) { - Z_Free( listedFiles[ i - 1 ] ); - listedFiles[i-1] = NULL; + if( !FS_pathcmp( files[ i - 1 ], files[i] ) ) { + Z_Free( files[ i - 1 ] ); + files[i-1] = NULL; } else { total++; } @@ -2414,14 +2397,14 @@ void **FS_ListFiles( const char *path, total = 0; for( i = 0; i < count; i++ ) { - if( listedFiles[i] ) { - list[total++] = listedFiles[i]; + if( files[i] ) { + list[total++] = files[i]; } } list[total] = NULL; - if( numFiles ) { - *numFiles = total; + if( count_p ) { + *count_p = total; } return list; @@ -2433,19 +2416,23 @@ FS_FreeList ================= */ void FS_FreeList( void **list ) { - void **p = list; + void **p; - while( *p ) { - Z_Free( *p++ ); + if( !list ) { + return; + } + + for( p = list; *p; p++ ) { + Z_Free( *p ); } Z_Free( list ); } -void FS_File_g( const char *path, const char *ext, int flags, genctx_t *ctx ) { +void FS_File_g( const char *path, const char *ext, unsigned flags, genctx_t *ctx ) { int i, numFiles; void **list; - char *s, *p; + char *s; list = FS_ListFiles( path, ext, flags, &numFiles ); if( !list ) { @@ -2454,10 +2441,6 @@ void FS_File_g( const char *path, const char *ext, int flags, genctx_t *ctx ) { for( i = 0; i < numFiles; i++ ) { s = list[i]; - if( flags & 0x80000000 ) { - p = COM_FileExtension( s ); - *p = 0; - } if( ctx->count < ctx->size && !strncmp( s, ctx->partial, ctx->length ) ) { ctx->matches[ctx->count++] = s; } else { @@ -2468,18 +2451,25 @@ void FS_File_g( const char *path, const char *ext, int flags, genctx_t *ctx ) { Z_Free( list ); } -static void print_file_list( const char *path, const char *ext, int flags ) { +static void print_file_list( const char *path, const char *ext, unsigned flags ) { void **list; - int ndirs = 0; - int i; + int i, listed, total; - if( ( list = FS_ListFiles( path, ext, flags, &ndirs ) ) != NULL ) { - for( i = 0; i < ndirs; i++ ) { - Com_Printf( "%s\n", ( char * )list[i] ); - } - FS_FreeList( list ); + list = FS_ListFiles( path, ext, flags, &total ); + + // don't list too many files to avoid console spam + listed = total > 128 ? 128 : total; + for( i = 0; i < listed; i++ ) { + Com_Printf( "%s\n", ( char * )list[i] ); + } + + FS_FreeList( list ); + + if( listed == total ) { + Com_Printf( "%i files listed\n", listed ); + } else { + Com_Printf( "%i files listed (%d files more)\n", listed, total - listed ); } - Com_Printf( "%i files listed\n", ndirs ); } /* @@ -2488,8 +2478,8 @@ FS_FDir_f ============ */ static void FS_FDir_f( void ) { - int flags; - char *filter; + unsigned flags; + char *filter; if( Cmd_Argc() < 2 ) { Com_Printf( "Usage: %s <filter> [full_path]\n", Cmd_Argv( 0 ) ); diff --git a/src/files.h b/src/files.h index 135757e..f3c7ff7 100644 --- a/src/files.h +++ b/src/files.h @@ -18,7 +18,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#define MAX_LISTED_FILES 4096 +#define MAX_LISTED_FILES 2048 +#define MAX_LISTED_DEPTH 8 typedef struct file_info_s { size_t size; @@ -34,13 +35,6 @@ typedef struct file_info_s { #define FS_MODE_RDWR 0x00000003 #define FS_MODE_MASK 0x00000003 -/* bits 0 - 1, enum */ -#define FS_SEARCHDIRS_NO 0x00000000 -#define FS_SEARCHDIRS_YES 0x00000001 -#define FS_SEARCHDIRS_ONLY 0x00000002 -#define FS_SEARCHDIRS_RESERVED 0x00000003 -#define FS_SEARCHDIRS_MASK 0x00000003 - /* bit 2, enum */ #define FS_FLUSH_NONE 0x00000000 #define FS_FLUSH_SYNC 0x00000004 @@ -59,11 +53,12 @@ typedef struct file_info_s { #define FS_PATH_GAME 0x00000040 #define FS_PATH_MASK 0x00000060 -/* bits 7 - 10, flag */ +/* bits 7 - 11, flag */ #define FS_SEARCH_BYFILTER 0x00000080 #define FS_SEARCH_SAVEPATH 0x00000100 #define FS_SEARCH_EXTRAINFO 0x00000200 -#define FS_SEARCH_NOSORT 0x00000400 +#define FS_SEARCH_STRIPEXT 0x00000400 +#define FS_SEARCH_DIRSONLY 0x00000800 /* bits 7 - 8, flag */ #define FS_FLAG_GZIP 0x00000080 @@ -127,7 +122,7 @@ ssize_t FS_GetFileLength( qhandle_t f ); qboolean FS_WildCmp( const char *filter, const char *string ); qboolean FS_ExtCmp( const char *extension, const char *string ); -void **FS_ListFiles( const char *path, const char *extension, int flags, int *numFiles ); +void **FS_ListFiles( const char *path, const char *filter, unsigned flags, int *count_p ); void **FS_CopyList( void **list, int count ); file_info_t *FS_CopyInfo( const char *name, size_t size, time_t ctime, time_t mtime ); void FS_FreeList( void **list ); @@ -137,7 +132,7 @@ char *FS_ReplaceSeparators( char *s, int separator ); int FS_pathcmp( const char *s1, const char *s2 ); int FS_pathcmpn( const char *s1, const char *s2, size_t n ); -void FS_File_g( const char *path, const char *ext, int flags, genctx_t *ctx ); +void FS_File_g( const char *path, const char *ext, unsigned flags, genctx_t *ctx ); extern cvar_t *fs_game; diff --git a/src/sv_ccmds.c b/src/sv_ccmds.c index a30bdec..d442687 100644 --- a/src/sv_ccmds.c +++ b/src/sv_ccmds.c @@ -340,7 +340,7 @@ static void SV_Map_f( void ) { static void SV_Map_c( genctx_t *ctx, int argnum ) { if( argnum == 1 ) { - FS_File_g( "maps", ".bsp", 0x80000000, ctx ); + FS_File_g( "maps", ".bsp", FS_SEARCH_STRIPEXT, ctx ); } } diff --git a/src/sys_public.h b/src/sys_public.h index 76280a8..1ebf7e8 100644 --- a/src/sys_public.h +++ b/src/sys_public.h @@ -52,8 +52,8 @@ void Sys_Printf( const char *fmt, ... ) q_printf( 1, 2 ); void Sys_Error( const char *error, ... ) q_noreturn q_printf( 1, 2 ); void Sys_Quit( void ) q_noreturn; -void **Sys_ListFiles( const char *path, const char *extension, - int flags, size_t length, int *numFiles ); +void Sys_ListFiles_r( const char *path, const char *filter, + unsigned flags, size_t baselen, int *count_p, void **files, int depth ); struct file_info_s; qerror_t Sys_GetPathInfo( const char *path, struct file_info_s *info ); diff --git a/src/sys_unix.c b/src/sys_unix.c index 1ab3630..94ec24e 100644 --- a/src/sys_unix.c +++ b/src/sys_unix.c @@ -835,187 +835,123 @@ MISC =============================================================================== */ +static void *copy_info( const char *name, const struct stat *st ) { + return FS_CopyInfo( name, st->st_size, st->st_ctime, st->st_mtime ); +} + /* ================= -Sys_ListFilteredFiles +Sys_ListFiles_r + +Internal function to filesystem. Conventions apply: + - files should hold at least MAX_LISTED_FILES + - *count_p must be initialized in range [0, MAX_LISTED_FILES - 1] + - depth must be 0 on the first call ================= */ -static void Sys_ListFilteredFiles( void **listedFiles, - int *count, - const char *path, - const char *filter, - int flags, - size_t baselen, - int depth ) +void Sys_ListFiles_r( const char *path, + const char *filter, + unsigned flags, + size_t baselen, + int *count_p, + void **files, + int depth ) { - struct dirent *findInfo; - DIR *findHandle; - struct stat st; - char findPath[MAX_OSPATH]; - char *name; - size_t len; - - if( depth >= 32 ) { - return; - } - - if( *count >= MAX_LISTED_FILES ) { - return; - } + struct dirent *ent; + DIR *dir; + struct stat st; + char fullpath[MAX_OSPATH]; + char *name; + size_t len; + void *info; - if( ( findHandle = opendir( path ) ) == NULL ) { + if( ( dir = opendir( path ) ) == NULL ) { return; } - while( ( findInfo = readdir( findHandle ) ) != NULL ) { - if( !strcmp( findInfo->d_name, "." ) ) { - continue; - } - if( !strcmp( findInfo->d_name, ".." ) ) { - continue; - } - len = Q_concat( findPath, sizeof( findPath ), - path, "/", findInfo->d_name, NULL ); - if( len >= sizeof( findPath ) ) { - continue; + while( ( ent = readdir( dir ) ) != NULL ) { + if( ent->d_name[0] == '.' ) { + continue; // ignore dotfiles } - if( stat( findPath, &st ) == -1 ) { + len = Q_concat( fullpath, sizeof( fullpath ), + path, "/", ent->d_name, NULL ); + if( len >= sizeof( fullpath ) ) { continue; } - if( st.st_mode & S_IFDIR ) { - Sys_ListFilteredFiles( listedFiles, count, findPath, - filter, flags, baselen, depth + 1 ); - } - - if( ( flags & FS_SEARCHDIRS_MASK ) == FS_SEARCHDIRS_ONLY ) { - if( !( st.st_mode & S_IFDIR ) ) { - continue; - } - } else if( ( flags & FS_SEARCHDIRS_MASK ) == FS_SEARCHDIRS_NO ) { - if( st.st_mode & S_IFDIR ) { - continue; - } - } - - if( !FS_WildCmp( filter, findPath + baselen ) ) { + if( stat( fullpath, &st ) == -1 ) { continue; } - if( flags & FS_SEARCH_SAVEPATH ) { - name = findPath + baselen; - } else { - name = findInfo->d_name; - } - - if( flags & FS_SEARCH_EXTRAINFO ) { - listedFiles[( *count )++] = FS_CopyInfo( name, - st.st_size, st.st_ctime, st.st_mtime ); - } else { - listedFiles[( *count )++] = FS_CopyString( name ); - } - if( *count >= MAX_LISTED_FILES ) { - break; - } - - } - - closedir( findHandle ); -} + // pattern search implies recursive search + if( ( flags & FS_SEARCH_BYFILTER ) && + S_ISDIR( st.st_mode ) && depth < MAX_LISTED_DEPTH ) + { + Sys_ListFiles_r( fullpath, filter, flags, baselen, + count_p, files, depth + 1 ); -/* -================= -Sys_ListFiles -================= -*/ -void **Sys_ListFiles( const char *path, - const char *extension, - int flags, - size_t baselen, - int *numFiles ) -{ - struct dirent *findInfo; - DIR *findHandle; - struct stat st; - char findPath[MAX_OSPATH]; - void *listedFiles[MAX_LISTED_FILES]; - int count = 0; - char *s; - size_t len; - - if( numFiles ) { - *numFiles = 0; - } - - if( flags & FS_SEARCH_BYFILTER ) { - Sys_ListFilteredFiles( listedFiles, &count, path, - extension, flags, baselen, 0 ); - } else { - if( ( findHandle = opendir( path ) ) == NULL ) { - return NULL; + // re-check count + if( *count_p >= MAX_LISTED_FILES ) { + break; + } } - while( ( findInfo = readdir( findHandle ) ) != NULL ) { - if( !strcmp( findInfo->d_name, "." ) ) { - continue; - } - if( !strcmp( findInfo->d_name, ".." ) ) { + // check type + if( flags & FS_SEARCH_DIRSONLY ) { + if( !S_ISDIR( st.st_mode ) ) { continue; } - - len = Q_concat( findPath, sizeof( findPath ), - path, "/", findInfo->d_name, NULL ); - if( len >= sizeof( findPath ) ) { + } else { + if( !S_ISREG( st.st_mode ) ) { continue; } + } - if( stat( findPath, &st ) == -1 ) { - continue; - } - if( ( flags & FS_SEARCHDIRS_MASK ) == FS_SEARCHDIRS_ONLY ) { - if( !( st.st_mode & S_IFDIR ) ) { + // check filter + if( filter ) { + if( flags & FS_SEARCH_BYFILTER ) { + if( !FS_WildCmp( filter, fullpath + baselen ) ) { continue; } - } else if( ( flags & FS_SEARCHDIRS_MASK ) == FS_SEARCHDIRS_NO ) { - if( st.st_mode & S_IFDIR ) { + } else { + if( !FS_ExtCmp( filter, ent->d_name ) ) { continue; } } + } - if( extension && !FS_ExtCmp( extension, findInfo->d_name ) ) { - continue; - } - - if( flags & FS_SEARCH_SAVEPATH ) { - s = findPath + baselen; - } else { - s = findInfo->d_name; - } - if( flags & FS_SEARCH_EXTRAINFO ) { - listedFiles[count++] = FS_CopyInfo( s, st.st_size, - st.st_ctime, st.st_mtime ); - } else { - listedFiles[count++] = FS_CopyString( s ); - } + // strip path + if( flags & FS_SEARCH_SAVEPATH ) { + name = fullpath + baselen; + } else { + name = ent->d_name; + } - if( count >= MAX_LISTED_FILES ) { - break; + // strip extension + if( flags & FS_SEARCH_STRIPEXT ) { + *COM_FileExtension( name ) = 0; + + if( !*name ) { + continue; } } - closedir( findHandle ); - } + // copy info off + if( flags & FS_SEARCH_EXTRAINFO ) { + info = copy_info( name, &st ); + } else { + info = FS_CopyString( name ); + } - if( !count ) { - return NULL; - } + files[(*count_p)++] = info; - if( numFiles ) { - *numFiles = count; + if( *count_p >= MAX_LISTED_FILES ) { + break; + } } - return FS_CopyList( listedFiles, count ); + closedir( dir ); } /* diff --git a/src/sys_win.c b/src/sys_win.c index 83aa158..35f2542 100644 --- a/src/sys_win.c +++ b/src/sys_win.c @@ -840,171 +840,154 @@ qerror_t Sys_GetFileInfo( FILE *fp, file_info_t *info ) { return Q_ERR_SUCCESS; } +static void *copy_info( const char *name, const LPWIN32_FIND_DATAA data ) { + time_t ctime = file_time_to_unix( &data->ftCreationTime ); + time_t mtime = file_time_to_unix( &data->ftLastWriteTime ); + + return FS_CopyInfo( name, data->nFileSizeLow, ctime, mtime ); +} /* ================= -Sys_ListFilteredFiles +Sys_ListFiles_r + +Internal function to filesystem. Conventions apply: + - files should hold at least MAX_LISTED_FILES + - *count_p must be initialized in range [0, MAX_LISTED_FILES - 1] + - depth must be 0 on the first call ================= */ -static void Sys_ListFilteredFiles( void **listedFiles, - int *count, - const char *path, - const char *filter, - int flags, - size_t length ) +void Sys_ListFiles_r( const char *path, + const char *filter, + unsigned flags, + size_t baselen, + int *count_p, + void **files, + int depth ) { - WIN32_FIND_DATAA findInfo; - HANDLE findHandle; - char findPath[MAX_OSPATH]; - char dirPath[MAX_OSPATH]; - char *name; + WIN32_FIND_DATAA data; + HANDLE handle; + char fullpath[MAX_OSPATH], *name; + size_t pathlen, len; + unsigned mask; + void *info; + + // optimize single extension search + if( !( flags & FS_SEARCH_BYFILTER ) && + filter && !strchr( filter, ';' ) ) + { + if( *filter == '.' ) { + filter++; + } + len = Q_concat( fullpath, sizeof( fullpath ), + path, "\\*.", filter, NULL ); + filter = NULL; // do not check it later + } else { + len = Q_concat( fullpath, sizeof( fullpath ), + path, "\\*", NULL ); + } - if( *count >= MAX_LISTED_FILES ) { + if( len >= sizeof( fullpath ) ) { return; } - Q_concat( findPath, sizeof( findPath ), path, "\\*", NULL ); + // format path to windows style + // done on the first run only + if( !depth ) { + FS_ReplaceSeparators( fullpath, '\\' ); + } - findHandle = FindFirstFileA( findPath, &findInfo ); - if( findHandle == INVALID_HANDLE_VALUE ) { + handle = FindFirstFileA( fullpath, &data ); + if( handle == INVALID_HANDLE_VALUE ) { return; } - do { - if( !strcmp( findInfo.cFileName, "." ) || !strcmp( findInfo.cFileName, ".." ) ) { - continue; - } - - if( findInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { - Q_concat( dirPath, sizeof( dirPath ), path, "\\", findInfo.cFileName, NULL ); - Sys_ListFilteredFiles( listedFiles, count, dirPath, filter, flags, length ); - } + // make it point right after the slash + pathlen = strlen( path ) + 1; - if( ( flags & FS_SEARCHDIRS_MASK ) == FS_SEARCHDIRS_ONLY ) { - if( !( findInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ) { - continue; - } - } else if( ( flags & FS_SEARCHDIRS_MASK ) == FS_SEARCHDIRS_NO ) { - if( findInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { - continue; - } + do { + if( !strcmp( data.cFileName, "." ) || + !strcmp( data.cFileName, ".." ) ) + { + continue; // ignore special entries } - Q_concat( dirPath, sizeof( dirPath ), path, "\\", findInfo.cFileName, NULL ); - if( !FS_WildCmp( filter, dirPath + length ) ) { + // construct full path + len = strlen( data.cFileName ); + if( pathlen + len >= sizeof( fullpath ) ) { continue; } - name = ( flags & FS_SEARCH_SAVEPATH ) ? dirPath + length : findInfo.cFileName; - - // reformat it back to quake filesystem style - FS_ReplaceSeparators( name, '/' ); + memcpy( fullpath + pathlen, data.cFileName, len + 1 ); - if( flags & FS_SEARCH_EXTRAINFO ) { - time_t ctime = file_time_to_unix( &findInfo.ftCreationTime ); - time_t mtime = file_time_to_unix( &findInfo.ftLastWriteTime ); - listedFiles[( *count )++] = FS_CopyInfo( name, findInfo.nFileSizeLow, ctime, mtime ); + if( data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { + mask = FS_SEARCH_DIRSONLY; } else { - listedFiles[( *count )++] = FS_CopyString( name ); + mask = 0; } - } while( *count < MAX_LISTED_FILES && FindNextFileA( findHandle, &findInfo ) != FALSE ); - - FindClose( findHandle ); -} - -/* -================= -Sys_ListFiles -================= -*/ -void **Sys_ListFiles( const char *rawPath, - const char *extension, - int flags, - size_t length, - int *numFiles ) -{ - WIN32_FIND_DATAA findInfo; - HANDLE findHandle; - char path[MAX_OSPATH]; - char findPath[MAX_OSPATH]; - void *listedFiles[MAX_LISTED_FILES]; - int count; - char *name; - - count = 0; - if( numFiles ) { - *numFiles = 0; - } - - Q_strlcpy( path, rawPath, sizeof( path ) ); - FS_ReplaceSeparators( path, '\\' ); + // pattern search implies recursive search + if( ( flags & FS_SEARCH_BYFILTER ) && mask && + depth < MAX_LISTED_DEPTH ) + { + Sys_ListFiles_r( fullpath, filter, flags, baselen, + count_p, files, depth + 1 ); - if( flags & FS_SEARCH_BYFILTER ) { - Q_strlcpy( findPath, extension, sizeof( findPath ) ); - FS_ReplaceSeparators( findPath, '\\' ); - Sys_ListFilteredFiles( listedFiles, &count, path, findPath, flags, length ); - } else { - if( !extension || strchr( extension, ';' ) ) { - Q_concat( findPath, sizeof( findPath ), path, "\\*", NULL ); - } else { - if( *extension == '.' ) { - extension++; + // re-check count + if( *count_p >= MAX_LISTED_FILES ) { + break; } - Q_concat( findPath, sizeof( findPath ), path, "\\*.", extension, NULL ); - extension = NULL; // do not check later - } - - findHandle = FindFirstFileA( findPath, &findInfo ); - if( findHandle == INVALID_HANDLE_VALUE ) { - return NULL; } - do { - if( !strcmp( findInfo.cFileName, "." ) || !strcmp( findInfo.cFileName, ".." ) ) { - continue; - } + // check type + if( ( flags & FS_SEARCH_DIRSONLY ) != mask ) { + continue; + } - if( ( flags & FS_SEARCHDIRS_MASK ) == FS_SEARCHDIRS_ONLY ) { - if( !( findInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ) { + // check filter + if( filter ) { + if( flags & FS_SEARCH_BYFILTER ) { + if( !FS_WildCmp( filter, fullpath + baselen ) ) { continue; } - } else if( ( flags & FS_SEARCHDIRS_MASK ) == FS_SEARCHDIRS_NO ) { - if( findInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { + } else { + if( !FS_ExtCmp( filter, data.cFileName ) ) { continue; } } + } - if( extension && !FS_ExtCmp( extension, findInfo.cFileName ) ) { - continue; - } + // strip path + if( flags & FS_SEARCH_SAVEPATH ) { + name = fullpath + baselen; + } else { + name = data.cFileName; + } - name = ( flags & FS_SEARCH_SAVEPATH ) ? va( "%s\\%s", path, findInfo.cFileName ) : findInfo.cFileName; - - // reformat it back to quake filesystem style - FS_ReplaceSeparators( name, '/' ); + // reformat it back to quake filesystem style + FS_ReplaceSeparators( name, '/' ); - if( flags & FS_SEARCH_EXTRAINFO ) { - time_t ctime = file_time_to_unix( &findInfo.ftCreationTime ); - time_t mtime = file_time_to_unix( &findInfo.ftLastWriteTime ); - listedFiles[count++] = FS_CopyInfo( name, findInfo.nFileSizeLow, ctime, mtime ); - } else { - listedFiles[count++] = FS_CopyString( name ); - } - } while( count < MAX_LISTED_FILES && FindNextFileA( findHandle, &findInfo ) != FALSE ); + // strip extension + if( flags & FS_SEARCH_STRIPEXT ) { + *COM_FileExtension( name ) = 0; - FindClose( findHandle ); - } + if( !*name ) { + continue; + } + } - if( !count ) { - return NULL; - } + // copy info off + if( flags & FS_SEARCH_EXTRAINFO ) { + info = copy_info( name, &data ); + } else { + info = FS_CopyString( name ); + } - if( numFiles ) { - *numFiles = count; - } + files[(*count_p)++] = info; + } while( *count_p < MAX_LISTED_FILES && + FindNextFileA( handle, &data ) != FALSE ); - return FS_CopyList( listedFiles, count ); + FindClose( handle ); } /* diff --git a/src/ui_demos.c b/src/ui_demos.c index a79b742..ab75fd7 100644 --- a/src/ui_demos.c +++ b/src/ui_demos.c @@ -218,7 +218,7 @@ static void BuildList( void ) { // alloc entries dirlist = FS_ListFiles( m_demos.browse, NULL, FS_PATH_GAME | - FS_SEARCHDIRS_ONLY, &numDirs ); + FS_SEARCH_DIRSONLY, &numDirs ); demolist = FS_ListFiles( m_demos.browse, DEMO_EXTENSIONS, FS_PATH_GAME | FS_SEARCH_EXTRAINFO, &numDemos ); |