Annotation of quake2/qcommon/files.c, revision 1.1.1.4

1.1.1.4 ! root        1: /*
        !             2: Copyright (C) 1997-2001 Id Software, Inc.
        !             3: 
        !             4: This program is free software; you can redistribute it and/or
        !             5: modify it under the terms of the GNU General Public License
        !             6: as published by the Free Software Foundation; either version 2
        !             7: of the License, or (at your option) any later version.
        !             8: 
        !             9: This program is distributed in the hope that it will be useful,
        !            10: but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
        !            12: 
        !            13: See the GNU General Public License for more details.
        !            14: 
        !            15: You should have received a copy of the GNU General Public License
        !            16: along with this program; if not, write to the Free Software
        !            17: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
        !            18: 
        !            19: */
1.1       root       20: 
                     21: #include "qcommon.h"
                     22: 
                     23: // define this to dissalow any data but the demo pak file
                     24: //#define      NO_ADDONS
                     25: 
                     26: // if a packfile directory differs from this, it is assumed to be hacked
                     27: // Full version
                     28: #define        PAK0_CHECKSUM   0x40e614e0
                     29: // Demo
                     30: //#define      PAK0_CHECKSUM   0xb2c6d7ea
                     31: // OEM
                     32: //#define      PAK0_CHECKSUM   0x78e135c
                     33: 
                     34: /*
                     35: =============================================================================
                     36: 
                     37: QUAKE FILESYSTEM
                     38: 
                     39: =============================================================================
                     40: */
                     41: 
                     42: 
                     43: //
                     44: // in memory
                     45: //
                     46: 
                     47: typedef struct
                     48: {
                     49:        char    name[MAX_QPATH];
                     50:        int             filepos, filelen;
                     51: } packfile_t;
                     52: 
                     53: typedef struct pack_s
                     54: {
                     55:        char    filename[MAX_OSPATH];
                     56:        FILE    *handle;
                     57:        int             numfiles;
                     58:        packfile_t      *files;
                     59: } pack_t;
                     60: 
                     61: char   fs_gamedir[MAX_OSPATH];
                     62: cvar_t *fs_basedir;
                     63: cvar_t *fs_cddir;
                     64: cvar_t *fs_gamedirvar;
                     65: 
                     66: typedef struct filelink_s
                     67: {
                     68:        struct filelink_s       *next;
                     69:        char    *from;
                     70:        int             fromlength;
                     71:        char    *to;
                     72: } filelink_t;
                     73: 
                     74: filelink_t     *fs_links;
                     75: 
                     76: typedef struct searchpath_s
                     77: {
                     78:        char    filename[MAX_OSPATH];
                     79:        pack_t  *pack;          // only one of filename / pack will be used
                     80:        struct searchpath_s *next;
                     81: } searchpath_t;
                     82: 
                     83: searchpath_t   *fs_searchpaths;
                     84: searchpath_t   *fs_base_searchpaths;   // without gamedirs
                     85: 
                     86: 
                     87: /*
                     88: 
                     89: All of Quake's data access is through a hierchal file system, but the contents of the file system can be transparently merged from several sources.
                     90: 
                     91: The "base directory" is the path to the directory holding the quake.exe and all game directories.  The sys_* files pass this to host_init in quakeparms_t->basedir.  This can be overridden with the "-basedir" command line parm to allow code debugging in a different directory.  The base directory is
                     92: only used during filesystem initialization.
                     93: 
                     94: The "game directory" is the first tree on the search path and directory that all generated files (savegames, screenshots, demos, config files) will be saved to.  This can be overridden with the "-game" command line parameter.  The game directory can never be changed while quake is executing.  This is a precacution against having a malicious server instruct clients to write files over areas they shouldn't.
                     95: 
                     96: */
                     97: 
                     98: 
                     99: /*
                    100: ================
                    101: FS_filelength
                    102: ================
                    103: */
                    104: int FS_filelength (FILE *f)
                    105: {
                    106:        int             pos;
                    107:        int             end;
                    108: 
                    109:        pos = ftell (f);
                    110:        fseek (f, 0, SEEK_END);
                    111:        end = ftell (f);
                    112:        fseek (f, pos, SEEK_SET);
                    113: 
                    114:        return end;
                    115: }
                    116: 
                    117: 
                    118: /*
                    119: ============
                    120: FS_CreatePath
                    121: 
                    122: Creates any directories needed to store the given filename
                    123: ============
                    124: */
                    125: void   FS_CreatePath (char *path)
                    126: {
                    127:        char    *ofs;
                    128:        
                    129:        for (ofs = path+1 ; *ofs ; ofs++)
                    130:        {
                    131:                if (*ofs == '/')
                    132:                {       // create the directory
                    133:                        *ofs = 0;
                    134:                        Sys_Mkdir (path);
                    135:                        *ofs = '/';
                    136:                }
                    137:        }
                    138: }
                    139: 
                    140: 
                    141: /*
                    142: ==============
                    143: FS_FCloseFile
                    144: 
                    145: For some reason, other dll's can't just cal fclose()
                    146: on files returned by FS_FOpenFile...
                    147: ==============
                    148: */
                    149: void FS_FCloseFile (FILE *f)
                    150: {
                    151:        fclose (f);
                    152: }
                    153: 
