#endif
#include "fs.h"
+#include "wad.h"
// Win32 requires us to add O_BINARY, but the other OSes don't have it
#ifndef O_BINARY
char fs_basedir[MAX_OSPATH];
// list of active game directories (empty if not running a mod)
-#define MAX_GAMEDIRS 16
int fs_numgamedirs = 0;
char fs_gamedirs[MAX_GAMEDIRS][MAX_QPATH];
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)"};
+cvar_t fs_empty_files_in_pack_mark_deletions = {0, "fs_empty_files_in_pack_mark_deletions", "0", "if enabled, empty files in a pak/pk3 count as not existing but cancel the search in further packs, effectively allowing patch pak/pk3 files to 'delete' files"};
/*
*/
void FS_AddGameDirectory (const char *dir)
{
- stringlist_t *list, *current;
+ int i;
+ stringlist_t list;
searchpath_t *search;
char pakfile[MAX_OSPATH];
strlcpy (fs_gamedir, dir, sizeof (fs_gamedir));
- list = listdirectory(dir);
+ stringlistinit(&list);
+ listdirectory(&list, dir);
+ stringlistsort(&list);
// add any PAK package in the directory
- for (current = list;current;current = current->next)
+ for (i = 0;i < list.numstrings;i++)
{
- if (!strcasecmp(FS_FileExtension(current->text), "pak"))
+ if (!strcasecmp(FS_FileExtension(list.strings[i]), "pak"))
{
- dpsnprintf (pakfile, sizeof (pakfile), "%s%s", dir, current->text);
+ dpsnprintf (pakfile, sizeof (pakfile), "%s%s", dir, list.strings[i]);
FS_AddPack_Fullpath(pakfile, NULL, false);
}
}
// add any PK3 package in the directory
- for (current = list;current;current = current->next)
+ for (i = 0;i < list.numstrings;i++)
{
- if (!strcasecmp(FS_FileExtension(current->text), "pk3"))
+ if (!strcasecmp(FS_FileExtension(list.strings[i]), "pk3"))
{
- dpsnprintf (pakfile, sizeof (pakfile), "%s%s", dir, current->text);
+ dpsnprintf (pakfile, sizeof (pakfile), "%s%s", dir, list.strings[i]);
FS_AddPack_Fullpath(pakfile, NULL, false);
}
}
- freedirectory(list);
+ stringlistfreecontents(&list);
// Add the directory to the search path
// (unpacked files have the priority over packed files)
*/
void FS_ClearSearchPath (void)
{
+ // unload all packs and directory information, close all pack files
+ // (if a qfile is still reading a pack it won't be harmed because it used
+ // dup() to get its own handle already)
while (fs_searchpaths)
{
searchpath_t *search = fs_searchpaths;
fs_searchpaths = search->next;
if (search->pack)
{
+ // close the file
+ close(search->pack->handle);
+ // free any memory associated with it
if (search->pack->files)
Mem_Free(search->pack->files);
Mem_Free(search->pack);
if (gamemode == GAME_NORMAL || gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
Con_Print("Playing registered version.\n");
}
+
+ // unload all wads so that future queries will return the new data
+ W_UnloadAll();
}
void FS_Rescan_f(void)
}
}
+ // halt demo playback to close the file
+ CL_Disconnect();
+
Host_SaveConfig_f();
fs_numgamedirs = numgamedirs;
// exec the new config
Host_LoadConfig_f();
- // reinitialize the loaded sounds
- S_Reload_f();
+ // unload all sounds so they will be reloaded from the new files as needed
+ S_UnloadAllSounds_f();
// reinitialize renderer (this reloads hud/console background/etc)
R_Modules_Restart();
for (i = 0;i < numgamedirs;i++)
strlcpy(gamedirs[i], Cmd_Argv(i+1), sizeof(gamedirs[i]));
- // allow gamedir change during demo loop
- if (cls.demoplayback)
- CL_Disconnect();
-
- if (cls.state != ca_disconnected || sv.active)
+ if ((cls.state == ca_connected && !cls.demoplayback) || sv.active)
{
// actually, changing during game would work fine, but would be stupid
Con_Printf("Can not change gamedir while client is connected or server is running!\n");
*/
qboolean FS_CheckGameDir(const char *gamedir)
{
- stringlist_t *list = listdirectory(va("%s%s/", fs_basedir, gamedir));
- if (list)
- freedirectory(list);
- return list != NULL;
+ qboolean success;
+ stringlist_t list;
+ stringlistinit(&list);
+ listdirectory(&list, va("%s%s/", fs_basedir, gamedir));
+ success = list.numstrings > 0;
+ stringlistfreecontents(&list);
+ return success;
}
void FS_Init_Commands(void)
{
Cvar_RegisterVariable (&scr_screenshot_name);
+ Cvar_RegisterVariable (&fs_empty_files_in_pack_mark_deletions);
Cmd_AddCommand ("gamedir", FS_GameDir_f, "changes active gamedir list (can take multiple arguments), not including base directory (example usage: gamedir ctf)");
Cmd_AddCommand ("fs_rescan", FS_Rescan_f, "rescans filesystem for new pack archives and any other changes");
*/
void FS_Shutdown (void)
{
+ // close all pack files and such
+ // (hopefully there aren't any other open files, but they'll be cleaned up
+ // by the OS anyway)
+ FS_ClearSearchPath();
Mem_FreePool (&fs_mempool);
}
// Found it
if (!diff)
{
+ if (fs_empty_files_in_pack_mark_deletions.integer && pak->files[middle].realsize == 0)
+ {
+ // yes, but the first one is empty so we treat it as not being there
+ if (!quiet && developer.integer >= 10)
+ Con_Printf("FS_FindFile: %s is marked as deleted\n", name);
+
+ if (index != NULL)
+ *index = -1;
+ return NULL;
+ }
+
if (!quiet && developer.integer >= 10)
Con_Printf("FS_FindFile: %s in %s\n",
pak->files[middle].name, pak->filename);
fssearch_t *search;
searchpath_t *searchpath;
pack_t *pak;
- int i, basepathlength, numfiles, numchars;
- stringlist_t *dir, *dirfile, *liststart, *listcurrent, *listtemp;
+ int i, basepathlength, numfiles, numchars, resultlistindex, dirlistindex;
+ stringlist_t resultlist;
+ stringlist_t dirlist;
const char *slash, *backslash, *colon, *separator;
char *basepath;
char netpath[MAX_OSPATH];
return NULL;
}
+ stringlistinit(&resultlist);
+ stringlistinit(&dirlist);
search = NULL;
- liststart = NULL;
- listcurrent = NULL;
- listtemp = NULL;
slash = strrchr(pattern, '/');
backslash = strrchr(pattern, '\\');
colon = strrchr(pattern, ':');
{
if (matchpattern(temp, (char *)pattern, true))
{
- for (listtemp = liststart;listtemp;listtemp = listtemp->next)
- if (!strcmp(listtemp->text, temp))
+ for (resultlistindex = 0;resultlistindex < resultlist.numstrings;resultlistindex++)
+ if (!strcmp(resultlist.strings[resultlistindex], temp))
break;
- if (listtemp == NULL)
+ if (resultlistindex == resultlist.numstrings)
{
- listcurrent = stringlistappend(listcurrent, temp);
- if (liststart == NULL)
- liststart = listcurrent;
+ stringlistappend(&resultlist, temp);
if (!quiet)
Con_DPrintf("SearchPackFile: %s : %s\n", pak->filename, temp);
}
{
// get a directory listing and look at each name
dpsnprintf(netpath, sizeof (netpath), "%s%s", searchpath->filename, basepath);
- if ((dir = listdirectory(netpath)))
+ stringlistinit(&dirlist);
+ listdirectory(&dirlist, netpath);
+ for (dirlistindex = 0;dirlistindex < dirlist.numstrings;dirlistindex++)
{
- for (dirfile = dir;dirfile;dirfile = dirfile->next)
+ dpsnprintf(temp, sizeof(temp), "%s%s", basepath, dirlist.strings[dirlistindex]);
+ if (matchpattern(temp, (char *)pattern, true))
{
- dpsnprintf(temp, sizeof(temp), "%s%s", basepath, dirfile->text);
- if (matchpattern(temp, (char *)pattern, true))
+ for (resultlistindex = 0;resultlistindex < resultlist.numstrings;resultlistindex++)
+ if (!strcmp(resultlist.strings[resultlistindex], temp))
+ break;
+ if (resultlistindex == resultlist.numstrings)
{
- for (listtemp = liststart;listtemp;listtemp = listtemp->next)
- if (!strcmp(listtemp->text, temp))
- break;
- if (listtemp == NULL)
- {
- listcurrent = stringlistappend(listcurrent, temp);
- if (liststart == NULL)
- liststart = listcurrent;
- if (!quiet)
- Con_DPrintf("SearchDirFile: %s\n", temp);
- }
+ stringlistappend(&resultlist, temp);
+ if (!quiet)
+ Con_DPrintf("SearchDirFile: %s\n", temp);
}
}
- freedirectory(dir);
}
+ stringlistfreecontents(&dirlist);
}
}
- if (liststart)
+ if (resultlist.numstrings)
{
- liststart = stringlistsort(liststart);
- numfiles = 0;
+ stringlistsort(&resultlist);
+ numfiles = resultlist.numstrings;
numchars = 0;
- for (listtemp = liststart;listtemp;listtemp = listtemp->next)
- {
- numfiles++;
- numchars += (int)strlen(listtemp->text) + 1;
- }
+ for (resultlistindex = 0;resultlistindex < resultlist.numstrings;resultlistindex++)
+ numchars += (int)strlen(resultlist.strings[resultlistindex]) + 1;
search = (fssearch_t *)Z_Malloc(sizeof(fssearch_t) + numchars + numfiles * sizeof(char *));
search->filenames = (char **)((char *)search + sizeof(fssearch_t));
search->filenamesbuffer = (char *)((char *)search + sizeof(fssearch_t) + numfiles * sizeof(char *));
search->numfilenames = (int)numfiles;
numfiles = 0;
numchars = 0;
- for (listtemp = liststart;listtemp;listtemp = listtemp->next)
+ for (resultlistindex = 0;resultlistindex < resultlist.numstrings;resultlistindex++)
{
size_t textlen;
search->filenames[numfiles] = search->filenamesbuffer + numchars;
- textlen = strlen(listtemp->text) + 1;
- memcpy(search->filenames[numfiles], listtemp->text, textlen);
+ textlen = strlen(resultlist.strings[resultlistindex]) + 1;
+ memcpy(search->filenames[numfiles], resultlist.strings[resultlistindex], textlen);
numfiles++;
numchars += (int)textlen;
}
- if (liststart)
- stringlistfree(liststart);
}
+ stringlistfreecontents(&resultlist);
Mem_Free(basepath);
return search;