@@ -206,6 +206,8 @@ static int fs_count_strlwr;
206206#define FS_COUNT_STRLWR (void)0
207207#endif
208208
209+ static cvar_t * fs_autoexec ;
210+
209211#if USE_DEBUG
210212static cvar_t * fs_debug ;
211213#endif
@@ -635,6 +637,8 @@ int FS_CreatePath(char *path)
635637 ofs = p + 1 ;
636638 }
637639 }
640+ } else if (Q_isalpha (* path ) && path [1 ] == ':' ) {
641+ ofs = path + 2 ; // skip drive part
638642 }
639643#endif
640644
@@ -2149,39 +2153,39 @@ static pack_t *load_pak_file(const char *packfile)
21492153
21502154 if (!fread (& header , sizeof (header ), 1 , fp )) {
21512155 Com_SetLastError ("reading header failed" );
2152- goto fail ;
2156+ goto fail1 ;
21532157 }
21542158
21552159 if (LittleLong (header .ident ) != IDPAKHEADER ) {
21562160 Com_SetLastError ("bad header ident" );
2157- goto fail ;
2161+ goto fail1 ;
21582162 }
21592163
21602164 header .dirlen = LittleLong (header .dirlen );
21612165 if (header .dirlen > INT_MAX || header .dirlen % sizeof (dpackfile_t )) {
21622166 Com_SetLastError ("bad directory length" );
2163- goto fail ;
2167+ goto fail1 ;
21642168 }
21652169
21662170 num_files = header .dirlen / sizeof (dpackfile_t );
21672171 if (num_files < 1 ) {
21682172 Com_SetLastError ("no files" );
2169- goto fail ;
2173+ goto fail1 ;
21702174 }
21712175
21722176 header .dirofs = LittleLong (header .dirofs );
21732177 if (header .dirofs > INT_MAX ) {
21742178 Com_SetLastError ("bad directory offset" );
2175- goto fail ;
2179+ goto fail1 ;
21762180 }
21772181 if (os_fseek (fp , header .dirofs , SEEK_SET )) {
21782182 Com_SetLastError ("seeking to directory failed" );
2179- goto fail ;
2183+ goto fail1 ;
21802184 }
2181- info = FS_Malloc (header .dirlen );
2185+ info = FS_AllocTempMem (header .dirlen );
21822186 if (!fread (info , header .dirlen , 1 , fp )) {
21832187 Com_SetLastError ("reading directory failed" );
2184- goto fail ;
2188+ goto fail2 ;
21852189 }
21862190
21872191 names_len = 0 ;
@@ -2190,7 +2194,7 @@ static pack_t *load_pak_file(const char *packfile)
21902194 dfile -> filelen = LittleLong (dfile -> filelen );
21912195 if (dfile -> filelen > INT_MAX || dfile -> filepos > INT_MAX - dfile -> filelen ) {
21922196 Com_SetLastError ("file length or position too big" );
2193- goto fail ;
2197+ goto fail2 ;
21942198 }
21952199 names_len += Q_strnlen (dfile -> name , sizeof (dfile -> name )) + 1 ;
21962200 }
@@ -2225,11 +2229,12 @@ static pack_t *load_pak_file(const char *packfile)
22252229 FS_DPrintf ("%s: %u files, %u hash\n" ,
22262230 packfile , pack -> num_files , pack -> hash_size );
22272231
2228- Z_Free (info );
2229-
2232+ FS_FreeTempMem (info );
22302233 return pack ;
22312234
2232- fail :
2235+ fail2 :
2236+ FS_FreeTempMem (info );
2237+ fail1 :
22332238 fclose (fp );
22342239 Z_Free (info );
22352240 return NULL ;
@@ -3530,6 +3535,11 @@ static void setup_base_paths(void)
35303535 // the GAME bit will be removed once gamedir is set,
35313536 // and will be put back once gamedir is reset to basegame
35323537 add_game_dir (FS_PATH_BASE | FS_PATH_GAME , "%s/" BASEGAME , sys_basedir -> string );
3538+
3539+ if (sys_homedir -> string [0 ]) {
3540+ add_game_dir (FS_PATH_BASE | FS_PATH_GAME , "%s/" BASEGAME , sys_homedir -> string );
3541+ }
3542+
35333543 fs_base_searchpaths = fs_searchpaths ;
35343544}
35353545
@@ -3544,7 +3554,6 @@ static void setup_game_paths(void)
35443554
35453555 // home paths override system paths
35463556 if (sys_homedir -> string [0 ]) {
3547- add_game_dir (FS_PATH_BASE , "%s/" BASEGAME , sys_homedir -> string );
35483557 add_game_dir (FS_PATH_GAME , "%s/%s" , sys_homedir -> string , fs_game -> string );
35493558 }
35503559
@@ -3555,13 +3564,7 @@ static void setup_game_paths(void)
35553564
35563565 // this var is set for compatibility with server browsers, etc
35573566 Cvar_FullSet ("gamedir" , fs_game -> string , CVAR_ROM | CVAR_SERVERINFO , FROM_CODE );
3558-
35593567 } else {
3560- if (sys_homedir -> string [0 ]) {
3561- add_game_dir (FS_PATH_BASE | FS_PATH_GAME ,
3562- "%s/" BASEGAME , sys_homedir -> string );
3563- }
3564-
35653568 // add the game bit to base paths
35663569 for (path = fs_base_searchpaths ; path ; path = path -> next ) {
35673570 path -> mode |= FS_PATH_GAME ;
@@ -3574,6 +3577,18 @@ static void setup_game_paths(void)
35743577 Cvar_FullSet ("fs_gamedir" , fs_gamedir , CVAR_ROM , FROM_CODE );
35753578}
35763579
3580+ static void setup_base_gamedir (void )
3581+ {
3582+ if (sys_homedir -> string [0 ]) {
3583+ Q_snprintf (fs_gamedir , sizeof (fs_gamedir ), "%s/" BASEGAME , sys_homedir -> string );
3584+ } else {
3585+ Q_snprintf (fs_gamedir , sizeof (fs_gamedir ), "%s/" BASEGAME , sys_basedir -> string );
3586+ }
3587+ #ifdef _WIN32
3588+ FS_ReplaceSeparators (fs_gamedir , '/' );
3589+ #endif
3590+ }
3591+
35773592/*
35783593================
35793594FS_Restart
@@ -3592,10 +3607,7 @@ void FS_Restart(bool total)
35923607 } else {
35933608 // just change gamedir
35943609 free_game_paths ();
3595- Q_snprintf (fs_gamedir , sizeof (fs_gamedir ), "%s/" BASEGAME , sys_basedir -> string );
3596- #ifdef _WIN32
3597- FS_ReplaceSeparators (fs_gamedir , '/' );
3598- #endif
3610+ setup_base_gamedir ();
35993611 }
36003612
36013613 setup_game_paths ();
@@ -3673,6 +3685,34 @@ void FS_Shutdown(void)
36733685 Cmd_Deregister (c_fs );
36743686}
36753687
3688+ /*
3689+ ================
3690+ FS_AddConfigFiles
3691+ ================
3692+ */
3693+ void FS_AddConfigFiles (bool init )
3694+ {
3695+ int flag = init ? FS_PATH_ANY : FS_PATH_GAME ;
3696+
3697+ if (!init && !fs_autoexec -> integer )
3698+ return ;
3699+
3700+ // default.cfg and q2rtx.cfg may come from packfile, but config.cfg and autoexec.cfg
3701+ // must be real files within the game directory.
3702+ Com_AddConfigFile (COM_DEFAULT_CFG , flag );
3703+ Com_AddConfigFile (COM_Q2RTX_CFG , FS_PATH_ANY );
3704+ Com_AddConfigFile (COM_CONFIG_CFG , FS_TYPE_REAL | flag );
3705+
3706+ // autoexec.cfg is executed twice, first from basedir and then from
3707+ // gamedir. This ensures user settings configured in baseq2/autoexec.cfg
3708+ // override those in default.cfg and config.cfg.
3709+ if (* fs_game -> string )
3710+ Com_AddConfigFile (COM_AUTOEXEC_CFG , FS_TYPE_REAL | FS_PATH_BASE );
3711+ Com_AddConfigFile (COM_AUTOEXEC_CFG , FS_TYPE_REAL | FS_PATH_GAME );
3712+
3713+ Com_AddConfigFile (COM_POSTEXEC_CFG , FS_TYPE_REAL );
3714+ }
3715+
36763716// this is called when local server starts up and gets it's latched variables,
36773717// client receives a serverdata packet, or user changes the game by hand while
36783718// disconnected
@@ -3683,7 +3723,7 @@ static void fs_game_changed(cvar_t *self)
36833723 // validate it
36843724 if (* s ) {
36853725 if (!Q_stricmp (s , BASEGAME )) {
3686- Cvar_Reset (self );
3726+ Cvar_SetByVar (self , "" , FROM_CODE );
36873727 } else if (!COM_IsPath (s )) {
36883728 Com_Printf ("'%s' should contain characters [A-Za-z0-9_-] only.\n" , self -> name );
36893729 Cvar_Reset (self );
@@ -3720,22 +3760,40 @@ static void fs_game_changed(cvar_t *self)
37203760 // otherwise, restart the filesystem
37213761 CL_RestartFilesystem (false);
37223762
3723- Com_AddConfigFile (COM_DEFAULT_CFG , FS_PATH_GAME );
3724- Com_AddConfigFile (COM_Q2RTX_CFG , 0 );
3725- Com_AddConfigFile (COM_CONFIG_CFG , FS_TYPE_REAL | FS_PATH_GAME );
3763+ FS_AddConfigFiles (false);
3764+ }
37263765
3727- // If baseq2/autoexec.cfg exists exec it again after default.cfg and config.cfg.
3728- // Assumes user prefers to do configuration via autoexec.cfg and hopefully
3729- // settings and binds will be restored to their preference whenever gamedir changes after startup.
3730- if (Q_stricmp (s , BASEGAME ) && FS_FileExistsEx (COM_AUTOEXEC_CFG , FS_TYPE_REAL | FS_PATH_BASE )) {
3731- Com_AddConfigFile (COM_AUTOEXEC_CFG , FS_TYPE_REAL | FS_PATH_BASE );
3766+ static void list_dirs (genctx_t * ctx , const char * path )
3767+ {
3768+ listfiles_t list = {
3769+ .flags = FS_SEARCH_DIRSONLY ,
3770+ };
3771+
3772+ Sys_ListFiles_r (& list , path , 0 );
3773+
3774+ for (int i = 0 ; i < list .count ; i ++ ) {
3775+ char * s = list .files [i ];
3776+
3777+ if (COM_IsPath (s ))
3778+ Prompt_AddMatch (ctx , s );
3779+
3780+ Z_Free (s );
37323781 }
37333782
3734- // exec autoexec.cfg (must be a real file within the game directory)
3735- Com_AddConfigFile ( COM_AUTOEXEC_CFG , FS_TYPE_REAL | FS_PATH_GAME );
3783+ Z_Free ( list . files );
3784+ }
37363785
3737- // exec postexec.cfg (must be a real file)
3738- Com_AddConfigFile (COM_POSTEXEC_CFG , FS_TYPE_REAL );
3786+ static void fs_game_generator (genctx_t * ctx )
3787+ {
3788+ ctx -> ignoredups = true;
3789+ #ifdef _WIN32
3790+ ctx -> ignorecase = true;
3791+ #endif
3792+
3793+ list_dirs (ctx , sys_basedir -> string );
3794+
3795+ if (sys_homedir -> string [0 ])
3796+ list_dirs (ctx , sys_homedir -> string );
37393797}
37403798
37413799/*
@@ -3752,15 +3810,18 @@ void FS_Init(void)
37523810
37533811 Cmd_Register (c_fs );
37543812
3813+ fs_autoexec = Cvar_Get ("fs_autoexec" , "1" , 0 );
3814+
37553815#if USE_DEBUG
37563816 fs_debug = Cvar_Get ("fs_debug" , "0" , 0 );
37573817#endif
37583818
37593819 fs_shareware = Cvar_Get ("fs_shareware" , "0" , CVAR_ROM );
37603820
37613821 // get the game cvar and start the filesystem
3762- fs_game = Cvar_Get ("game" , DEFGAME , CVAR_LATCH | CVAR_SERVERINFO );
3822+ fs_game = Cvar_Get ("game" , DEFGAME , CVAR_LATCH | CVAR_SERVERINFO | CVAR_NOARCHIVE );
37633823 fs_game -> changed = fs_game_changed ;
3824+ fs_game -> generator = fs_game_generator ;
37643825 fs_game_changed (fs_game );
37653826
37663827 Com_Printf ("-----------------------\n" );
0 commit comments