Skip to content

Commit c72212b

Browse files
committed
Address folder selection review findings
- A folder dialog error (SDL passes a NULL file list) was treated like a cancel, silently exiting instead of reaching the missing-data error. Sys_SelectFolder now distinguishes the two; cancel still exits cleanly, inside COM_SelectBaseDir so the cancel handling isn't repeated at every call site. - The store detection gate only checked for game data of any version in the working directory, so -original/-remastered were silently ignored when the other version's data was present. It now validates the working directory against the requested version. - The remembered basedirs are kept in memory between the startup load and the deferred write instead of re-reading basedirs.txt, so a transient read failure can no longer drop the other version's entry. - New COM_FOpenPrefFile replaces the five copies of the SDL_GetPrefPath + fopen + SDL_free idiom in cfgfile.c, cmd.c, host.c and common.c.
1 parent a59fbb0 commit c72212b

7 files changed

Lines changed: 106 additions & 113 deletions

File tree

Quake/cfgfile.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -159,11 +159,7 @@ int CFG_OpenConfig (const char *cfg_name)
159159
CFG_CloseConfig ();
160160

161161
if (multiuser)
162-
{
163-
char *pref_path = SDL_GetPrefPath ("", "vkQuake");
164-
f = fopen (va ("%s/config.cfg", pref_path), "rb");
165-
SDL_free (pref_path);
166-
}
162+
f = COM_FOpenPrefFile ("config.cfg", "rb");
167163
if (f)
168164
{
169165
length = Sys_filelength (f);

Quake/cmd.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -280,11 +280,7 @@ void Cmd_Exec_f (void)
280280
}
281281

282282
if (multiuser)
283-
{
284-
char *pref_path = SDL_GetPrefPath ("", "vkQuake");
285-
f = fopen (va ("%s/%s", pref_path, Cmd_Argv (1)), "rb");
286-
SDL_free (pref_path);
287-
}
283+
f = COM_FOpenPrefFile (Cmd_Argv (1), "rb");
288284
qboolean read_from_pref_path = false;
289285
if (f)
290286
{

Quake/common.c

Lines changed: 87 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -2736,11 +2736,6 @@ static qboolean COM_IsValidFlavorDir (const char *dir, int flavor)
27362736
return false;
27372737
}
27382738

2739-
static qboolean COM_IsValidBaseDir (const char *dir)
2740-
{
2741-
return COM_IsValidFlavorDir (dir, -1);
2742-
}
2743-
27442739
/*
27452740
=================
27462741
COM_RequestedQuakeFlavor
@@ -2757,28 +2752,41 @@ static int COM_RequestedQuakeFlavor (void)
27572752
return -1;
27582753
}
27592754

2755+
/*
2756+
=================
2757+
COM_FOpenPrefFile
2758+
2759+
Opens a file in the per-user preferences directory
2760+
(%APPDATA%\vkQuake on Windows)
2761+
=================
2762+
*/
2763+
FILE *COM_FOpenPrefFile (const char *filename, const char *mode)
2764+
{
2765+
char *pref_path = SDL_GetPrefPath ("", "vkQuake");
2766+
FILE *f = fopen (va ("%s/%s", pref_path, filename), mode);
2767+
SDL_free (pref_path);
2768+
return f;
2769+
}
2770+
27602771
#ifdef USE_SDL3
27612772
/*
27622773
=================
2763-
COM_LoadSelectedBaseDirs / COM_SaveSelectedBaseDirs
2774+
COM_LoadSelectedBaseDirs
27642775
2765-
Game folders the user picked in the folder dialog, kept in the pref
2766-
dir. A new pick is only written once the engine is fully initialized
2767-
(COM_WriteSelectedBaseDir) so a folder with broken data can't get
2768-
remembered.
2776+
Game folders the user picked in the folder dialog, kept in basedirs.txt
2777+
in the pref dir. A new pick is only written back once the engine is
2778+
fully initialized (COM_WriteSelectedBaseDir) so a folder with broken
2779+
data can't get remembered.
27692780
=================
27702781
*/
2771-
static int com_pendingbasedirflavor = -1;
2772-
static char com_pendingbasedir[MAX_OSPATH];
2782+
static char com_storedbasedirs[2][MAX_OSPATH]; // indexed by quakeflavor_t
2783+
static qboolean com_pendingbasedirwrite;
27732784

