Skip to content

Commit

Permalink
Filesystem: allow scanning external directories recursively via FS_MA…
Browse files Browse the repository at this point in the history
…TCH_SUBDIRS flag, enabled for cfg and demo files completion

Filesystem: sort mod list, strip ending newlines in mod descriptions
  • Loading branch information
ec- committed Jan 4, 2025
1 parent d523bb4 commit f5b387e
Show file tree
Hide file tree
Showing 6 changed files with 308 additions and 351 deletions.
7 changes: 5 additions & 2 deletions code/client/cl_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -829,7 +829,7 @@ static void CL_CompleteDemoName(const char *args, int argNum )
if ( argNum == 2 )
{
FS_SetFilenameCallback( CL_DemoNameCallback_f );
Field_CompleteFilename( "demos", "." DEMOEXT "??", qfalse, FS_MATCH_ANY | FS_MATCH_STICK );
Field_CompleteFilename( "demos", "." DEMOEXT "??", qfalse, FS_MATCH_ANY | FS_MATCH_STICK | FS_MATCH_SUBDIRS );
FS_SetFilenameCallback( NULL );
}
}
Expand Down Expand Up @@ -3797,9 +3797,12 @@ static void CL_InitGLimp_Cvars( void )
r_mode = Cvar_Get( "r_mode", "-2", CVAR_ARCHIVE | CVAR_LATCH );
Cvar_CheckRange( r_mode, "-2", va( "%i", s_numVidModes-1 ), CV_INTEGER );
Cvar_SetDescription( r_mode, "Set video mode:\n -2 - use current desktop resolution\n -1 - use \\r_customWidth and \\r_customHeight\n 0..N - enter \\modelist for details" );
#ifdef _DEBUG
r_modeFullscreen = Cvar_Get( "r_modeFullscreen", "", CVAR_ARCHIVE | CVAR_LATCH );
#else
r_modeFullscreen = Cvar_Get( "r_modeFullscreen", "-2", CVAR_ARCHIVE | CVAR_LATCH );
#endif
Cvar_SetDescription( r_modeFullscreen, "Dedicated fullscreen mode, set to \"\" to use \\r_mode in all cases." );

