📄 files.c
字号:
if ( !fs_searchpaths ) {
Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
}
if ( !list ) {
return;
}
for ( i = 0 ; list[i] ; i++ ) {
Z_Free( list[i] );
}
Z_Free( list );
}
/*
================
FS_GetFileList
================
*/
int FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize ) {
int nFiles, i, nTotal, nLen;
char **pFiles = NULL;
*listbuf = 0;
nFiles = 0;
nTotal = 0;
if (Q_stricmp(path, "$modlist") == 0) {
return FS_GetModList(listbuf, bufsize);
}
pFiles = FS_ListFiles(path, extension, &nFiles);
for (i =0; i < nFiles; i++) {
nLen = strlen(pFiles[i]) + 1;
if (nTotal + nLen + 1 < bufsize) {
strcpy(listbuf, pFiles[i]);
listbuf += nLen;
nTotal += nLen;
}
else {
nFiles = i;
break;
}
}
FS_FreeFileList(pFiles);
return nFiles;
}
/*
=======================
Sys_ConcatenateFileLists
mkv: Naive implementation. Concatenates three lists into a
new list, and frees the old lists from the heap.
bk001129 - from cvs1.17 (mkv)
FIXME TTimo those two should move to common.c next to Sys_ListFiles
=======================
*/
static unsigned int Sys_CountFileList(char **list)
{
int i = 0;
if (list)
{
while (*list)
{
list++;
i++;
}
}
return i;
}
static char** Sys_ConcatenateFileLists( char **list0, char **list1, char **list2 )
{
int totalLength = 0;
char** cat = NULL, **dst, **src;
totalLength += Sys_CountFileList(list0);
totalLength += Sys_CountFileList(list1);
totalLength += Sys_CountFileList(list2);
/* Create new list. */
dst = cat = Z_Malloc( ( totalLength + 1 ) * sizeof( char* ) );
/* Copy over lists. */
if (list0)
{
for (src = list0; *src; src++, dst++)
*dst = *src;
}
if (list1)
{
for (src = list1; *src; src++, dst++)
*dst = *src;
}
if (list2)
{
for (src = list2; *src; src++, dst++)
*dst = *src;
}
// Terminate the list
*dst = NULL;
// Free our old lists.
// NOTE: not freeing their content, it's been merged in dst and still being used
if (list0) Z_Free( list0 );
if (list1) Z_Free( list1 );
if (list2) Z_Free( list2 );
return cat;
}
/*
================
FS_GetModList
Returns a list of mod directory names
A mod directory is a peer to baseq3 with a pk3 in it
The directories are searched in base path, cd path and home path
================
*/
int FS_GetModList( char *listbuf, int bufsize ) {
int nMods, i, j, nTotal, nLen, nPaks, nPotential, nDescLen;
char **pFiles = NULL;
char **pPaks = NULL;
char *name, *path;
char descPath[MAX_OSPATH];
fileHandle_t descHandle;
int dummy;
char **pFiles0 = NULL;
char **pFiles1 = NULL;
char **pFiles2 = NULL;
qboolean bDrop = qfalse;
*listbuf = 0;
nMods = nPotential = nTotal = 0;
pFiles0 = Sys_ListFiles( fs_homepath->string, NULL, NULL, &dummy, qtrue );
pFiles1 = Sys_ListFiles( fs_basepath->string, NULL, NULL, &dummy, qtrue );
pFiles2 = Sys_ListFiles( fs_cdpath->string, NULL, NULL, &dummy, qtrue );
// we searched for mods in the three paths
// it is likely that we have duplicate names now, which we will cleanup below
pFiles = Sys_ConcatenateFileLists( pFiles0, pFiles1, pFiles2 );
nPotential = Sys_CountFileList(pFiles);
for ( i = 0 ; i < nPotential ; i++ ) {
name = pFiles[i];
// NOTE: cleaner would involve more changes
// ignore duplicate mod directories
if (i!=0) {
bDrop = qfalse;
for(j=0; j<i; j++)
{
if (Q_stricmp(pFiles[j],name)==0) {
// this one can be dropped
bDrop = qtrue;
break;
}
}
}
if (bDrop) {
continue;
}
// we drop "baseq3" "." and ".."
if (Q_stricmp(name, "baseq3") && Q_stricmpn(name, ".", 1)) {
// now we need to find some .pk3 files to validate the mod
// NOTE TTimo: (actually I'm not sure why .. what if it's a mod under developement with no .pk3?)
// we didn't keep the information when we merged the directory names, as to what OS Path it was found under
// so it could be in base path, cd path or home path
// we will try each three of them here (yes, it's a bit messy)
path = FS_BuildOSPath( fs_basepath->string, name, "" );
nPaks = 0;
pPaks = Sys_ListFiles(path, ".pk3", NULL, &nPaks, qfalse);
Sys_FreeFileList( pPaks ); // we only use Sys_ListFiles to check wether .pk3 files are present
/* Try on cd path */
if( nPaks <= 0 ) {
path = FS_BuildOSPath( fs_cdpath->string, name, "" );
nPaks = 0;
pPaks = Sys_ListFiles( path, ".pk3", NULL, &nPaks, qfalse );
Sys_FreeFileList( pPaks );
}
/* try on home path */
if ( nPaks <= 0 )
{
path = FS_BuildOSPath( fs_homepath->string, name, "" );
nPaks = 0;
pPaks = Sys_ListFiles( path, ".pk3", NULL, &nPaks, qfalse );
Sys_FreeFileList( pPaks );
}
if (nPaks > 0) {
nLen = strlen(name) + 1;
// nLen is the length of the mod path
// we need to see if there is a description available
descPath[0] = '\0';
strcpy(descPath, name);
strcat(descPath, "/description.txt");
nDescLen = FS_SV_FOpenFileRead( descPath, &descHandle );
if ( nDescLen > 0 && descHandle) {
FILE *file;
file = FS_FileForHandle(descHandle);
Com_Memset( descPath, 0, sizeof( descPath ) );
nDescLen = fread(descPath, 1, 48, file);
if (nDescLen >= 0) {
descPath[nDescLen] = '\0';
}
FS_FCloseFile(descHandle);
} else {
strcpy(descPath, name);
}
nDescLen = strlen(descPath) + 1;
if (nTotal + nLen + 1 + nDescLen + 1 < bufsize) {
strcpy(listbuf, name);
listbuf += nLen;
strcpy(listbuf, descPath);
listbuf += nDescLen;
nTotal += nLen + nDescLen;
nMods++;
}
else {
break;
}
}
}
}
Sys_FreeFileList( pFiles );
return nMods;
}
//============================================================================
/*
================
FS_Dir_f
================
*/
void FS_Dir_f( void ) {
char *path;
char *extension;
char **dirnames;
int ndirs;
int i;
if ( Cmd_Argc() < 2 || Cmd_Argc() > 3 ) {
Com_Printf( "usage: dir <directory> [extension]\n" );
return;
}
if ( Cmd_Argc() == 2 ) {
path = Cmd_Argv( 1 );
extension = "";
} else {
path = Cmd_Argv( 1 );
extension = Cmd_Argv( 2 );
}
Com_Printf( "Directory of %s %s\n", path, extension );
Com_Printf( "---------------\n" );
dirnames = FS_ListFiles( path, extension, &ndirs );
for ( i = 0; i < ndirs; i++ ) {
Com_Printf( "%s\n", dirnames[i] );
}
FS_FreeFileList( dirnames );
}
/*
===========
FS_ConvertPath
===========
*/
void FS_ConvertPath( char *s ) {
while (*s) {
if ( *s == '\\' || *s == ':' ) {
*s = '/';
}
s++;
}
}
/*
===========
FS_PathCmp
Ignore case and seprator char distinctions
===========
*/
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
================
*/
void FS_SortFileList(char **filelist, int numfiles) {
int i, j, k, numsortedfiles;
char **sortedlist;
sortedlist = Z_Malloc( ( numfiles + 1 ) * sizeof( *sortedlist ) );
sortedlist[0] = NULL;
numsortedfiles = 0;
for (i = 0; i < numfiles; i++) {
for (j = 0; j < numsortedfiles; j++) {
if (FS_PathCmp(filelist[i], sortedlist[j]) < 0) {
break;
}
}
for (k = numsortedfiles; k > j; k--) {
sortedlist[k] = sortedlist[k-1];
}
sortedlist[j] = filelist[i];
numsortedfiles++;
}
Com_Memcpy(filelist, sortedlist, numfiles * sizeof( *filelist ) );
Z_Free(sortedlist);
}
/*
================
FS_NewDir_f
================
*/
void FS_NewDir_f( void ) {
char *filter;
char **dirnames;
int ndirs;
int i;
if ( Cmd_Argc() < 2 ) {
Com_Printf( "usage: fdir <filter>\n" );
Com_Printf( "example: fdir *q3dm*.bsp\n");
return;
}
filter = Cmd_Argv( 1 );
Com_Printf( "---------------\n" );
dirnames = FS_ListFilteredFiles( "", "", filter, &ndirs );
FS_SortFileList(dirnames, ndirs);
for ( i = 0; i < ndirs; i++ ) {
FS_ConvertPath(dirnames[i]);
Com_Printf( "%s\n", dirnames[i] );
}
Com_Printf( "%d files listed\n", ndirs );
FS_FreeFileList( dirnames );
}
/*
============
FS_Path_f
============
*/
void FS_Path_f( void ) {
searchpath_t *s;
int i;
Com_Printf ("Current search path:\n");
for (s = fs_searchpaths; s; s = s->next) {
if (s->pack) {
Com_Printf ("%s (%i files)\n", s->pack->pakFilename, s->pack->numfiles);
if ( fs_numServerPaks ) {
if ( !FS_PakIsPure(s->pack) ) {
Com_Printf( " not on the pure list\n" );
} else {
Com_Printf( " on the pure list\n" );
}
}
} else {
Com_Printf ("%s/%s\n", s->dir->path, s->dir->gamedir );
}
}
Com_Printf( "\n" );
for ( i = 1 ; i < MAX_FILE_HANDLES ; i++ ) {
if ( fsh[i].handleFiles.file.o ) {
Com_Printf( "handle %i: %s\n", i, fsh[i].name );
}
}
}
/*
============
FS_TouchFile_f
The only purpose of this function is to allow game script files to copy
arbitrary files furing an "fs_copyfiles 1" run.
============
*/
void FS_TouchFile_f( void ) {
fileHandle_t f;
if ( Cmd_Argc() != 2 ) {
Com_Printf( "Usage: touchFile <file>\n" );
return;
}
FS_FOpenFileRead( Cmd_Argv( 1 ), &f, qfalse );
if ( f ) {
FS_FCloseFile( f );
}
}
//===========================================================================
static int QDECL paksort( const void *a, const void *b ) {
char *aa, *bb;
aa = *(char **)a;
bb = *(char **)b;
return FS_PathCmp( aa, bb );
}
/*
================
FS_AddGameDirectory
Sets fs_gamedir, adds the directory to the head of the path,
then loads the zip headers
================
*/
#define MAX_PAKFILES 1024
static void FS_AddGameDirectory( const char *path, const char *dir ) {
searchpath_t *sp;
int i;
searchpath_t *search;
pack_t *pak;
char *pakfile;
int numfiles;
char **pakfiles;
char *sorted[MAX_PAKFILES];
// this fixes the case where fs_basepath is the same as fs_cdpath
// which happens on full installs
for ( sp = fs_searchpaths ; sp ; sp = sp->next ) {
if ( sp->dir && !Q_stricmp(sp->dir->path, path) && !Q_stricmp(sp->dir->gamedir, dir)) {
return; // we've already got this one
}
}
Q_strncpyz( fs_gamedir, dir, sizeof( fs_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -