Browse Source

Improve path combination & variadic print, fix load logic

1. Provide a new function `UTIL_CombinePath` for path comination
purpose, which handles path separator automatically between path
elements.
2. Rename the `va` function into `UTIL_va`, and make it reentrant by
using user-supplied buffer rather than internally-provided buffer.
However, to make easy use of this function, a macro `PAL_va` and some
pre-defined internal global buffers are also provided, so that the
function can be used almost the same way as before.
3. Fix the logic in `PAL_LoadGame` to load save files from save path
rather than game path.
Lou Yihua 6 years ago
parent
commit
a816001366
16 changed files with 194 additions and 67 deletions
  1. 14 5
      audio.c
  2. 3 0
      common.h
  3. 3 5
      global.c
  4. 2 1
      main.c
  5. 1 2
      midi.c
  6. 2 2
      mp3play.c
  7. 1 2
      oggplay.c
  8. 2 2
      palcfg.c
  9. 1 1
      psp/main_PSP.c
  10. 0 5
      rixplay.cpp
  11. 3 6
      uigame.c
  12. 1 1
      unix/native_midi.cpp
  13. 1 1
      unix/pal_config.h
  14. 99 26
      util.c
  15. 56 3
      util.h
  16. 5 5
      video.c

+ 14 - 5
audio.c

@@ -259,9 +259,9 @@ AUDIO_OpenDevice(
    switch (gConfig.eMusicType)
    {
    case MUSIC_RIX:
-       if (!(gAudioDevice.pMusPlayer = RIX_Init(va("%s/%s", gConfig.pszGamePath, "mus.mkf"))))
+       if (!(gAudioDevice.pMusPlayer = RIX_Init(PAL_CombinePath(0, gConfig.pszGamePath, "mus.mkf"))))
        {
-           gAudioDevice.pMusPlayer = RIX_Init(va("%s/%s", gConfig.pszGamePath, "MUS.MKF"));
+           gAudioDevice.pMusPlayer = RIX_Init(PAL_CombinePath(0, gConfig.pszGamePath, "MUS.MKF"));
        }
 	   break;
    case MUSIC_MP3:
@@ -495,6 +495,14 @@ AUDIO_PlayMusic(
    FLOAT     flFadeTime
 )
 {
+	if (iNumRIX > 0)
+	{
+		//
+		// Stop the current CD music.
+		//
+		AUDIO_PlayCDTrack(-1);
+	}
+
    if (gConfig.eMusicType == MUSIC_MIDI)
    {
       MIDI_Play(iNumRIX, fLoop);
@@ -529,6 +537,10 @@ AUDIO_PlayCDTrack(
 --*/
 {
 	BOOL ret = FALSE;
+	if (iNumTrack > 0)
+	{
+		AUDIO_PlayMusic(-1, FALSE, 0);
+	}
 #if PAL_HAS_SDLCD
    if (gAudioDevice.pCD != NULL)
    {
@@ -538,8 +550,6 @@ AUDIO_PlayCDTrack(
 
          if (iNumTrack != -1)
          {
-            AUDIO_PlayMusic(-1, FALSE, 0);
-
             if (SDL_CDPlayTracks(gAudioDevice.pCD, iNumTrack - 1, 0, 1, 0) == 0)
             {
                return TRUE;
@@ -553,7 +563,6 @@ AUDIO_PlayCDTrack(
    {
 	   if (iNumTrack != -1)
 	   {
-		   AUDIO_PlayMusic(-1, FALSE, 0);
 		   ret = gAudioDevice.pCDPlayer->Play(gAudioDevice.pCDPlayer, PAL_CDTRACK_BASE + iNumTrack, TRUE, 0);
 	   }
 	   else

+ 3 - 0
common.h

@@ -246,4 +246,7 @@ typedef enum tagLOGLEVEL
 # define PAL_HAS_CONFIG_PAGE   FALSE
 #endif
 
+#define PAL_MAX_GLOBAL_BUFFERS 4
+#define PAL_GLOBAL_BUFFER_SIZE 1024
+
 #endif

+ 3 - 5
global.c

@@ -202,7 +202,7 @@ PAL_InitGlobals(
    //
    Decompress = gConfig.fIsWIN95 ? YJ2_Decompress : YJ1_Decompress;
 
-   gpGlobals->lpObjectDesc = gConfig.fIsWIN95 ? NULL : PAL_LoadObjectDesc(va("%s%s", gConfig.pszGamePath, "desc.dat"));
+   gpGlobals->lpObjectDesc = gConfig.fIsWIN95 ? NULL : PAL_LoadObjectDesc(PAL_CombinePath(0, gConfig.pszGamePath, "desc.dat"));
    gpGlobals->bCurrentSaveSlot = 1;
 
    return 0;
@@ -575,7 +575,7 @@ PAL_LoadGame_Common(
 	//
 	// Try to open the specified file
 	//
-	FILE *fp = UTIL_OpenFileForMode(szFileName, "rb");
+	FILE *fp = fopen(szFileName, "rb");
 	//
 	// Read all data from the file and close.
 	//
@@ -921,9 +921,7 @@ PAL_InitGameData(
    //
    // try loading from the saved game file.
    //
-   char saveFileName[PAL_MAX_PATH];
-   snprintf(saveFileName, PAL_MAX_PATH, "%d%s", iSaveSlot, ".rpg");
-   if (iSaveSlot == 0 || PAL_LoadGame(saveFileName) != 0)
+   if (iSaveSlot == 0 || PAL_LoadGame(PAL_CombinePath(0, gConfig.pszSavePath, PAL_va(1, "%d.rpg", iSaveSlot))) != 0)
    {
       //
       // Cannot load the saved game file. Load the defaults.

+ 2 - 1
main.c

@@ -102,7 +102,8 @@ PAL_Init(
    AUDIO_OpenDevice();
    PAL_AVIInit();
 
-   VIDEO_SetWindowTitle(va("Pal %s%s%s",
+   VIDEO_SetWindowTitle(UTIL_va(UTIL_GlobalBuffer(0), PAL_GLOBAL_BUFFER_SIZE,
+	   "Pal %s%s%s",
 	   gConfig.fIsWIN95 ? "Win95" : "DOS",
 #if defined(_DEBUG) || defined(DEBUG)
 	   " (Debug) ",

+ 1 - 2
midi.c

@@ -40,7 +40,6 @@ MIDI_Play(
 		return;
 	}
 
-	AUDIO_PlayCDTrack(-1);
 	native_midi_stop(g_pMidi);
 	native_midi_freesong(g_pMidi);
 	g_pMidi = NULL;
@@ -53,7 +52,7 @@ MIDI_Play(
 
 	if (gConfig.fIsWIN95)
 	{
-		g_pMidi = native_midi_loadsong(va("%sMusics/%.3d.mid", gConfig.pszGamePath, iNumRIX));
+		g_pMidi = native_midi_loadsong(PAL_CombinePath(0, gConfig.pszGamePath, PAL_va(1, "Musics/%.3d.mid", iNumRIX)));
 	}
 
 	if (!g_pMidi)

+ 2 - 2
mp3play.c

@@ -113,9 +113,9 @@ MP3_Play(
 
 	if (iNum > 0)
 	{
-		if ((player->pMP3 = mad_openFile(va("%smp3/%.2d.mp3", gConfig.pszGamePath, iNum), AUDIO_GetDeviceSpec(), gConfig.iResampleQuality)) == NULL)
+		if ((player->pMP3 = mad_openFile(PAL_CombinePath(0, gConfig.pszGamePath, PAL_va(1, "mp3/%.2d.mp3", iNum)), AUDIO_GetDeviceSpec(), gConfig.iResampleQuality)) == NULL)
 		{
-			player->pMP3 = mad_openFile(va("%sMP3/%.2d.MP3", gConfig.pszGamePath, iNum), AUDIO_GetDeviceSpec(), gConfig.iResampleQuality);
+			player->pMP3 = mad_openFile(PAL_CombinePath(0, gConfig.pszGamePath, PAL_va(1, "MP3/%.2d.MP3", iNum)), AUDIO_GetDeviceSpec(), gConfig.iResampleQuality);
 		}
 
 		if (player->pMP3)

+ 1 - 2
oggplay.c

@@ -405,7 +405,6 @@ OGG_Play(
 	FLOAT       flFadeTime
 	)
 {
-	char filename[256];
 	LPOGGPLAYER player = (LPOGGPLAYER)object;
 
 	//
@@ -436,7 +435,7 @@ OGG_Play(
 		return TRUE;
 	}
 
-	player->fp = UTIL_OpenFile(strcpy(filename, va("ogg/%.2d.ogg", iNum)));
+	player->fp = UTIL_OpenFile(PAL_va(0, "ogg/%.2d.ogg", iNum));
 	if (player->fp == NULL)
 	{
 		return FALSE;

+ 2 - 2
palcfg.c

@@ -297,7 +297,7 @@ PAL_LoadConfig(
 
 	for (PALCFG_ITEM i = PALCFG_ALL_MIN; i < PALCFG_ALL_MAX; i++) values[i] = gConfigItems[i].DefaultValue;
 
-	if (fFromFile && (fp = fopen(va("%ssdlpal.cfg", PAL_CONFIG_PREFIX), "r")))
+	if (fFromFile && (fp = fopen(PAL_CombinePath(0, PAL_CONFIG_PREFIX, "sdlpal.cfg"), "r")))
 	{
 		PAL_LARGE char buf[512];
 
@@ -477,7 +477,7 @@ PAL_SaveConfig(
 )
 {
 	char buf[512];
-	FILE *fp = fopen(va("%ssdlpal.cfg", PAL_CONFIG_PREFIX), "w");
+	FILE *fp = fopen(PAL_CombinePath(0, PAL_CONFIG_PREFIX, "sdlpal.cfg"), "w");
 
 	if (fp)
 	{

+ 1 - 1
psp/main_PSP.c

@@ -71,7 +71,7 @@ int PSPSuspendCallback(int arg1, int pwrflags, void *common)
     gpGlobals->f.fpDATA = UTIL_OpenRequiredFile("data.mkf");
     gpGlobals->f.fpFIRE = UTIL_OpenRequiredFile("fire.mkf");
     gpGlobals->f.fpSSS = UTIL_OpenRequiredFile("sss.mkf");
-    gpGlobals->lpObjectDesc = PAL_LoadObjectDesc(va("%s%s", PAL_PREFIX, "desc.dat"));
+    gpGlobals->lpObjectDesc = PAL_LoadObjectDesc(PAL_CombinePath(0, PAL_PREFIX, "desc.dat"));
     SOUND_Reload();
   }
   int cbid;

+ 0 - 5
rixplay.cpp

@@ -333,11 +333,6 @@ RIX_Play(
 		return FALSE;
 	}
 
-	//
-	// Stop the current CD music.
-	//
-	AUDIO_PlayCDTrack(-1);
-
 	if (iNumRIX == pRixPlayer->iCurrentMusic && pRixPlayer->iNextMusic == -1)
 	{
 		/* Will play the same music without any pending play changes,

+ 3 - 6
uigame.c

@@ -22,13 +22,10 @@
 
 #include "main.h"
 
-static WORD GetSavedTimes(int saveslot)
+static WORD GetSavedTimes(int iSaveSlot)
 {
-	FILE *fp;
+	FILE *fp = fopen(PAL_CombinePath(0, gConfig.pszSavePath, PAL_va(1, "%d.rpg", iSaveSlot)), "rb");
 	WORD wSavedTimes = 0;
-	char buf[1024];
-	sprintf(buf, "%d%s", saveslot, ".rpg");
-	fp = UTIL_OpenFileForMode(buf, "rb");
 	if (fp != NULL)
 	{
 		if (fread(&wSavedTimes, sizeof(WORD), 1, fp) == 1)
@@ -602,7 +599,7 @@ PAL_SystemMenu(
                wSavedTimes = curSavedTimes;
             }
          }
-         PAL_SaveGame(va("%s/%d%s", gConfig.pszSavePath, iSlot, ".rpg"), wSavedTimes + 1);
+         PAL_SaveGame(PAL_CombinePath(0, gConfig.pszSavePath, PAL_va(1, "%d.rpg", iSlot)), wSavedTimes + 1);
       }
       break;
 

+ 1 - 1
unix/native_midi.cpp

@@ -35,7 +35,7 @@ char* cliplayer = nullptr;
 static char *which(const char *cmd)
 {
 	static char path[PATH_MAX] = { '\0' };
-    FILE *fp = popen(va("which %s", cmd), "r");
+    FILE *fp = popen(PAL_va(0, "which %s", cmd), "r");
     if (fp == NULL) {
         return NULL;
     }else{

+ 1 - 1
unix/pal_config.h

@@ -46,7 +46,7 @@
 #  define PAL_VIDEO_INIT_FLAGS  (SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | (gConfig.fFullScreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0))
 # else
 #  define PAL_VIDEO_INIT_FLAGS  (SDL_HWSURFACE | SDL_RESIZABLE | (gConfig.fFullScreen ? SDL_FULLSCREEN : 0))
-#  define PAL_FATAL_OUTPUT(s)   system(va("beep; xmessage -center \"FATAL ERROR: %s\"", (s)))
+#  define PAL_FATAL_OUTPUT(s)   system(PAL_va(0, "beep; xmessage -center \"FATAL ERROR: %s\"", (s)))
 # endif
 
 # define PAL_SDL_INIT_FLAGS	(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_CDROM | SDL_INIT_NOPARACHUTE | SDL_INIT_JOYSTICK)

+ 99 - 26
util.c

@@ -32,6 +32,8 @@
 #include "SDL_messagebox.h"
 #endif
 
+static char internal_buffer[PAL_MAX_GLOBAL_BUFFERS + 1][PAL_GLOBAL_BUFFER_SIZE];
+
 void UTIL_MsgBox(char *string)
 {
 #if SDL_VERSION_ATLEAST(2, 0, 0)
@@ -101,34 +103,27 @@ trim(
 }
 
 char *
-va(
-   const char *format,
-   ...
+UTIL_va(
+	char       *buffer,
+	int         buflen,
+	const char *format,
+	...
 )
-/*++
-  Purpose:
-
-    Does a varargs printf into a temp buffer, so we don't need to have
-    varargs versions of all text functions.
-
-  Parameters:
-
-    format - the format string.
-
-  Return value:
-
-    Pointer to the result string.
-
---*/
 {
-   static char string[1024];
-   va_list     argptr;
+   if (buflen > 0 && buffer)
+   {
+	   va_list     argptr;
 
-   va_start(argptr, format);
-   vsnprintf(string, sizeof(string), format, argptr);
-   va_end(argptr);
+	   va_start(argptr, format);
+	   vsnprintf(buffer, buflen, format, argptr);
+	   va_end(argptr);
 
-   return string;
+	   return buffer;
+   }
+   else
+   {
+	   return NULL;
+   }
 }
 
 /*
@@ -493,7 +488,7 @@ UTIL_OpenFileForMode(
 	if (UTIL_IsAbsolutePath(lpszFileName))
 		fp = fopen(lpszFileName, szMode);
 	else
-		fp = fopen(va("%s/%s", gConfig.pszGamePath, lpszFileName), szMode);
+		fp = fopen(UTIL_CombinePath(internal_buffer[PAL_MAX_GLOBAL_BUFFERS], PAL_GLOBAL_BUFFER_SIZE, 2, gConfig.pszGamePath, lpszFileName), szMode);
 
 #if !defined(PAL_FILESYSTEM_IGNORE_CASE) || !PAL_FILESYSTEM_IGNORE_CASE
 	if (fp == NULL)
@@ -506,7 +501,7 @@ UTIL_OpenFileForMode(
 		while (n-- > 0)
 		{
 			if (!fp && strcasecmp(list[n]->d_name, lpszFileName) == 0)
-				fp = fopen(va("%s/%s", gConfig.pszGamePath, list[n]->d_name), szMode);
+				fp = fopen(UTIL_CombinePath(internal_buffer[PAL_MAX_GLOBAL_BUFFERS], PAL_GLOBAL_BUFFER_SIZE, 2, gConfig.pszGamePath, list[n]->d_name), szMode);
 			free(list[n]);
 		}
 		free(list);
@@ -541,6 +536,83 @@ UTIL_CloseFile(
    }
 }
 
+
+const char *
+UTIL_CombinePath(
+	char       *buffer,
+	int         buflen,
+	int         numentry,
+	...
+)
+{
+#ifdef _WIN32
+#define isseparator(x) ((x) == '/' || (x) == '\\')
+#else
+#define isseparator(x) ((x) == '/')
+#endif
+	if (buffer && buflen > 0 && numentry > 0)
+	{
+		const char *retval = buffer;
+		va_list argptr;
+
+		va_start(argptr, numentry);
+		for (int i = 0; i < numentry && buflen > 1; i++)
+		{
+			const char *path = va_arg(argptr, const char *);
+			int path_len = path ? strlen(path) : 0;
+			int append_delim = (i < numentry - 1 && path_len > 0 && !isseparator(path[path_len - 1]));
+			
+			for (int is_sep = 0, j = 0; j < path_len && buflen > append_delim + 1; j++)
+			{
+				//
+				// Skip continuous path separators
+				// 
+				if (isseparator(path[j]))
+				{
+					if (is_sep)
+						continue;
+					else
+						is_sep = 1;
+				}
+				else
+				{
+					is_sep = 0;
+				}
+				*buffer++ = path[j];
+				buflen--;
+			}
+			//
+			// Make sure a path delimeter is append to the destination if this is not the last entry
+			// 
+			if (append_delim)
+			{
+				*buffer++ = '/';
+				buflen--;
+			}
+		}
+		va_end(argptr);
+
+		*buffer = '\0';
+
+		return retval;
+	}
+	else
+	{
+		return NULL;
+	}
+#undef isseparator
+}
+
+
+char *
+UTIL_GlobalBuffer(
+	int         index
+)
+{
+	return (index >= 0 && index < PAL_MAX_GLOBAL_BUFFERS) ? internal_buffer[index] : NULL;
+}
+
+
 #if !defined(PAL_HAS_PLATFORM_SPECIFIC_UTILS)
 
 BOOL
@@ -579,6 +651,7 @@ UTIL_Platform_Quit(
 
 #endif
 
+
 /*
 * Logging utilities
 */

+ 56 - 3
util.h

@@ -42,10 +42,36 @@ trim(
    char *str
 );
 
-char *va(
-   const char *format,
-   ...
+char *
+UTIL_GlobalBuffer(
+	int         index
+);
+
+/*++
+  Purpose:
+
+    Does a varargs printf into the user-supplied buffer,
+	so we don't need to have varargs versions of all text functions.
+
+  Parameters:
+
+    buffer - user-supplied buffer.
+	buflen - size of the buffer, including null-terminator.
+    format - the format string.
+
+  Return value:
+
+    The value of buffer if buffer is non-NULL and buflen > 0, otherwise NULL.
+
+--*/
+char *
+UTIL_va(
+	char       *buffer,
+	int         buflen,
+	const char *format,
+	...
 );
+#define PAL_va(i, fmt, ...) UTIL_va(UTIL_GlobalBuffer(i), PAL_GLOBAL_BUFFER_SIZE, fmt, __VA_ARGS__)
 
 int
 RandomLong(
@@ -108,6 +134,33 @@ UTIL_CloseFile(
    FILE                *fp
 );
 
+/*++
+  Purpose:
+
+    Combine the 'dir' and 'file' part into a single path string.
+	If 'dir' is non-NULL, then it ensures that the output string contains
+	'/' between 'dir' and 'file' (no matter whether 'file' is NULL or not).
+
+  Parameters:
+
+    buffer - user-supplied buffer.
+	buflen - size of the buffer, including null-terminator.
+    dir    - the directory path.
+	file   - the file path.
+
+  Return value:
+
+    The value of buffer if buffer is non-NULL and buflen > 0, otherwise NULL.
+
+--*/
+const char *
+UTIL_CombinePath(
+	char       *buffer,
+	int         buflen,
+	int         numentry,
+	...
+);
+#define PAL_CombinePath(i, d, f) UTIL_CombinePath(UTIL_GlobalBuffer(i), PAL_GLOBAL_BUFFER_SIZE, 2, (d), (f))
 
 /*
  * Platform-specific utilities

+ 5 - 5
video.c

@@ -779,26 +779,26 @@ VIDEO_SaveScreenshot(
 
 --*/
 {
-	char filename[1024];
+	char filename[32];
 #ifdef _WIN32
 	SYSTEMTIME st;
 	GetLocalTime(&st);
-	sprintf(filename, "%s/%04d%02d%02d%02d%02d%02d%03d.bmp", gConfig.pszSavePath, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
+	sprintf(filename, "%04d%02d%02d%02d%02d%02d%03d.bmp", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
 #else
 	struct timeval tv;
 	struct tm *ptm;
 	gettimeofday(&tv, NULL);
 	ptm = localtime(&tv.tv_sec);
-	sprintf(filename, "%s/%04d%02d%02d%02d%02d%02d%03d.bmp", gConfig.pszSavePath, ptm->tm_year + 1900, ptm->tm_mon, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (int)(tv.tv_usec / 1000));
+	sprintf(filename, "%04d%02d%02d%02d%02d%02d%03d.bmp", ptm->tm_year + 1900, ptm->tm_mon, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (int)(tv.tv_usec / 1000));
 #endif
 	
 	//
 	// Save the screenshot.
 	//
 #if SDL_VERSION_ATLEAST(2,0,0)
-	SDL_SaveBMP(gpScreen, filename);
+	SDL_SaveBMP(gpScreen, PAL_CombinePath(0, gConfig.pszSavePath, filename));
 #else
-	SDL_SaveBMP(gpScreenReal, filename);
+	SDL_SaveBMP(gpScreenReal, PAL_CombinePath(0, gConfig.pszSavePath, filename));
 #endif
 }