summaryrefslogtreecommitdiff
path: root/src/sys_win.c
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 /src/sys_win.c
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.
Diffstat (limited to 'src/sys_win.c')
-rw-r--r--src/sys_win.c231
1 files changed, 107 insertions, 124 deletions
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 );
}
/*