2774-
static void COM_LoadSelectedBaseDirs (char *original, size_t originalsize, char *remastered, size_t remasteredsize)
2785+
static void COM_LoadSelectedBaseDirs (void)
27752786
{
27762787
char line[MAX_OSPATH + 16];
2777-
FILE *f;
2778-
char *pref_path = SDL_GetPrefPath ("", "vkQuake");
2788+
FILE *f = COM_FOpenPrefFile ("basedirs.txt", "r");
27792789

2780-
f = fopen (va ("%s/basedirs.txt", pref_path), "r");
2781-
SDL_free (pref_path);
27822790
if (!f)
27832791
return;
27842792

@@ -2790,74 +2798,70 @@ static void COM_LoadSelectedBaseDirs (char *original, size_t originalsize, char
27902798
*path++ = '\0';
27912799
path[strcspn (path, "\r\n")] = '\0';
27922800
if (!strcmp (line, "classic"))
2793-
q_strlcpy (original, path, originalsize);
2801+
q_strlcpy (com_storedbasedirs[QUAKE_FLAVOR_ORIGINAL], path, MAX_OSPATH);
27942802
else if (!strcmp (line, "remastered"))
2795-
q_strlcpy (remastered, path, remasteredsize);
2803+
q_strlcpy (com_storedbasedirs[QUAKE_FLAVOR_REMASTERED], path, MAX_OSPATH);
27962804
}
27972805

27982806
fclose (f);
27992807
}
28002808

2801-
static void COM_SaveSelectedBaseDirs (const char *original, const char *remastered)
2802-
{
2803-
FILE *f;
2804-
char *pref_path = SDL_GetPrefPath ("", "vkQuake");
2805-
2806-
f = fopen (va ("%s/basedirs.txt", pref_path), "w");
2807-
SDL_free (pref_path);
2808-
if (!f)
2809-
return;
2810-
2811-
if (original[0])
2812-
fprintf (f, "classic %s\n", original);
2813-
if (remastered[0])
2814-
fprintf (f, "remastered %s\n", remastered);
2815-
2816-
fclose (f);
2817-
}
2818-
28192809
/*
28202810
=================
28212811
COM_SelectBaseDir
28222812
28232813
Asks the user for a game folder until it contains data for the wanted
2824-
flavor (-1 accepts either); returns false if the dialog was cancelled
2814+
flavor (-1 accepts either), starting at the folder remembered from a
2815+
previous run. Exits cleanly when the user cancels the dialog; returns
2816+
false when no dialog could be shown so the caller falls through to
2817+
the regular missing-data error
28252818
=================
28262819
*/
2827-
static qboolean COM_SelectBaseDir (int flavor, const char *default_location, char *dst, size_t dstsize)
2820+
static qboolean COM_SelectBaseDir (int flavor, char *dst, size_t dstsize)
28282821
{
2829-
const char *title, *complaint;
2822+
const char *title, *complaint, *default_location;
2823+
int result;
28302824

28312825
switch (flavor)
28322826
{
28332827
case QUAKE_FLAVOR_ORIGINAL:
28342828
title = "Select your classic Quake folder";
28352829
complaint = "The selected folder does not contain " GAMENAME "/pak0.pak.";
2830+
default_location = com_storedbasedirs[QUAKE_FLAVOR_ORIGINAL];
28362831
break;
28372832
case QUAKE_FLAVOR_REMASTERED:
28382833
title = "Select your remastered Quake folder";
28392834
complaint = "The selected folder does not contain QuakeEX.kpf.";
2835+
default_location = com_storedbasedirs[QUAKE_FLAVOR_REMASTERED];
28402836
break;
28412837
default:
28422838
title = "Select your Quake folder";
28432839
complaint = "The selected folder does not contain Quake game data (" GAMENAME "/pak0.pak or QuakeEX.kpf).";
2840+
default_location =
2841+
com_storedbasedirs[QUAKE_FLAVOR_REMASTERED][0] ? com_storedbasedirs[QUAKE_FLAVOR_REMASTERED] : com_storedbasedirs[QUAKE_FLAVOR_ORIGINAL];
28442842
break;
28452843
}
28462844

2847-
while (Sys_SelectFolder (title, default_location, dst, dstsize))
2845+
while ((result = Sys_SelectFolder (title, default_location, dst, dstsize)) > 0)
28482846
{
28492847
if (COM_IsValidFlavorDir (dst, flavor))
28502848
return true;
28512849
SDL_ShowSimpleMessageBox (SDL_MESSAGEBOX_WARNING, "vkQuake", complaint, NULL);
28522850
}
28532851

2854-
return false;
2852+
if (result == 0) // cancelled
2853+
{
2854+
SDL_Quit ();
2855+
exit (0);
2856+
}
2857+
2858+
return false; // no dialog could be shown
28552859
}
28562860

