X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=fs.c;h=3aab0537b24f27f7cb3d4ed84befff07453de7d0;hb=9f904fa9411f2b09cd33a5ee11639ae46b17c0e1;hp=904645d6811ae2de99ffd6e7621891cae18d6b73;hpb=182f5dd46097dc11b3643dc2376b4dd6a4fa42c7;p=xonotic%2Fdarkplaces.git diff --git a/fs.c b/fs.c index 904645d6..3aab0537 100644 --- a/fs.c +++ b/fs.c @@ -1,8 +1,7 @@ /* DarkPlaces file system - Copyright (C) 2003-2005 Mathieu Olivier - Copyright (C) 1999,2000 contributors of the QuakeForge project + Copyright (C) 2003-2006 Mathieu Olivier This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -44,6 +43,11 @@ # define O_BINARY 0 #endif +// In case the system doesn't support the O_NONBLOCK flag +#ifndef O_NONBLOCK +# define O_NONBLOCK 0 +#endif + /* @@ -90,7 +94,11 @@ CONSTANTS #define MAX_WBITS 15 #define Z_OK 0 #define Z_STREAM_END 1 -#define ZLIB_VERSION "1.1.4" +#define ZLIB_VERSION "1.2.3" + +// Uncomment the following line if the zlib DLL you have still uses +// the 1.1.x series calling convention on Win32 (WINAPI) +//#define ZLIB_USES_WINAPI /* @@ -106,11 +114,11 @@ TYPES // been cast to "void*" for a matter of simplicity typedef struct { - qbyte *next_in; // next input byte + unsigned char *next_in; // next input byte unsigned int avail_in; // number of bytes available at next_in unsigned long total_in; // total nb of input bytes read so far - qbyte *next_out; // next output byte should be put there + unsigned char *next_out; // next output byte should be put there unsigned int avail_out; // remaining free space at next_out unsigned long total_out; // total nb of bytes output so far @@ -127,12 +135,10 @@ typedef struct } z_stream; -typedef enum -{ - QFILE_FLAG_NONE = 0, - QFILE_FLAG_PACKED = (1 << 0), // inside a package (PAK or PK3) - QFILE_FLAG_DEFLATED = (1 << 1) // file is compressed using the deflate algorithm (PK3 only) -} qfile_flags_t; +// inside a package (PAK or PK3) +#define QFILE_FLAG_PACKED (1 << 0) +// file is compressed using the deflate algorithm (PK3 only) +#define QFILE_FLAG_DEFLATED (1 << 1) #define FILE_BUFF_SIZE 2048 typedef struct @@ -141,21 +147,21 @@ typedef struct size_t comp_length; // length of the compressed file size_t in_ind, in_len; // input buffer current index and length size_t in_position; // position in the compressed file - qbyte input [FILE_BUFF_SIZE]; + unsigned char input [FILE_BUFF_SIZE]; } ztoolkit_t; struct qfile_s { - qfile_flags_t flags; + int flags; int handle; // file descriptor - size_t real_length; // uncompressed file size (for files opened in "read" mode) - size_t position; // current position in the file - size_t offset; // offset into the package (0 if external file) + fs_offset_t real_length; // uncompressed file size (for files opened in "read" mode) + fs_offset_t position; // current position in the file + fs_offset_t offset; // offset into the package (0 if external file) int ungetc; // single stored character from ungetc, cleared to EOF when read // Contents buffer - size_t buff_ind, buff_len; // buffer current index and length - qbyte buff [FILE_BUFF_SIZE]; + fs_offset_t buff_ind, buff_len; // buffer current index and length + unsigned char buff [FILE_BUFF_SIZE]; // For zipped files ztoolkit_t* ztk; @@ -166,7 +172,7 @@ struct qfile_s // You can get the complete ZIP format description from PKWARE website -typedef struct +typedef struct pk3_endOfCentralDir_s { unsigned int signature; unsigned short disknum; @@ -180,13 +186,13 @@ typedef struct // ------ PAK files on disk ------ // -typedef struct +typedef struct dpackfile_s { char name[56]; int filepos, filelen; } dpackfile_t; -typedef struct +typedef struct dpackheader_s { char id[4]; int dirofs; @@ -195,20 +201,18 @@ typedef struct // Packages in memory -typedef enum -{ - PACKFILE_FLAG_NONE = 0, - PACKFILE_FLAG_TRUEOFFS = (1 << 0), // the offset in packfile_t is the true contents offset - PACKFILE_FLAG_DEFLATED = (1 << 1) // file compressed using the deflate algorithm -} packfile_flags_t; +// the offset in packfile_t is the true contents offset +#define PACKFILE_FLAG_TRUEOFFS (1 << 0) +// file compressed using the deflate algorithm +#define PACKFILE_FLAG_DEFLATED (1 << 1) -typedef struct +typedef struct packfile_s { char name [MAX_QPATH]; - packfile_flags_t flags; - size_t offset; - size_t packsize; // size in the package - size_t realsize; // real file size (uncompressed) + int flags; + fs_offset_t offset; + fs_offset_t packsize; // size in the package + fs_offset_t realsize; // real file size (uncompressed) } packfile_t; typedef struct pack_s @@ -243,9 +247,11 @@ FUNCTION PROTOTYPES void FS_Dir_f(void); void FS_Ls_f(void); +static const char *FS_FileExtension (const char *in); +static searchpath_t *FS_FindFile (const char *name, int* index, qboolean quiet); static packfile_t* FS_AddFileToPack (const char* name, pack_t* pack, - size_t offset, size_t packsize, - size_t realsize, packfile_flags_t flags); + fs_offset_t offset, fs_offset_t packsize, + fs_offset_t realsize, int flags); /* @@ -258,8 +264,6 @@ VARIABLES mempool_t *fs_mempool; -int fs_filesize; - pack_t *packlist = NULL; searchpath_t *fs_searchpaths = NULL; @@ -271,6 +275,8 @@ char fs_basedir[MAX_OSPATH]; qboolean fs_modified; // set true if using non-id files +cvar_t scr_screenshot_name = {0, "scr_screenshot_name","dp", "prefix name for saved screenshots (changes based on -game commandline, as well as which game mode is running)"}; + /* ============================================================================= @@ -281,7 +287,7 @@ PRIVATE FUNCTIONS - PK3 HANDLING */ // Functions exported from zlib -#ifdef WIN32 +#if defined(WIN32) && defined(ZLIB_USES_WINAPI) # define ZEXPORT WINAPI #else # define ZEXPORT @@ -332,8 +338,15 @@ qboolean PK3_OpenLibrary (void) { const char* dllnames [] = { -#ifdef WIN32 +#if defined(WIN64) + "zlib64.dll", +#elif defined(WIN32) +# ifdef ZLIB_USES_WINAPI + "zlibwapi.dll", "zlib.dll", +# else + "zlib1.dll", +# endif #elif defined(MACOSX) "libz.dylib", #else @@ -368,8 +381,8 @@ Extract the end of the central directory from a PK3 package */ qboolean PK3_GetEndOfCentralDir (const char *packfile, int packhandle, pk3_endOfCentralDir_t *eocd) { - long filesize, maxsize; - qbyte *buffer, *ptr; + fs_offset_t filesize, maxsize; + unsigned char *buffer, *ptr; int ind; // Get the package size @@ -382,9 +395,9 @@ qboolean PK3_GetEndOfCentralDir (const char *packfile, int packhandle, pk3_endOf maxsize = filesize; else maxsize = ZIP_MAX_COMMENTS_SIZE + ZIP_END_CDIR_SIZE; - buffer = Mem_Alloc (tempmempool, maxsize); + buffer = (unsigned char *)Mem_Alloc (tempmempool, maxsize); lseek (packhandle, filesize - maxsize, SEEK_SET); - if (read (packhandle, buffer, maxsize) != (ssize_t) maxsize) + if (read (packhandle, buffer, maxsize) != (fs_offset_t) maxsize) { Mem_Free (buffer); return false; @@ -431,12 +444,12 @@ Extract the file list from a PK3 file */ int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd) { - qbyte *central_dir, *ptr; + unsigned char *central_dir, *ptr; unsigned int ind; - int remaining; + fs_offset_t remaining; // Load the central directory in memory - central_dir = Mem_Alloc (tempmempool, eocd->cdir_size); + central_dir = (unsigned char *)Mem_Alloc (tempmempool, eocd->cdir_size); lseek (pack->handle, eocd->cdir_offset, SEEK_SET); read (pack->handle, central_dir, eocd->cdir_size); @@ -448,7 +461,7 @@ int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd) ptr = central_dir; for (ind = 0; ind < eocd->nbentries; ind++) { - size_t namesize, count; + fs_offset_t namesize, count; // Checking the remaining size if (remaining < ZIP_CDIR_CHUNK_BASE_SIZE) @@ -475,7 +488,7 @@ int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd) if ((ptr[8] & 0x29) == 0 && (ptr[38] & 0x18) == 0) { // Still enough bytes for the name? - if ((size_t) remaining < namesize || namesize >= sizeof (*pack->files)) + if (remaining < namesize || namesize >= (int)sizeof (*pack->files)) { Mem_Free (central_dir); return -1; @@ -485,12 +498,11 @@ int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd) if (ptr[ZIP_CDIR_CHUNK_BASE_SIZE + namesize - 1] != '/') { char filename [sizeof (pack->files[0].name)]; - size_t offset, packsize, realsize; - packfile_flags_t flags; + fs_offset_t offset, packsize, realsize; + int flags; // Extract the name (strip it if necessary) - if (namesize >= sizeof (filename)) - namesize = sizeof (filename) - 1; + namesize = min(namesize, (int)sizeof (filename) - 1); memcpy (filename, &ptr[ZIP_CDIR_CHUNK_BASE_SIZE], namesize); filename[namesize] = '\0'; @@ -539,32 +551,49 @@ pack_t *FS_LoadPackPK3 (const char *packfile) return NULL; if (! PK3_GetEndOfCentralDir (packfile, packhandle, &eocd)) - Sys_Error ("%s is not a PK3 file", packfile); + { + Con_Printf ("%s is not a PK3 file\n", packfile); + close(packhandle); + return NULL; + } // Multi-volume ZIP archives are NOT allowed if (eocd.disknum != 0 || eocd.cdir_disknum != 0) - Sys_Error ("%s is a multi-volume ZIP archive", packfile); + { + Con_Printf ("%s is a multi-volume ZIP archive\n", packfile); + close(packhandle); + return NULL; + } // We only need to do this test if MAX_FILES_IN_PACK is lesser than 65535 // since eocd.nbentries is an unsigned 16 bits integer #if MAX_FILES_IN_PACK < 65535 if (eocd.nbentries > MAX_FILES_IN_PACK) - Sys_Error ("%s contains too many files (%hu)", packfile, eocd.nbentries); + { + Con_Printf ("%s contains too many files (%hu)\n", packfile, eocd.nbentries); + close(packhandle); + return NULL; + } #endif // Create a package structure in memory - pack = Mem_Alloc(fs_mempool, sizeof (pack_t)); + pack = (pack_t *)Mem_Alloc(fs_mempool, sizeof (pack_t)); pack->ignorecase = true; // PK3 ignores case strlcpy (pack->filename, packfile, sizeof (pack->filename)); pack->handle = packhandle; pack->numfiles = eocd.nbentries; - pack->files = Mem_Alloc(fs_mempool, eocd.nbentries * sizeof(packfile_t)); + pack->files = (packfile_t *)Mem_Alloc(fs_mempool, eocd.nbentries * sizeof(packfile_t)); pack->next = packlist; packlist = pack; real_nb_files = PK3_BuildFileList (pack, &eocd); if (real_nb_files < 0) - Sys_Error ("%s is not a valid PK3 file", packfile); + { + Con_Printf ("%s is not a valid PK3 file\n", packfile); + close(pack->handle); + Mem_Free(pack); + return NULL; + } Con_Printf("Added packfile %s (%i files)\n", packfile, real_nb_files); return pack; @@ -578,25 +607,29 @@ PK3_GetTrueFileOffset Find where the true file data offset is ==================== */ -void PK3_GetTrueFileOffset (packfile_t *pfile, pack_t *pack) +qboolean PK3_GetTrueFileOffset (packfile_t *pfile, pack_t *pack) { - qbyte buffer [ZIP_LOCAL_CHUNK_BASE_SIZE]; - size_t count; + unsigned char buffer [ZIP_LOCAL_CHUNK_BASE_SIZE]; + fs_offset_t count; // Already found? if (pfile->flags & PACKFILE_FLAG_TRUEOFFS) - return; + return true; // Load the local file description lseek (pack->handle, pfile->offset, SEEK_SET); count = read (pack->handle, buffer, ZIP_LOCAL_CHUNK_BASE_SIZE); if (count != ZIP_LOCAL_CHUNK_BASE_SIZE || BuffBigLong (buffer) != ZIP_DATA_HEADER) - Sys_Error ("Can't retrieve file %s in package %s", pfile->name, pack->filename); + { + Con_Printf ("Can't retrieve file %s in package %s\n", pfile->name, pack->filename); + return false; + } // Skip name and extra field pfile->offset += BuffLittleShort (&buffer[26]) + BuffLittleShort (&buffer[28]) + ZIP_LOCAL_CHUNK_BASE_SIZE; pfile->flags |= PACKFILE_FLAG_TRUEOFFS; + return true; } @@ -617,8 +650,8 @@ Add a file to the list of files contained into a package ==================== */ static packfile_t* FS_AddFileToPack (const char* name, pack_t* pack, - size_t offset, size_t packsize, - size_t realsize, packfile_flags_t flags) + fs_offset_t offset, fs_offset_t packsize, + fs_offset_t realsize, int flags) { int (*strcmp_funct) (const char* str1, const char* str2); int left, right, middle; @@ -638,8 +671,7 @@ static packfile_t* FS_AddFileToPack (const char* name, pack_t* pack, // If we found the file, there's a problem if (!diff) - Sys_Error ("Package %s contains the file %s several times\n", - pack->filename, name); + Con_Printf ("Package %s contains the file %s several times\n", pack->filename, name); // If we're too far in the list if (diff > 0) @@ -702,9 +734,7 @@ void FS_Path_f (void) for (s=fs_searchpaths ; s ; s=s->next) { if (s->pack) - { Con_Printf("%s (%i files)\n", s->pack->filename, s->pack->numfiles); - } else Con_Printf("%s\n", s->filename); } @@ -734,36 +764,54 @@ pack_t *FS_LoadPackPAK (const char *packfile) return NULL; read (packhandle, (void *)&header, sizeof(header)); if (memcmp(header.id, "PACK", 4)) - Sys_Error ("%s is not a packfile", packfile); + { + Con_Printf ("%s is not a packfile\n", packfile); + close(packhandle); + return NULL; + } header.dirofs = LittleLong (header.dirofs); header.dirlen = LittleLong (header.dirlen); if (header.dirlen % sizeof(dpackfile_t)) - Sys_Error ("%s has an invalid directory size", packfile); + { + Con_Printf ("%s has an invalid directory size\n", packfile); + close(packhandle); + return NULL; + } numpackfiles = header.dirlen / sizeof(dpackfile_t); if (numpackfiles > MAX_FILES_IN_PACK) - Sys_Error ("%s has %i files", packfile, numpackfiles); + { + Con_Printf ("%s has %i files\n", packfile, numpackfiles); + close(packhandle); + return NULL; + } + + info = (dpackfile_t *)Mem_Alloc(tempmempool, sizeof(*info) * numpackfiles); + lseek (packhandle, header.dirofs, SEEK_SET); + if(header.dirlen != read (packhandle, (void *)info, header.dirlen)) + { + Con_Printf("%s is an incomplete PAK, not loading\n", packfile); + Mem_Free(info); + close(packhandle); + return NULL; + } - pack = Mem_Alloc(fs_mempool, sizeof (pack_t)); + pack = (pack_t *)Mem_Alloc(fs_mempool, sizeof (pack_t)); pack->ignorecase = false; // PAK is case sensitive strlcpy (pack->filename, packfile, sizeof (pack->filename)); pack->handle = packhandle; pack->numfiles = 0; - pack->files = Mem_Alloc(fs_mempool, numpackfiles * sizeof(packfile_t)); + pack->files = (packfile_t *)Mem_Alloc(fs_mempool, numpackfiles * sizeof(packfile_t)); pack->next = packlist; packlist = pack; - info = Mem_Alloc(tempmempool, sizeof(*info) * numpackfiles); - lseek (packhandle, header.dirofs, SEEK_SET); - read (packhandle, (void *)info, header.dirlen); - // parse the directory for (i = 0;i < numpackfiles;i++) { - size_t offset = LittleLong (info[i].filepos); - size_t size = LittleLong (info[i].filelen); + fs_offset_t offset = LittleLong (info[i].filepos); + fs_offset_t size = LittleLong (info[i].filelen); FS_AddFileToPack (info[i].name, pack, offset, size, size, PACKFILE_FLAG_TRUEOFFS); } @@ -774,6 +822,136 @@ pack_t *FS_LoadPackPAK (const char *packfile) return pack; } +/* +================ +FS_AddPack_Fullpath + +Adds the given pack to the search path. +The pack type is autodetected by the file extension. + +Returns true if the file was successfully added to the +search path or if it was already included. + +If keep_plain_dirs is set, the pack will be added AFTER the first sequence of +plain directories. +================ +*/ +static qboolean FS_AddPack_Fullpath(const char *pakfile, qboolean *already_loaded, qboolean keep_plain_dirs) +{ + searchpath_t *search; + pack_t *pak = NULL; + const char *ext = FS_FileExtension(pakfile); + + for(search = fs_searchpaths; search; search = search->next) + { + if(search->pack && !strcasecmp(search->pack->filename, pakfile)) + { + if(already_loaded) + *already_loaded = true; + return true; // already loaded + } + } + + if(already_loaded) + *already_loaded = false; + + if(!strcasecmp(ext, "pak")) + pak = FS_LoadPackPAK (pakfile); + else if(!strcasecmp(ext, "pk3")) + pak = FS_LoadPackPK3 (pakfile); + else + Con_Printf("\"%s\" does not have a pack extension\n", pakfile); + + if (pak) + { + if(keep_plain_dirs) + { + // find the first item whose next one is a pack or NULL + searchpath_t *insertion_point = 0; + if(fs_searchpaths && !fs_searchpaths->pack) + { + insertion_point = fs_searchpaths; + for(;;) + { + if(!insertion_point->next) + break; + if(insertion_point->next->pack) + break; + insertion_point = insertion_point->next; + } + } + // If insertion_point is NULL, this means that either there is no + // item in the list yet, or that the very first item is a pack. In + // that case, we want to insert at the beginning... + if(!insertion_point) + { + search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t)); + search->pack = pak; + search->next = fs_searchpaths; + fs_searchpaths = search; + } + else + // otherwise we want to append directly after insertion_point. + { + search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t)); + search->pack = pak; + search->next = insertion_point->next; + insertion_point->next = search; + } + } + else + { + search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t)); + search->pack = pak; + search->next = fs_searchpaths; + fs_searchpaths = search; + } + return true; + } + else + { + Con_Printf("unable to load pak \"%s\"\n", pakfile); + return false; + } +} + + +/* +================ +FS_AddPack + +Adds the given pack to the search path and searches for it in the game path. +The pack type is autodetected by the file extension. + +Returns true if the file was successfully added to the +search path or if it was already included. + +If keep_plain_dirs is set, the pack will be added AFTER the first sequence of +plain directories. +================ +*/ +qboolean FS_AddPack(const char *pakfile, qboolean *already_loaded, qboolean keep_plain_dirs) +{ + char fullpath[MAX_QPATH]; + int index; + searchpath_t *search; + + if(already_loaded) + *already_loaded = false; + + // then find the real name... + search = FS_FindFile(pakfile, &index, true); + if(!search || search->pack) + { + Con_Printf("could not find pak \"%s\"\n", pakfile); + return false; + } + + dpsnprintf(fullpath, sizeof(fullpath), "%s%s", search->filename, pakfile); + + return FS_AddPack_Fullpath(fullpath, already_loaded, keep_plain_dirs); +} + /* ================ @@ -787,7 +965,6 @@ void FS_AddGameDirectory (const char *dir) { stringlist_t *list, *current; searchpath_t *search; - pack_t *pak; char pakfile[MAX_OSPATH]; strlcpy (fs_gamedir, dir, sizeof (fs_gamedir)); @@ -797,45 +974,27 @@ void FS_AddGameDirectory (const char *dir) // add any PAK package in the directory for (current = list;current;current = current->next) { - if (matchpattern(current->text, "*.pak", true)) + if (!strcasecmp(FS_FileExtension(current->text), "pak")) { - dpsnprintf (pakfile, sizeof (pakfile), "%s/%s", dir, current->text); - pak = FS_LoadPackPAK (pakfile); - if (pak) - { - search = Mem_Alloc(fs_mempool, sizeof(searchpath_t)); - search->pack = pak; - search->next = fs_searchpaths; - fs_searchpaths = search; - } - else - Con_Printf("unable to load pak \"%s\"\n", pakfile); + dpsnprintf (pakfile, sizeof (pakfile), "%s%s", dir, current->text); + FS_AddPack_Fullpath(pakfile, NULL, false); } } // add any PK3 package in the director for (current = list;current;current = current->next) { - if (matchpattern(current->text, "*.pk3", true)) + if (!strcasecmp(FS_FileExtension(current->text), "pk3")) { - dpsnprintf (pakfile, sizeof (pakfile), "%s/%s", dir, current->text); - pak = FS_LoadPackPK3 (pakfile); - if (pak) - { - search = Mem_Alloc(fs_mempool, sizeof(searchpath_t)); - search->pack = pak; - search->next = fs_searchpaths; - fs_searchpaths = search; - } - else - Con_Printf("unable to load pak \"%s\"\n", pakfile); + dpsnprintf (pakfile, sizeof (pakfile), "%s%s", dir, current->text); + FS_AddPack_Fullpath(pakfile, NULL, false); } } freedirectory(list); // Add the directory to the search path // (unpacked files have the priority over packed files) - search = Mem_Alloc(fs_mempool, sizeof(searchpath_t)); + search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t)); strlcpy (search->filename, dir, sizeof (search->filename)); search->next = fs_searchpaths; fs_searchpaths = search; @@ -854,13 +1013,13 @@ void FS_AddGameHierarchy (const char *dir) #endif // Add the common game directory - FS_AddGameDirectory (va("%s/%s", fs_basedir, dir)); + FS_AddGameDirectory (va("%s%s/", fs_basedir, dir)); #ifndef WIN32 // Add the personal game directory homedir = getenv ("HOME"); if (homedir != NULL && homedir[0] != '\0') - FS_AddGameDirectory (va("%s/.%s/%s", homedir, gameuserdirname, dir)); + FS_AddGameDirectory (va("%s/.%s/%s/", homedir, gameuserdirname, dir)); #endif } @@ -876,14 +1035,14 @@ static const char *FS_FileExtension (const char *in) separator = strrchr(in, '/'); backslash = strrchr(in, '\\'); - if (separator < backslash) + if (!separator || separator < backslash) separator = backslash; colon = strrchr(in, ':'); - if (separator < colon) + if (!separator || separator < colon) separator = colon; dot = strrchr(in, '.'); - if (dot == NULL || dot < separator) + if (dot == NULL || (separator && (dot < separator))) return ""; return dot + 1; @@ -902,8 +1061,28 @@ void FS_Init (void) fs_mempool = Mem_AllocPool("file management", 0, NULL); - strcpy(fs_basedir, "."); - strcpy(fs_gamedir, "."); + strcpy(fs_gamedir, ""); + +// If the base directory is explicitly defined by the compilation process +#ifdef DP_FS_BASEDIR + strcpy(fs_basedir, DP_FS_BASEDIR); +#else + strcpy(fs_basedir, ""); + +#ifdef MACOSX + // FIXME: is there a better way to find the directory outside the .app? + if (strstr(com_argv[0], ".app/")) + { + char *split; + + split = strstr(com_argv[0], ".app/"); + while (split > com_argv[0] && *split != '/') + split--; + strlcpy(fs_basedir, com_argv[0], sizeof(fs_basedir)); + fs_basedir[split - com_argv[0]] = 0; + } +#endif +#endif PK3_OpenLibrary (); @@ -914,11 +1093,15 @@ void FS_Init (void) if (i && i < com_argc-1) { strlcpy (fs_basedir, com_argv[i+1], sizeof (fs_basedir)); - i = strlen (fs_basedir); + i = (int)strlen (fs_basedir); if (i > 0 && (fs_basedir[i-1] == '\\' || fs_basedir[i-1] == '/')) fs_basedir[i-1] = 0; } + // add a path separator to the end of the basedir if it lacks one + if (fs_basedir[0] && fs_basedir[strlen(fs_basedir) - 1] != '/' && fs_basedir[strlen(fs_basedir) - 1] != '\\') + strlcat(fs_basedir, "/", sizeof(fs_basedir)); + // -path