r_fullscreen = Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE | CVAR_LATCH );
Cvar_SetDescription( r_fullscreen, "Fullscreen mode. Set to 0 for windowed mode." );
r_customPixelAspect = Cvar_Get( "r_customPixelAspect", "1", CVAR_ARCHIVE_ND | CVAR_LATCH );
Expand Down
4 changes: 2 additions & 2 deletions code/qcommon/cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1011,8 +1011,8 @@ Cmd_CompleteCfgName
==================
*/
static void Cmd_CompleteCfgName( const char *args, int argNum ) {
if( argNum == 2 ) {
Field_CompleteFilename( "", "cfg", qfalse, FS_MATCH_ANY | FS_MATCH_STICK );
if ( argNum == 2 ) {
Field_CompleteFilename( "", "cfg", qfalse, FS_MATCH_ANY | FS_MATCH_STICK | FS_MATCH_SUBDIRS );
}
}

Expand Down
186 changes: 97 additions & 89 deletions code/qcommon/files.c
Original file line number Diff line number Diff line change
Expand Up @@ -3339,10 +3339,11 @@ static char **FS_ListFilteredFiles( const char *path, const char *extension, con
Com_Error( ERR_FATAL, "Filesystem call made without initialization" );
}

if ( fs_numServerPaks && !( flags & FS_MATCH_STICK ) ) {
if ( fs_numServerPaks && ( flags & FS_MATCH_STICK ) == 0 ) {
flags &= ~FS_MATCH_UNPURE;
if ( !FS_AllowListExternal( extension ) )
if ( !FS_AllowListExternal( extension ) ) {
flags &= ~FS_MATCH_EXTERN;
}
}

if ( !path ) {
Expand All @@ -3364,13 +3365,14 @@ static char **FS_ListFilteredFiles( const char *path, const char *extension, con
if ( pathLength > 0 && ( path[pathLength-1] == '\\' || path[pathLength-1] == '/' ) ) {
pathLength--;
}

nfiles = 0;
FS_ReturnPath(path, zpath, &pathDepth);
FS_ReturnPath( path, zpath, &pathDepth );

//
// search through the path, one element at a time, adding to list
//
for (search = fs_searchpaths ; search ; search = search->next) {
for ( search = fs_searchpaths; search; search = search->next ) {
// is the element a pak file?
if ( search->pack && ( flags & FS_MATCH_PK3s ) ) {

Expand Down Expand Up @@ -3437,15 +3439,15 @@ static char **FS_ListFilteredFiles( const char *path, const char *extension, con
nfiles = FS_AddFileToList( name + temp, list, nfiles );
}
}
} else if ( search->dir && ( flags & FS_MATCH_EXTERN ) && search->policy != DIR_DENY ) { // scan for files in the filesystem
} else if ( search->dir && ( search->policy != DIR_DENY || (flags & FS_MATCH_EXTERN) != 0 ) ) { // scan for files in the filesystem
const char *netpath;
int numSysFiles;
char **sysFiles;
const char *name;

netpath = FS_BuildOSPath( search->dir->path, search->dir->gamedir, path );
sysFiles = Sys_ListFiles( netpath, extension, filter, &numSysFiles, qfalse );
for ( i = 0 ; i < numSysFiles ; i++ ) {
sysFiles = Sys_ListFiles( netpath, extension, filter, &numSysFiles, (flags & FS_MATCH_SUBDIRS) ? FS_MAX_SUBDIRS : 0);
for ( i = 0; i < numSysFiles; i++ ) {
// unique the match
name = sysFiles[ i ];
length = strlen( name );
Expand All @@ -3464,12 +3466,12 @@ static char **FS_ListFilteredFiles( const char *path, const char *extension, con
// return a copy of the list
*numfiles = nfiles;

if ( !nfiles ) {
if ( nfiles == 0 ) {
return NULL;
}

listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( listCopy[0] ) );
for ( i = 0 ; i < nfiles ; i++ ) {
for ( i = 0; i < nfiles; i++ ) {
listCopy[i] = list[i];
}
listCopy[i] = NULL;
Expand Down Expand Up @@ -3579,7 +3581,7 @@ static unsigned int Sys_CountFileList( char **list )
}


static char** Sys_ConcatenateFileLists( char **list0, char **list1 )
static char** FS_ConcatenateFileLists( char **list0, char **list1 )
{
int totalLength;
char **src, **dst, **cat;
Expand Down Expand Up @@ -3675,6 +3677,76 @@ static qboolean FS_IsBaseGame( const char *game )
}


/*
===========
FS_PathCmp
Ignore case and separator char distinctions
===========
*/
static int FS_PathCmp( const char* s1, const char* s2 ) {
int c1, c2;

do {
c1 = *s1++;
c2 = *s2++;

if ( c1 >= 'a' && c1 <= 'z' ) {
c1 -= ('a' - 'A');
}
if ( c2 >= 'a' && c2 <= 'z' ) {
c2 -= ('a' - 'A');
}

if ( c1 == '\\' || c1 == ':' ) {
c1 = '/';
}
if ( c2 == '\\' || c2 == ':' ) {
c2 = '/';
}

if ( c1 < c2 ) {
return -1; // strings not equal
}
if ( c1 > c2 ) {
return 1;
}
}
while ( c1 );

return 0; // strings are equal
}


/*
================
FS_SortFileList
================
*/
static void FS_SortFileList( char** list, int n ) {
const char* m;
char* temp;
int i, j;
i = 0;
j = n;
m = list[n >> 1];
do {
while ( FS_PathCmp( list[i], m ) < 0 ) i++;
while ( FS_PathCmp( list[j], m ) > 0 ) j--;
if ( i <= j ) {
temp = list[i];
list[i] = list[j];
list[j] = temp;
i++;
j--;
}
}
while ( i <= j );
if ( j > 0 ) FS_SortFileList( list, j );
if ( n > i ) FS_SortFileList( list + i, n - i );
}


/*
================
FS_GetModList
Expand Down Expand Up @@ -3707,14 +3779,18 @@ static int FS_GetModList( char *listbuf, int bufsize ) {
for (i = 0; i < ARRAY_LEN( paths ); i++) {
if ( !*paths[ i ] || !(*paths[i])->string[0] )
continue;
pFiles0 = Sys_ListFiles( (*paths[i])->string, NULL, NULL, &dummy, qtrue );
pFiles0 = Sys_ListFiles( (*paths[i])->string, "/", NULL, &dummy, 1 );
// Sys_ConcatenateFileLists frees the lists so Sys_FreeFileList isn't required
pFiles = Sys_ConcatenateFileLists( pFiles, pFiles0 );
pFiles = FS_ConcatenateFileLists( pFiles, pFiles0 );
}

nPotential = Sys_CountFileList( pFiles );

for ( i = 0 ; i < nPotential ; i++ ) {
if ( nPotential >= 2 ) {
FS_SortFileList( pFiles, nPotential - 1 );
}

for ( i = 0; i < nPotential; i++ ) {
name = pFiles[i];
// NOTE: cleaner would involve more changes
// ignore duplicate mod directories
Expand Down Expand Up @@ -3748,8 +3824,8 @@ static int FS_GetModList( char *listbuf, int bufsize ) {
path = FS_BuildOSPath( (*paths[j])->string, name, NULL );

nPaks = nDirs = nPakDirs = 0;
pPaks = Sys_ListFiles( path, ".pk3", NULL, &nPaks, qfalse );
pDirs = Sys_ListFiles( path, "/", NULL, &nDirs, qfalse );
pPaks = Sys_ListFiles( path, ".pk3", NULL, &nPaks, 0 );
pDirs = Sys_ListFiles( path, "/", NULL, &nDirs, 0 );
for ( k = 0; k < nDirs; k++ ) {
// we only want to count directories ending with ".pk3dir"
if ( FS_IsExt( pDirs[k], ".pk3dir", strlen( pDirs[k] ) ) ) {
Expand Down Expand Up @@ -3844,74 +3920,6 @@ static void FS_ConvertPath( char *s ) {
}


/*
===========
FS_PathCmp
Ignore case and separator char distinctions
===========
*/
static int FS_PathCmp( const char *s1, const char *s2 ) {
int c1, c2;

do {
c1 = *s1++;
c2 = *s2++;

if (c1 >= 'a' && c1 <= 'z') {
c1 -= ('a' - 'A');
}
if (c2 >= 'a' && c2 <= 'z') {
c2 -= ('a' - 'A');
}

if ( c1 == '\\' || c1 == ':' ) {
c1 = '/';
}
if ( c2 == '\\' || c2 == ':' ) {
c2 = '/';
}

if (c1 < c2) {
return -1; // strings not equal
}
if (c1 > c2) {
return 1;
}
} while (c1);

return 0; // strings are equal
}


/*
================
FS_SortFileList
================
*/
static void FS_SortFileList( char **list, int n ) {
const char *m;
char *temp;
int i, j;
i = 0;
j = n;
m = list[ n >> 1 ];
do {
while ( FS_PathCmp( list[i], m ) < 0 ) i++;
while ( FS_PathCmp( list[j], m ) > 0 ) j--;
if ( i <= j ) {
temp = list[i];
list[i] = list[j];
list[j] = temp;
i++;
j--;
}
} while ( i <= j );
if ( j > 0 ) FS_SortFileList( list, j );
if ( n > i ) FS_SortFileList( list+i, n-i );
}


/*
================
FS_NewDir_f
Expand All @@ -3934,10 +3942,11 @@ static void FS_NewDir_f( void ) {

Com_Printf( "---------------\n" );

dirnames = FS_ListFilteredFiles( "", "", filter, &ndirs, FS_MATCH_ANY );
dirnames = FS_ListFilteredFiles( "", "", filter, &ndirs, FS_MATCH_ANY | FS_MATCH_SUBDIRS );

if ( ndirs >= 2 )
if ( ndirs >= 2 ) {
FS_SortFileList( dirnames, ndirs - 1 );
}

for ( i = 0; i < ndirs; i++ ) {
Q_strncpyz( dirname, dirnames[i], sizeof( dirname ) );
Expand Down Expand Up @@ -4158,7 +4167,7 @@ static void FS_AddGameDirectory( const char *path, const char *dir ) {
Q_strncpyz( curpath, FS_BuildOSPath( path, dir, NULL ), sizeof( curpath ) );

// Get .pk3 files
pakfiles = Sys_ListFiles(curpath, ".pk3", NULL, &numfiles, qfalse);
pakfiles = Sys_ListFiles( curpath, ".pk3", NULL, &numfiles, 0 );

if ( numfiles >= 2 )
FS_SortFileList( pakfiles, numfiles - 1 );
Expand All @@ -4171,7 +4180,7 @@ static void FS_AddGameDirectory( const char *path, const char *dir ) {
pakdirs = NULL;
} else {
// Get top level directories (we'll filter them later since the Sys_ListFiles filtering is terrible)
pakdirs = Sys_ListFiles( curpath, "/", NULL, &numdirs, qfalse );
pakdirs = Sys_ListFiles( curpath, "/", NULL, &numdirs, 0 );
if ( numdirs >= 2 ) {
FS_SortFileList( pakdirs, numdirs - 1 );
}
Expand Down Expand Up @@ -5577,8 +5586,7 @@ void FS_Flush( fileHandle_t f )
}


void FS_FilenameCompletion( const char *dir, const char *ext,
qboolean stripExt, void(*callback)(const char *s), int flags ) {
void FS_FilenameCompletion( const char *dir, const char *ext, qboolean stripExt, void(*callback)(const char *s), int flags ) {
char filename[ MAX_STRING_CHARS ];
char **filenames;
int nfiles;
Expand Down
20 changes: 11 additions & 9 deletions code/qcommon/qcommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -678,12 +678,15 @@ typedef enum {
H_Q3UI
} handleOwner_t;

#define FS_MATCH_EXTERN (1<<0)
#define FS_MATCH_PURE (1<<1)
#define FS_MATCH_UNPURE (1<<2)
#define FS_MATCH_STICK (1<<3)
#define FS_MATCH_PK3s (FS_MATCH_PURE | FS_MATCH_UNPURE)
#define FS_MATCH_ANY (FS_MATCH_EXTERN | FS_MATCH_PURE | FS_MATCH_UNPURE)
#define FS_MATCH_EXTERN (1<<0)
#define FS_MATCH_PURE (1<<1)
#define FS_MATCH_UNPURE (1<<2)
#define FS_MATCH_STICK (1<<3)
#define FS_MATCH_SUBDIRS (1<<4)
#define FS_MATCH_PK3s (FS_MATCH_PURE | FS_MATCH_UNPURE)
#define FS_MATCH_ANY (FS_MATCH_EXTERN | FS_MATCH_PURE | FS_MATCH_UNPURE)

#define FS_MAX_SUBDIRS 8 /* should be enough for practical use with FS_MATCH_SUBDIRS */

#define MAX_FILE_HANDLES 64
#define FS_INVALID_HANDLE 0
Expand Down Expand Up @@ -848,8 +851,7 @@ void FS_Rename( const char *from, const char *to );
void FS_Remove( const char *osPath );
void FS_HomeRemove( const char *homePath );

void FS_FilenameCompletion( const char *dir, const char *ext,
qboolean stripExt, void(*callback)(const char *s), int flags );
void FS_FilenameCompletion( const char *dir, const char *ext, qboolean stripExt, void(*callback)(const char *s), int flags );

int FS_VM_OpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode, handleOwner_t owner );
int FS_VM_ReadFile( void *buffer, int len, fileHandle_t f, handleOwner_t owner );
Expand Down Expand Up @@ -1318,7 +1320,7 @@ const char *Sys_SteamPath( void );
char *Sys_DefaultAppPath( void );
#endif

char **Sys_ListFiles( const char *directory, const char *extension, const char *filter, int *numfiles, qboolean wantsubs );
char **Sys_ListFiles( const char *directory, const char *extension, const char *filter, int *numfiles, int subdirs );
void Sys_FreeFileList( char **list );

qboolean Sys_GetFileStats( const char *filename, fileOffset_t *size, fileTime_t *mtime, fileTime_t *ctime );
Expand Down
Loading

0 comments on commit f5b387e

Please sign in to comment.