+ const char *p;
+ int i;
+#ifdef WIN32
+ TCHAR mydocsdir[MAX_PATH + 1];
+#if _MSC_VER >= 1400
+ size_t homedirlen;
+#endif
+#endif
+ char *homedir;
+
+#ifdef WIN32
+ const char* dllnames [] =
+ {
+ "shfolder.dll", // IE 4, or Win NT and higher
+ NULL
+ };
+ Sys_LoadLibrary(dllnames, &shfolder_dll, shfolderfuncs);
+ // don't care for the result; if it fails, %USERPROFILE% will be used instead
+#endif
+
+ // Add the personal game directory
+ if((i = COM_CheckParm("-userdir")) && i < com_argc - 1)
+ {
+ dpsnprintf(fs_userdir, sizeof(fs_userdir), "%s/", com_argv[i+1]);
+ }
+ else if(COM_CheckParm("-nohome"))
+ {
+ *fs_userdir = 0;
+ }
+ else
+ {
+#ifdef WIN32
+ if(qSHGetFolderPath && (qSHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, mydocsdir) == S_OK))
+ {
+ dpsnprintf(fs_userdir, sizeof(fs_userdir), "%s/My Games/%s/", mydocsdir, gameuserdirname);
+ Con_DPrintf("Obtained personal directory %s from SHGetFolderPath\n", fs_userdir);
+ }
+ else
+ {
+ // use the environment
+#if _MSC_VER >= 1400
+ _dupenv_s (&homedir, &homedirlen, "USERPROFILE");
+#else
+ homedir = getenv("USERPROFILE");
+#endif
+
+ if(homedir)
+ {
+ dpsnprintf(fs_userdir, sizeof(fs_userdir), "%s/My Documents/My Games/%s/", homedir, gameuserdirname);
+#if _MSC_VER >= 1400
+ free(homedir);
+#endif
+ Con_DPrintf("Obtained personal directory %s from environment\n", fs_userdir);
+ }
+ }
+
+ if(!*fs_userdir)
+ Con_DPrintf("Could not obtain home directory; not supporting -mygames\n");
+#else
+ homedir = getenv ("HOME");
+ if(homedir)
+ dpsnprintf(fs_userdir, sizeof(fs_userdir), "%s/.%s/", homedir, gameuserdirname);
+
+ if(!*fs_userdir)
+ Con_DPrintf("Could not obtain home directory; assuming -nohome\n");
+#endif
+
+#ifdef WIN32
+ if(!COM_CheckParm("-mygames"))
+ {
+#if _MSC_VER >= 1400
+ int fd;
+ _sopen_s(&fd, va("%s%s/config.cfg", fs_basedir, gamedirname1), O_WRONLY | O_CREAT, _SH_DENYNO, _S_IREAD | _S_IWRITE); // note: no O_TRUNC here!
+#else
+ int fd = open (va("%s%s/config.cfg", fs_basedir, gamedirname1), O_WRONLY | O_CREAT, 0666); // note: no O_TRUNC here!
+#endif
+ if(fd >= 0)
+ {
+ close(fd);
+ *fs_userdir = 0; // we have write access to the game dir, so let's use it
+ }
+ }
+#endif
+ }
+
+ strlcpy(fs_gamedir, "", sizeof(fs_gamedir));
+
+// If the base directory is explicitly defined by the compilation process
+#ifdef DP_FS_BASEDIR
+ strlcpy(fs_basedir, DP_FS_BASEDIR, sizeof(fs_basedir));
+#else
+ *fs_basedir = 0;
+
+#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
+
+ // -basedir <path>
+ // Overrides the system supplied base directory (under GAMENAME)
+// COMMANDLINEOPTION: Filesystem: -basedir <path> chooses what base directory the game data is in, inside this there should be a data directory for the game (for example id1)
+ i = COM_CheckParm ("-basedir");
+ if (i && i < com_argc-1)
+ {
+ strlcpy (fs_basedir, com_argv[i+1], sizeof (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));
+
+ FS_ListGameDirs();
+
+ p = FS_CheckGameDir(gamedirname1);
+ if(!p || p == fs_checkgamedir_missing)
+ Con_Printf("WARNING: base gamedir %s%s/ not found!\n", fs_basedir, gamedirname1);
+
+ if(gamedirname2)
+ {
+ p = FS_CheckGameDir(gamedirname2);
+ if(!p || p == fs_checkgamedir_missing)
+ Con_Printf("WARNING: base gamedir %s%s/ not found!\n", fs_basedir, gamedirname2);
+ }
+
+ // -game <gamedir>
+ // Adds basedir/gamedir as an override game
+ // LordHavoc: now supports multiple -game directories
+ for (i = 1;i < com_argc && fs_numgamedirs < MAX_GAMEDIRS;i++)
+ {
+ if (!com_argv[i])
+ continue;
+ if (!strcmp (com_argv[i], "-game") && i < com_argc-1)
+ {
+ i++;
+ p = FS_CheckGameDir(com_argv[i]);
+ if(!p)
+ Sys_Error("Nasty -game name rejected: %s", com_argv[i]);
+ if(p == fs_checkgamedir_missing)
+ Con_Printf("WARNING: -game %s%s/ not found!\n", fs_basedir, com_argv[i]);
+ // add the gamedir to the list of active gamedirs
+ strlcpy (fs_gamedirs[fs_numgamedirs], com_argv[i], sizeof(fs_gamedirs[fs_numgamedirs]));
+ fs_numgamedirs++;
+ }
+ }
+
+ // generate the searchpath
+ FS_Rescan();
+}
+
+void FS_Init_Commands(void)
+{
+ Cvar_RegisterVariable (&scr_screenshot_name);
+ Cvar_RegisterVariable (&fs_empty_files_in_pack_mark_deletions);
+ Cvar_RegisterVariable (&cvar_fs_gamedir);
+
+ 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");
+ Cmd_AddCommand ("path", FS_Path_f, "print searchpath (game directories and archives)");
+ Cmd_AddCommand ("dir", FS_Dir_f, "list files in searchpath matching an * filename pattern, one per line");
+ Cmd_AddCommand ("ls", FS_Ls_f, "list files in searchpath matching an * filename pattern, multiple per line");
+ Cmd_AddCommand ("which", FS_Which_f, "accepts a file name as argument and reports where the file is taken from");
+}
+
+/*
+================
+FS_Shutdown
+================
+*/
+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);
+
+#ifdef WIN32
+ Sys_UnloadLibrary (&shfolder_dll);
+#endif
+}
+
+int FS_SysOpenFD(const char *filepath, const char *mode, qboolean nonblocking)
+{
+ int handle;