1.1.1.2   root      154: 
                    155: // RAFAEL
                    156: /*
                    157:        Developer_searchpath
                    158: */
                    159: int    Developer_searchpath (int who)
                    160: {
                    161:        
                    162:        int             ch;
1.1.1.3   root      163:        // PMM - warning removal
                    164: //     char    *start;
1.1.1.2   root      165:        searchpath_t    *search;
                    166:        
                    167:        if (who == 1) // xatrix
                    168:                ch = 'x';
1.1.1.3   root      169:        else if (who == 2)
                    170:                ch = 'r';
1.1.1.2   root      171: 
                    172:        for (search = fs_searchpaths ; search ; search = search->next)
                    173:        {
1.1.1.3   root      174:                if (strstr (search->filename, "xatrix"))
                    175:                        return 1;
                    176: 
                    177:                if (strstr (search->filename, "rogue"))
                    178:                        return 2;
                    179: /*
1.1.1.2   root      180:                start = strchr (search->filename, ch);
                    181: 
                    182:                if (start == NULL)
                    183:                        continue;
                    184: 
                    185:                if (strcmp (start ,"xatrix") == 0)
                    186:                        return (1);
1.1.1.3   root      187: */
1.1.1.2   root      188:        }
                    189:        return (0);
                    190: 
                    191: }
                    192: 
                    193: 
1.1       root      194: /*
                    195: ===========
                    196: FS_FOpenFile
                    197: 
                    198: Finds the file in the search path.
                    199: returns filesize and an open FILE *
                    200: Used for streaming data out of either a pak file or
                    201: a seperate file.
                    202: ===========
                    203: */