28572861
static void COM_SetPendingBaseDir (int flavor, const char *dir)
28582862
{
2859-
com_pendingbasedirflavor = flavor;
2860-
q_strlcpy (com_pendingbasedir, dir, sizeof (com_pendingbasedir));
2863+
q_strlcpy (com_storedbasedirs[flavor], dir, MAX_OSPATH);
2864+
com_pendingbasedirwrite = true;
28612865
}
28622866
#endif
28632867

@@ -2872,20 +2876,22 @@ fully initialized as proof the folder contains working game data
28722876
void COM_WriteSelectedBaseDir (void)
28732877
{
28742878
#ifdef USE_SDL3
2875-
char original[MAX_OSPATH] = {0};
2876-
char remastered[MAX_OSPATH] = {0};
2879+
FILE *f;
28772880

2878-
if (com_pendingbasedirflavor < 0)
2881+
if (!com_pendingbasedirwrite)
28792882
return;
28802883

2881-
COM_LoadSelectedBaseDirs (original, sizeof (original), remastered, sizeof (remastered));
2882-
if (com_pendingbasedirflavor == QUAKE_FLAVOR_REMASTERED)
2883-
q_strlcpy (remastered, com_pendingbasedir, sizeof (remastered));
2884-
else
2885-
q_strlcpy (original, com_pendingbasedir, sizeof (original));
2886-
COM_SaveSelectedBaseDirs (original, remastered);
2884+
f = COM_FOpenPrefFile ("basedirs.txt", "w");
2885+
if (!f)
2886+
return;
28872887

2888-
com_pendingbasedirflavor = -1;
2888+
if (com_storedbasedirs[QUAKE_FLAVOR_ORIGINAL][0])
2889+
fprintf (f, "classic %s\n", com_storedbasedirs[QUAKE_FLAVOR_ORIGINAL]);
2890+
if (com_storedbasedirs[QUAKE_FLAVOR_REMASTERED][0])
2891+
fprintf (f, "remastered %s\n", com_storedbasedirs[QUAKE_FLAVOR_REMASTERED]);
2892+
2893+
fclose (f);
2894+
com_pendingbasedirwrite = false;
28892895
#endif
28902896
}
28912897

