summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Nazarov <skuller@skuller.net>2010-10-01 16:33:37 +0400
committerAndrey Nazarov <skuller@skuller.net>2010-10-01 17:21:52 +0400
commit57ff04fceb133d7c06c67bf991b5941766bb28da (patch)
tree4f7ca34f1a58cd35059c76f72dbdaadcc81684c7
parentffd86f8fccf7a523e89553fefaa621457460aa38 (diff)
Clean up and fix file listing functions.
- Merge Sys_ListFiles and Sys_ListFilteredFiles into the single Sys_ListFiles_r implementatation (per platform). - Fix an off-by-one bug in Sys_ListFiles (per platform). - Fix an off-by-one bug in FS_ListFiles. - Made Sys_ListFiles ignore hidden and non-regular (irregular?) files on Unix. - Limit maximum recursion depth to 8 (opposed to 32 on Unix and unlimited depth on Win32). - Reduce listed files limit to 2048 from 4096. - Implement FS_SEARCH_STRIPEXT flag instead of ugly hack in FS_File_g. - Kill unused FS_SEARCH_NOSORT flag. - Replace FS_SEARCHDIRS_* cruft with single FS_SEARCH_DIRSONLY flag. - Use unsigned integer type for flags. - Don't list more than 128 files to avoid console spam.
-rw-r--r--src/cl_console.c2
-rw-r--r--src/cl_main.c2
-rw-r--r--src/cmd.c2
-rw-r--r--src/files.c256
-rw-r--r--src/files.h19
-rw-r--r--src/sv_ccmds.c2
-rw-r--r--src/sys_public.h4
-rw-r--r--src/sys_unix.c220
-rw-r--r--src/sys_win.c231
-rw-r--r--src/ui_demos.c2
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 ) {
diff --git a/src/cmd.c b/src/cmd.c
index cf29739..2293e95 100644
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -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 );