1.1.1.2   root      204: int file_from_pak = 0;
1.1       root      205: #ifndef NO_ADDONS
                    206: int FS_FOpenFile (char *filename, FILE **file)
                    207: {
                    208:        searchpath_t    *search;
                    209:        char                    netpath[MAX_OSPATH];
                    210:        pack_t                  *pak;
                    211:        int                             i;
                    212:        filelink_t              *link;
                    213: 
1.1.1.2   root      214:        file_from_pak = 0;
                    215: 
1.1       root      216:        // check for links first
                    217:        for (link = fs_links ; link ; link=link->next)
                    218:        {
                    219:                if (!strncmp (filename, link->from, link->fromlength))
                    220:                {
                    221:                        Com_sprintf (netpath, sizeof(netpath), "%s%s",link->to, filename+link->fromlength);
                    222:                        *file = fopen (netpath, "rb");
                    223:                        if (*file)
                    224:                        {               
                    225:                                Com_DPrintf ("link file: %s\n",netpath);
                    226:                                return FS_filelength (*file);
                    227:                        }
                    228:                        return -1;
                    229:                }
                    230:        }
                    231: 
                    232: //
                    233: // search through the path, one element at a time
                    234: //
                    235:        for (search = fs_searchpaths ; search ; search = search->next)
                    236:        {
                    237:        // is the element a pak file?
                    238:                if (search->pack)
                    239:                {
                    240:                // look through all the pak file elements
                    241:                        pak = search->pack;
                    242:                        for (i=0 ; i<pak->numfiles ; i++)
                    243:                                if (!Q_strcasecmp (pak->files[i].name, filename))
                    244:                                {       // found it!
1.1.1.2   root      245:                                        file_from_pak = 1;
1.1       root      246:                                        Com_DPrintf ("PackFile: %s : %s\n",pak->filename, filename);
                    247:                                // open a new file on the pakfile
                    248:                                        *file = fopen (pak->filename, "rb");
                    249:                                        if (!*file)
                    250:                                                Com_Error (ERR_FATAL, "Couldn't reopen %s", pak->filename);     
                    251:                                        fseek (*file, pak->files[i].filepos, SEEK_SET);
                    252:                                        return pak->files[i].filelen;
                    253:                                }
                    254:                }
                    255:                else
                    256:                {               
                    257:        // check a file in the directory tree
                    258:                        
                    259:                        Com_sprintf (netpath, sizeof(netpath), "%s/%s",search->filename, filename);
                    260:                        
                    261:                        *file = fopen (netpath, "rb");
                    262:                        if (!*file)
                    263:                                continue;
                    264:                        
                    265:                        Com_DPrintf ("FindFile: %s\n",netpath);
                    266: 
                    267:                        return FS_filelength (*file);
                    268:                }
                    269:                
                    270:        }
                    271:        
                    272:        Com_DPrintf ("FindFile: can't find %s\n", filename);
                    273:        
                    274:        *file = NULL;
                    275:        return -1;
                    276: }
                    277: 
                    278: #else
                    279: 
                    280: // this is just for demos to prevent add on hacking
                    281: 
                    282: int FS_FOpenFile (char *filename, FILE **file)
                    283: {
                    284:        searchpath_t    *search;
                    285:        char                    netpath[MAX_OSPATH];
                    286:        pack_t                  *pak;
                    287:        int                             i;
                    288: 
1.1.1.2   root      289:        file_from_pak = 0;
                    290: 
1.1       root      291:        // get config from directory, everything else from pak
                    292:        if (!strcmp(filename, "config.cfg") || !strncmp(filename, "players/", 8))
                    293:        {
                    294:                Com_sprintf (netpath, sizeof(netpath), "%s/%s",FS_Gamedir(), filename);
                    295:                
                    296:                *file = fopen (netpath, "rb");
                    297:                if (!*file)
                    298:                        return -1;
                    299:                
                    300:                Com_DPrintf ("FindFile: %s\n",netpath);
                    301: 
                    302:                return FS_filelength (*file);
                    303:        }
                    304: 
                    305:        for (search = fs_searchpaths ; search ; search = search->next)
                    306:                if (search->pack)
                    307:                        break;
                    308:        if (!search)
                    309:        {
                    310:                *file = NULL;
                    311:                return -1;
                    312:        }
                    313: 
                    314:        pak = search->pack;
                    315:        for (i=0 ; i<pak->numfiles ; i++)
                    316:                if (!Q_strcasecmp (pak->files[i].name, filename))
                    317:                {       // found it!
1.1.1.2   root      318:                        file_from_pak = 1;
1.1       root      319:                        Com_DPrintf ("PackFile: %s : %s\n",pak->filename, filename);
                    320:                // open a new file on the pakfile
                    321:                        *file = fopen (pak->filename, "rb");
                    322:                        if (!*file)
                    323:                                Com_Error (ERR_FATAL, "Couldn't reopen %s", pak->filename);     
                    324:                        fseek (*file, pak->files[i].filepos, SEEK_SET);
                    325:                        return pak->files[i].filelen;
                    326:                }
                    327:        
                    328:        Com_DPrintf ("FindFile: can't find %s\n", filename);
                    329:        
                    330:        *file = NULL;
                    331:        return -1;
                    332: }
                    333: 
                    334: #endif
                    335: 
                    336: 
                    337: /*
                    338: =================
                    339: FS_ReadFile
                    340: 
                    341: Properly handles partial reads
                    342: =================
                    343: */
                    344: void CDAudio_Stop(void);
                    345: #define        MAX_READ        0x10000         // read in blocks of 64k
                    346: void FS_Read (void *buffer, int len, FILE *f)
                    347: {
                    348:        int             block, remaining;
                    349:        int             read;
                    350:        byte    *buf;
                    351:        int             tries;
                    352: 
                    353:        buf = (byte *)buffer;
                    354: 
                    355:        // read in chunks for progress bar
                    356:        remaining = len;
                    357:        tries = 0;
                    358:        while (remaining)
                    359:        {
                    360:                block = remaining;
                    361:                if (block > MAX_READ)
                    362:                        block = MAX_READ;
                    363:                read = fread (buf, 1, block, f);
                    364:                if (read == 0)
                    365:                {
                    366:                        // we might have been trying to read from a CD
                    367:                        if (!tries)
                    368:                        {
                    369:                                tries = 1;
                    370:                                CDAudio_Stop();
                    371:                        }
                    372:                        else
                    373:                                Com_Error (ERR_FATAL, "FS_Read: 0 bytes read");
                    374:                }
                    375: 
                    376:                if (read == -1)
                    377:                        Com_Error (ERR_FATAL, "FS_Read: -1 bytes read");
                    378: 
                    379:                // do some progress bar thing here...
                    380: 
                    381:                remaining -= read;
                    382:                buf += read;
                    383:        }
                    384: }
                    385: 
                    386: /*
                    387: ============
                    388: FS_LoadFile
                    389: 
                    390: Filename are reletive to the quake search path
                    391: a null buffer will just return the file length without loading
                    392: ============
                    393: */
                    394: int FS_LoadFile (char *path, void **buffer)
                    395: {
                    396:        FILE    *h;
                    397:        byte    *buf;
                    398:        int             len;
                    399: 
                    400:        buf = NULL;     // quiet compiler warning
                    401: 
                    402: // look for it in the filesystem or pack files
                    403:        len = FS_FOpenFile (path, &h);
                    404:        if (!h)
                    405:        {
                    406:                if (buffer)
                    407:                        *buffer = NULL;
                    408:                return -1;
                    409:        }
                    410:        
                    411:        if (!buffer)
                    412:        {
                    413:                fclose (h);
                    414:                return len;
                    415:        }
                    416: 
                    417:        buf = Z_Malloc(len);
                    418:        *buffer = buf;
                    419: 
                    420:        FS_Read (buf, len, h);
                    421: 
                    422:        fclose (h);
                    423: 
                    424:        return len;
                    425: }
                    426: 
                    427: 
                    428: /*
                    429: =============
                    430: FS_FreeFile
                    431: =============
                    432: */
                    433: void FS_FreeFile (void *buffer)
                    434: {
                    435:        Z_Free (buffer);
                    436: }
                    437: 
                    438: /*
                    439: =================
                    440: FS_LoadPackFile
                    441: 
                    442: Takes an explicit (not game tree related) path to a pak file.
                    443: 
                    444: Loads the header and directory, adding the files at the beginning
                    445: of the list so they override previous pack files.
                    446: =================
                    447: */
                    448: pack_t *FS_LoadPackFile (char *packfile)
                    449: {
                    450:        dpackheader_t   header;
                    451:        int                             i;
                    452:        packfile_t              *newfiles;
                    453:        int                             numpackfiles;
                    454:        pack_t                  *pack;
                    455:        FILE                    *packhandle;
                    456:        dpackfile_t             info[MAX_FILES_IN_PACK];
                    457:        unsigned                checksum;
                    458: 
                    459:        packhandle = fopen(packfile, "rb");
                    460:        if (!packhandle)
                    461:                return NULL;
                    462: 
                    463:        fread (&header, 1, sizeof(header), packhandle);
                    464:        if (LittleLong(header.ident) != IDPAKHEADER)
                    465:                Com_Error (ERR_FATAL, "%s is not a packfile", packfile);
                    466:        header.dirofs = LittleLong (header.dirofs);
                    467:        header.dirlen = LittleLong (header.dirlen);
                    468: 
                    469:        numpackfiles = header.dirlen / sizeof(dpackfile_t);
                    470: 
                    471:        if (numpackfiles > MAX_FILES_IN_PACK)
                    472:                Com_Error (ERR_FATAL, "%s has %i files", packfile, numpackfiles);
                    473: 
                    474:        newfiles = Z_Malloc (numpackfiles * sizeof(packfile_t));
                    475: 
                    476:        fseek (packhandle, header.dirofs, SEEK_SET);
                    477:        fread (info, 1, header.dirlen, packhandle);
                    478: 
                    479: // crc the directory to check for modifications
                    480:        checksum = Com_BlockChecksum ((void *)info, header.dirlen);
                    481: 
                    482: #ifdef NO_ADDONS
                    483:        if (checksum != PAK0_CHECKSUM)
                    484:                return NULL;
                    485: #endif
                    486: // parse the directory
                    487:        for (i=0 ; i<numpackfiles ; i++)
                    488:        {
                    489:                strcpy (newfiles[i].name, info[i].name);
                    490:                newfiles[i].filepos = LittleLong(info[i].filepos);
                    491:                newfiles[i].filelen = LittleLong(info[i].filelen);
                    492:        }
                    493: 
                    494:        pack = Z_Malloc (sizeof (pack_t));
                    495:        strcpy (pack->filename, packfile);
                    496:        pack->handle = packhandle;
                    497:        pack->numfiles = numpackfiles;
                    498:        pack->files = newfiles;
                    499:        
                    500:        Com_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
                    501:        return pack;
                    502: }
                    503: 
                    504: 
                    505: /*
                    506: ================
                    507: FS_AddGameDirectory
                    508: 
                    509: Sets fs_gamedir, adds the directory to the head of the path,
                    510: then loads and adds pak1.pak pak2.pak ... 
                    511: ================
                    512: */
                    513: void FS_AddGameDirectory (char *dir)
                    514: {
                    515:        int                             i;
                    516:        searchpath_t    *search;
                    517:        pack_t                  *pak;
                    518:        char                    pakfile[MAX_OSPATH];
                    519: 
                    520:        strcpy (fs_gamedir, dir);
                    521: 
                    522:        //
                    523:        // add the directory to the search path
                    524:        //
                    525:        search = Z_Malloc (sizeof(searchpath_t));
                    526:        strcpy (search->filename, dir);
                    527:        search->next = fs_searchpaths;
                    528:        fs_searchpaths = search;
                    529: 
                    530:        //
                    531:        // add any pak files in the format pak0.pak pak1.pak, ...
                    532:        //
                    533:        for (i=0; i<10; i++)
                    534:        {
                    535:                Com_sprintf (pakfile, sizeof(pakfile), "%s/pak%i.pak", dir, i);
                    536:                pak = FS_LoadPackFile (pakfile);
                    537:                if (!pak)
                    538:                        continue;
                    539:                search = Z_Malloc (sizeof(searchpath_t));
                    540:                search->pack = pak;
                    541:                search->next = fs_searchpaths;
                    542:                fs_searchpaths = search;                
                    543:        }
                    544: 
                    545: 
                    546: }
                    547: 
                    548: /*
                    549: ============
                    550: FS_Gamedir
                    551: 
                    552: Called to find where to write a file (demos, savegames, etc)
                    553: ============
                    554: */
                    555: char *FS_Gamedir (void)
                    556: {
1.1.1.4 ! root      557:        if (*fs_gamedir)
        !           558:                return fs_gamedir;
        !           559:        else
        !           560:                return BASEDIRNAME;
1.1       root      561: }
                    562: 
                    563: /*
                    564: =============
                    565: FS_ExecAutoexec
                    566: =============
                    567: */
                    568: void FS_ExecAutoexec (void)
                    569: {
                    570:        char *dir;
                    571:        char name [MAX_QPATH];
                    572: 
                    573:        dir = Cvar_VariableString("gamedir");
                    574:        if (*dir)
                    575:                Com_sprintf(name, sizeof(name), "%s/%s/autoexec.cfg", fs_basedir->string, dir); 
                    576:        else
                    577:                Com_sprintf(name, sizeof(name), "%s/%s/autoexec.cfg", fs_basedir->string, BASEDIRNAME); 
                    578:        if (Sys_FindFirst(name, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM))
                    579:                Cbuf_AddText ("exec autoexec.cfg\n");
                    580:        Sys_FindClose();
                    581: }
                    582: 
                    583: 
                    584: /*
                    585: ================
                    586: FS_SetGamedir
                    587: 
                    588: Sets the gamedir and path to a different directory.
                    589: ================
                    590: */
                    591: void FS_SetGamedir (char *dir)
                    592: {
                    593:        searchpath_t    *next;
                    594: 
                    595:        if (strstr(dir, "..") || strstr(dir, "/")
                    596:                || strstr(dir, "\\") || strstr(dir, ":") )
                    597:        {
                    598:                Com_Printf ("Gamedir should be a single filename, not a path\n");
                    599:                return;
                    600:        }
                    601: 
                    602:        //
                    603:        // free up any current game dir info
                    604:        //
                    605:        while (fs_searchpaths != fs_base_searchpaths)
                    606:        {
                    607:                if (fs_searchpaths->pack)
                    608:                {
                    609:                        fclose (fs_searchpaths->pack->handle);
                    610:                        Z_Free (fs_searchpaths->pack->files);
                    611:                        Z_Free (fs_searchpaths->pack);
                    612:                }
                    613:                next = fs_searchpaths->next;
                    614:                Z_Free (fs_searchpaths);
                    615:                fs_searchpaths = next;
                    616:        }
                    617: 
                    618:        //
                    619:        // flush all data, so it will be forced to reload
                    620:        //
                    621:        if (dedicated && !dedicated->value)
                    622:                Cbuf_AddText ("vid_restart\nsnd_restart\n");
                    623: 
                    624:        Com_sprintf (fs_gamedir, sizeof(fs_gamedir), "%s/%s", fs_basedir->string, dir);
                    625: 
                    626:        if (!strcmp(dir,BASEDIRNAME) || (*dir == 0))
                    627:        {
                    628:                Cvar_FullSet ("gamedir", "", CVAR_SERVERINFO|CVAR_NOSET);
                    629:                Cvar_FullSet ("game", "", CVAR_LATCH|CVAR_SERVERINFO);
                    630:        }
                    631:        else
                    632:        {
                    633:                Cvar_FullSet ("gamedir", dir, CVAR_SERVERINFO|CVAR_NOSET);
                    634:                if (fs_cddir->string[0])
                    635:                        FS_AddGameDirectory (va("%s/%s", fs_cddir->string, dir) );
                    636:                FS_AddGameDirectory (va("%s/%s", fs_basedir->string, dir) );
                    637:        }
                    638: }
                    639: 
                    640: 
                    641: /*
                    642: ================
                    643: FS_Link_f
                    644: 
                    645: Creates a filelink_t
                    646: ================
                    647: */
                    648: void FS_Link_f (void)
                    649: {
                    650:        filelink_t      *l, **prev;
                    651: 
                    652:        if (Cmd_Argc() != 3)
                    653:        {
                    654:                Com_Printf ("USAGE: link <from> <to>\n");
                    655:                return;
                    656:        }
                    657: 
                    658:        // see if the link already exists
                    659:        prev = &fs_links;
                    660:        for (l=fs_links ; l ; l=l->next)
                    661:        {
                    662:                if (!strcmp (l->from, Cmd_Argv(1)))
                    663:                {
                    664:                        Z_Free (l->to);
                    665:                        if (!strlen(Cmd_Argv(2)))
                    666:                        {       // delete it
                    667:                                *prev = l->next;
                    668:                                Z_Free (l->from);
                    669:                                Z_Free (l);
                    670:                                return;
                    671:                        }
                    672:                        l->to = CopyString (Cmd_Argv(2));
                    673:                        return;
                    674:                }
                    675:                prev = &l->next;
                    676:        }
                    677: 
                    678:        // create a new link
                    679:        l = Z_Malloc(sizeof(*l));
                    680:        l->next = fs_links;
                    681:        fs_links = l;
                    682:        l->from = CopyString(Cmd_Argv(1));
                    683:        l->fromlength = strlen(l->from);
                    684:        l->to = CopyString(Cmd_Argv(2));
                    685: }
                    686: 
                    687: /*
                    688: ** FS_ListFiles
                    689: */
                    690: char **FS_ListFiles( char *findname, int *numfiles, unsigned musthave, unsigned canthave )
                    691: {
                    692:        char *s;
                    693:        int nfiles = 0;
                    694:        char **list = 0;
                    695: 
                    696:        s = Sys_FindFirst( findname, musthave, canthave );
                    697:        while ( s )
                    698:        {
                    699:                if ( s[strlen(s)-1] != '.' )
                    700:                        nfiles++;
                    701:                s = Sys_FindNext( musthave, canthave );
                    702:        }
                    703:        Sys_FindClose ();
                    704: 
                    705:        if ( !nfiles )
                    706:                return NULL;
                    707: 
                    708:        nfiles++; // add space for a guard
                    709:        *numfiles = nfiles;
                    710: 
                    711:        list = malloc( sizeof( char * ) * nfiles );
                    712:        memset( list, 0, sizeof( char * ) * nfiles );
                    713: 
                    714:        s = Sys_FindFirst( findname, musthave, canthave );
                    715:        nfiles = 0;
                    716:        while ( s )
                    717:        {
                    718:                if ( s[strlen(s)-1] != '.' )
                    719:                {
                    720:                        list[nfiles] = strdup( s );
                    721: #ifdef _WIN32
                    722:                        strlwr( list[nfiles] );
                    723: #endif
                    724:                        nfiles++;
                    725:                }
                    726:                s = Sys_FindNext( musthave, canthave );
                    727:        }
                    728:        Sys_FindClose ();
                    729: 
                    730:        return list;
                    731: }
                    732: 
                    733: /*
                    734: ** FS_Dir_f
                    735: */
                    736: void FS_Dir_f( void )
                    737: {
                    738:        char    *path = NULL;
                    739:        char    findname[1024];
                    740:        char    wildcard[1024] = "*.*";
                    741:        char    **dirnames;
                    742:        int             ndirs;
                    743: 
                    744:        if ( Cmd_Argc() != 1 )
                    745:        {
                    746:                strcpy( wildcard, Cmd_Argv( 1 ) );
                    747:        }
                    748: 
                    749:        while ( ( path = FS_NextPath( path ) ) != NULL )
                    750:        {
                    751:                char *tmp = findname;
                    752: 
                    753:                Com_sprintf( findname, sizeof(findname), "%s/%s", path, wildcard );
                    754: 
                    755:                while ( *tmp != 0 )
                    756:                {
                    757:                        if ( *tmp == '\\' ) 
                    758:                                *tmp = '/';
                    759:                        tmp++;
                    760:                }
                    761:                Com_Printf( "Directory of %s\n", findname );
                    762:                Com_Printf( "----\n" );
                    763: 
                    764:                if ( ( dirnames = FS_ListFiles( findname, &ndirs, 0, 0 ) ) != 0 )
                    765:                {
                    766:                        int i;
                    767: 
                    768:                        for ( i = 0; i < ndirs-1; i++ )
                    769:                        {
                    770:                                if ( strrchr( dirnames[i], '/' ) )
                    771:                                        Com_Printf( "%s\n", strrchr( dirnames[i], '/' ) + 1 );
                    772:                                else
                    773:                                        Com_Printf( "%s\n", dirnames[i] );
                    774: 
                    775:                                free( dirnames[i] );
                    776:                        }
                    777:                        free( dirnames );
                    778:                }
                    779:                Com_Printf( "\n" );
                    780:        };
                    781: }
                    782: 
                    783: /*
                    784: ============
                    785: FS_Path_f
                    786: 
                    787: ============
                    788: */
                    789: void FS_Path_f (void)
                    790: {
                    791:        searchpath_t    *s;
                    792:        filelink_t              *l;
                    793: 
                    794:        Com_Printf ("Current search path:\n");
                    795:        for (s=fs_searchpaths ; s ; s=s->next)
                    796:        {
                    797:                if (s == fs_base_searchpaths)
                    798:                        Com_Printf ("----------\n");
                    799:                if (s->pack)
                    800:                        Com_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
                    801:                else
                    802:                        Com_Printf ("%s\n", s->filename);
                    803:        }
                    804: 
                    805:        Com_Printf ("\nLinks:\n");
                    806:        for (l=fs_links ; l ; l=l->next)
                    807:                Com_Printf ("%s : %s\n", l->from, l->to);
                    808: }
                    809: 
                    810: /*
                    811: ================
                    812: FS_NextPath
                    813: 
                    814: Allows enumerating all of the directories in the search path
                    815: ================
                    816: */
                    817: char *FS_NextPath (char *prevpath)
                    818: {
                    819:        searchpath_t    *s;
                    820:        char                    *prev;
                    821: 
                    822:        if (!prevpath)
                    823:                return fs_gamedir;
                    824: 
                    825:        prev = fs_gamedir;
                    826:        for (s=fs_searchpaths ; s ; s=s->next)
                    827:        {
                    828:                if (s->pack)
                    829:                        continue;
                    830:                if (prevpath == prev)
                    831:                        return s->filename;
                    832:                prev = s->filename;
                    833:        }
                    834: 
                    835:        return NULL;
                    836: }
                    837: 
                    838: 
                    839: /*
                    840: ================
                    841: FS_InitFilesystem
                    842: ================
                    843: */
                    844: void FS_InitFilesystem (void)
                    845: {
                    846:        Cmd_AddCommand ("path", FS_Path_f);
                    847:        Cmd_AddCommand ("link", FS_Link_f);
                    848:        Cmd_AddCommand ("dir", FS_Dir_f );
                    849: 
                    850:        //
                    851:        // basedir <path>
                    852:        // allows the game to run from outside the data tree
                    853:        //
                    854:        fs_basedir = Cvar_Get ("basedir", ".", CVAR_NOSET);
                    855: 
                    856:        //
                    857:        // cddir <path>
                    858:        // Logically concatenates the cddir after the basedir for 
                    859:        // allows the game to run from outside the data tree
                    860:        //
                    861:        fs_cddir = Cvar_Get ("cddir", "", CVAR_NOSET);
                    862:        if (fs_cddir->string[0])
                    863:                FS_AddGameDirectory (va("%s/"BASEDIRNAME, fs_cddir->string) );
                    864: 
                    865:        //
                    866:        // start up with baseq2 by default
                    867:        //
                    868:        FS_AddGameDirectory (va("%s/"BASEDIRNAME, fs_basedir->string) );
                    869: 
                    870:        // any set gamedirs will be freed up to here
                    871:        fs_base_searchpaths = fs_searchpaths;
                    872: 
                    873:        // check for game override
                    874:        fs_gamedirvar = Cvar_Get ("game", "", CVAR_LATCH|CVAR_SERVERINFO);
                    875:        if (fs_gamedirvar->string[0])
                    876:                FS_SetGamedir (fs_gamedirvar->string);
                    877: }
                    878: 
                    879: 
                    880: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.