@@ -2945,56 +2951,45 @@ static void COM_FindStoreBaseDir (void)
29452951
if (!forced && !isDedicated)
29462952
{
29472953
#ifdef USE_SDL3
2948-
char stored_original[MAX_OSPATH] = {0};
2949-
char stored_remastered[MAX_OSPATH] = {0};
2950-
2951-
COM_LoadSelectedBaseDirs (stored_original, sizeof (stored_original), stored_remastered, sizeof (stored_remastered));
2954+
COM_LoadSelectedBaseDirs ();
29522955

29532956
// use the folder picked in a previous run unless the user wants a new one
29542957
if (!COM_CheckParm ("-select-basedir"))
29552958
{
2956-
if (!original[0] && stored_original[0] && COM_IsValidFlavorDir (stored_original, QUAKE_FLAVOR_ORIGINAL))
2957-
q_strlcpy (original, stored_original, sizeof (original));
2958-
if (!remastered[0] && stored_remastered[0] && COM_IsValidFlavorDir (stored_remastered, QUAKE_FLAVOR_REMASTERED))
2959-
q_strlcpy (remastered, stored_remastered, sizeof (remastered));
2959+
if (!original[0] && com_storedbasedirs[QUAKE_FLAVOR_ORIGINAL][0] &&
2960+
COM_IsValidFlavorDir (com_storedbasedirs[QUAKE_FLAVOR_ORIGINAL], QUAKE_FLAVOR_ORIGINAL))
2961+
q_strlcpy (original, com_storedbasedirs[QUAKE_FLAVOR_ORIGINAL], sizeof (original));
2962+
if (!remastered[0] && com_storedbasedirs[QUAKE_FLAVOR_REMASTERED][0] &&
2963+
COM_IsValidFlavorDir (com_storedbasedirs[QUAKE_FLAVOR_REMASTERED], QUAKE_FLAVOR_REMASTERED))
2964+
q_strlcpy (remastered, com_storedbasedirs[QUAKE_FLAVOR_REMASTERED], sizeof (remastered));
29602965
}
29612966

2962-
// still missing: ask for the folder, starting the dialog at the previous pick
2967+
// still missing: ask for the folder, remember it only once it's usable
29632968
if (requested == QUAKE_FLAVOR_ORIGINAL && !original[0])
29642969
{
2965-
if (!COM_SelectBaseDir (QUAKE_FLAVOR_ORIGINAL, stored_original, original, sizeof (original)))
2966-
{
2967-
SDL_Quit ();
2968-
exit (0);
2969-
}
2970-
COM_SetPendingBaseDir (QUAKE_FLAVOR_ORIGINAL, original);
2970+
if (COM_SelectBaseDir (QUAKE_FLAVOR_ORIGINAL, original, sizeof (original)))
2971+
COM_SetPendingBaseDir (QUAKE_FLAVOR_ORIGINAL, original);
29712972
}
29722973
else if (requested == QUAKE_FLAVOR_REMASTERED && !remastered[0])
29732974
{
2974-
if (!COM_SelectBaseDir (QUAKE_FLAVOR_REMASTERED, stored_remastered, remastered, sizeof (remastered)))
2975-
{
2976-
SDL_Quit ();
2977-
exit (0);
2978-
}
2979-
COM_SetPendingBaseDir (QUAKE_FLAVOR_REMASTERED, remastered);
2975+
if (COM_SelectBaseDir (QUAKE_FLAVOR_REMASTERED, remastered, sizeof (remastered)))
2976+
COM_SetPendingBaseDir (QUAKE_FLAVOR_REMASTERED, remastered);
29802977
}
29812978
else if (requested < 0 && !original[0] && !remastered[0])
29822979
{
29832980
char selected[MAX_OSPATH];
2984-
if (!COM_SelectBaseDir (-1, stored_remastered[0] ? stored_remastered : stored_original, selected, sizeof (selected)))
2981+
if (COM_SelectBaseDir (-1, selected, sizeof (selected)))
29852982
{
2986-
SDL_Quit ();
2987-
exit (0);
2988-
}
2989-
if (COM_IsValidFlavorDir (selected, QUAKE_FLAVOR_REMASTERED))
2990-
{
2991-
q_strlcpy (remastered, selected, sizeof (remastered));
2992-
COM_SetPendingBaseDir (QUAKE_FLAVOR_REMASTERED, selected);
2993-
}
2994-
else
2995-
{
2996-
q_strlcpy (original, selected, sizeof (original));
2997-
COM_SetPendingBaseDir (QUAKE_FLAVOR_ORIGINAL, selected);
2983+
if (COM_IsValidFlavorDir (selected, QUAKE_FLAVOR_REMASTERED))
2984+
{
2985+
q_strlcpy (remastered, selected, sizeof (remastered));
2986+
COM_SetPendingBaseDir (QUAKE_FLAVOR_REMASTERED, selected);
2987+
}
2988+
else
2989+
{
2990+
q_strlcpy (original, selected, sizeof (original));
2991+
COM_SetPendingBaseDir (QUAKE_FLAVOR_ORIGINAL, selected);
2992+
}
29982993
}
29992994
}
30002995
#else
@@ -3137,8 +3132,10 @@ void COM_InitFilesystem (void) // johnfitz -- modified based on topaz's tutorial
31373132
com_basedir[j - 1] = 0;
31383133

31393134
// no explicit -basedir: run store detection if the working directory has no
3140-
// game data, or if a store version was requested explicitly on the command line
3141-
if (!i && (!COM_IsValidBaseDir (com_basedir) || COM_CheckParm ("-steam") || COM_CheckParm ("-gog") || COM_CheckParm ("-egs") || COM_CheckParm ("-epic")))
3135+
// game data for the requested version (any version if none was requested),
3136+
// or if a store was named explicitly on the command line
3137+
if (!i && (!COM_IsValidFlavorDir (com_basedir, COM_RequestedQuakeFlavor ()) || COM_CheckParm ("-steam") || COM_CheckParm ("-gog") ||
3138+
COM_CheckParm ("-egs") || COM_CheckParm ("-epic")))
31423139
COM_FindStoreBaseDir ();
31433140

31443141
// achievements/rich presence if the game data comes from the Steam install,

Quake/common.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,9 @@ void COM_InitArgv (int argc, char **argv);
316316
void COM_InitFilesystem (void);
317317
void COM_WriteSelectedBaseDir (void);
318318

319+
// opens a file in the per-user preferences dir (%APPDATA%\vkQuake on Windows)
320+
FILE *COM_FOpenPrefFile (const char *filename, const char *mode);
321+
319322
const char *COM_SkipPath (const char *pathname);
320323
void COM_StripExtension (const char *in, char *out, size_t outsize);
321324
void COM_FileBase (const char *in, char *out, size_t outsize);

Quake/host.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -416,11 +416,7 @@ void Host_WriteConfiguration (void)
416416
if (host_initialized && !isDedicated && !host_parms->errstate)
417417
{
418418
if (multiuser)
419-
{
420-
char *pref_path = SDL_GetPrefPath ("", "vkQuake");
421-
f = fopen (va ("%s/config.cfg", pref_path), "w");
422-
SDL_free (pref_path);
423-
}
419+
f = COM_FOpenPrefFile ("config.cfg", "w");
424420
else
425421
f = fopen (va ("%s/" CONFIG_NAME, com_gamedir), "w");
426422
if (!f)

Quake/sys.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,10 @@ const char *Sys_GetEGSLauncherData (void); // Mem_Alloc'ed buffer, caller Mem_Fr
117117
qboolean Sys_GetNightdiveUserDir (char *path, size_t pathsize, const char *steamlibrary);
118118

119119
#ifdef USE_SDL3
120-
// folder picker (SDL3 file dialog); starts at default_location if non-NULL,
121-
// returns false when cancelled
122-
qboolean Sys_SelectFolder (const char *title, const char *default_location, char *dst, size_t dstsize);
120+
// folder picker (SDL3 file dialog); starts at default_location if non-NULL.
121+
// returns 1 with dst filled in, 0 when the user cancelled, -1 when no dialog
122+
// could be shown
123+
int Sys_SelectFolder (const char *title, const char *default_location, char *dst, size_t dstsize);
123124
#endif
124125

125126
//

Quake/sys_sdl.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -328,23 +328,27 @@ typedef struct folderselect_s
328328
char *dst;
329329
size_t dstsize;
330330
SDL_AtomicInt done;
331-
qboolean ok;
331+
int result;
332332
} folderselect_t;
333333

334334
static void SDLCALL Sys_FolderSelected (void *userdata, const char *const *filelist, int filter)
335335
{
336336
folderselect_t *sel = (folderselect_t *)userdata;
337337
(void)filter;
338338

339-
if (filelist && filelist[0])
339+
if (!filelist)
340+
sel->result = -1; // dialog could not be shown
341+
else if (!filelist[0])
342+
sel->result = 0; // cancelled
343+
else
340344
{
341345
q_strlcpy (sel->dst, filelist[0], sel->dstsize);
342-
sel->ok = true;
346+
sel->result = 1;
343347
}
344348
SDL_SetAtomicInt (&sel->done, 1);
345349
}
346350

347-
qboolean Sys_SelectFolder (const char *title, const char *default_location, char *dst, size_t dstsize)
351+
int Sys_SelectFolder (const char *title, const char *default_location, char *dst, size_t dstsize)
348352
{
349353
folderselect_t sel;
350354
SDL_PropertiesID props;
@@ -367,6 +371,6 @@ qboolean Sys_SelectFolder (const char *title, const char *default_location, char
367371
SDL_Delay (10);
368372
}
369373

370-
return sel.ok;
374+
return sel.result;
371375
}
372376
#endif

0 commit comments

Comments
 (0)