shithub: choc

Download patch

ref: 0e7e7ba3b64e6bccfcca85d4120f2f60f1fe05c3
parent: 808f6fd842f581f31aa0d91617a759af46fdc732
author: James Haley <[email protected]>
date: Thu Feb 10 15:45:00 EST 2011

Restarted work on hub save code. Brought in multiple filepath handling
routines from Eternity.

Subversion-branch: /branches/strife-branch
Subversion-revision: 2252

--- a/src/strife/d_main.c
+++ b/src/strife/d_main.c
@@ -58,6 +58,7 @@
 #include "m_controls.h"
 #include "m_misc.h"
 #include "m_menu.h"
+#include "m_saves.h" // haleyjd [STRIFE]
 #include "p_saveg.h"
 
 #include "i_endoom.h"
@@ -80,7 +81,6 @@
 #include "p_setup.h"
 #include "r_local.h"
 
-
 #include "d_main.h"
 
 //
@@ -793,54 +793,7 @@
     return gamename;
 }
 
-// 
-// haleyjd: STRIFE-FIXME: Temporary?
-// Code borrowed from Eternity, and modified to return separator char
 //
-char M_GetFilePath(const char *fn, char *dest, size_t len)
-{
-   boolean found_slash = false;
-   char *p;
-   char sepchar = '\0';
-
-   memset(dest, 0, len);
-
-   p = dest + len - 1;
-
-   strncpy(dest, fn, len);
-   
-   while(p >= dest)
-   {
-      if(*p == '/' || *p == '\\')
-      {
-         sepchar = *p;
-         found_slash = true; // mark that the path ended with a slash
-         *p = '\0';
-         break;
-      }
-      *p = '\0';
-      p--;
-   }
-
-   // haleyjd: in the case that no slash was ever found, yet the
-   // path string is empty, we are dealing with a file local to the
-   // working directory. The proper path to return for such a string is
-   // not "", but ".", since the format strings add a slash now. When
-   // the string is empty but a slash WAS found, we really do want to
-   // return the empty string, since the path is relative to the root.
-   if(!found_slash && *dest == '\0')
-      *dest = '.';
-
-   // if a separator is not found, default to forward, because Windows 
-   // supports that too.
-   if(sepchar == '\0') 
-       sepchar = '/';
-
-   return sepchar;
-}
-
-
-//
 // Find out what version of Doom is playing.
 //
 
@@ -978,6 +931,8 @@
             basefile, DIR_SEPARATOR);
 
     M_MakeDirectory(savegamedir);
+
+    // haleyjd 20110210: Create Strife hub save folders
 }
 
 // Check if the IWAD file is the Chex Quest IWAD.  
--- a/src/strife/doomdef.h
+++ b/src/strife/doomdef.h
@@ -246,8 +246,8 @@
     QF_QUEST1  = (1 << tk_quest1),  // Obtained Beldin's ring
     QF_QUEST2  = (1 << tk_quest2),  // Stole the Chalice
     QF_QUEST3  = (1 << tk_quest3),  // Permission to visit Irale (visited Macil)
-    QF_QUEST4  = (1 << tk_quest4),
-    QF_QUEST5  = (1 << tk_quest5),
+    QF_QUEST4  = (1 << tk_quest4),  // Accepted Gov. Mourel's "messy" chore
+    QF_QUEST5  = (1 << tk_quest5),  // Accepted Gov. Mourel's "bloody" chore
     QF_QUEST6  = (1 << tk_quest6),  // Destroyed the Power Coupling
     QF_QUEST7  = (1 << tk_quest7),  // Killed Blue Acolytes ("Scanning Team")
     QF_QUEST8  = (1 << tk_quest8),
--- a/src/strife/g_game.c
+++ b/src/strife/g_game.c
@@ -23,8 +23,6 @@
 //
 //-----------------------------------------------------------------------------
 
-
-
 #include <string.h>
 #include <stdlib.h>
 #include <math.h>
@@ -41,6 +39,7 @@
 #include "m_controls.h"
 #include "m_misc.h"
 #include "m_menu.h"
+#include "m_saves.h" // STRIFE
 #include "m_random.h"
 #include "i_system.h"
 #include "i_timer.h"
@@ -53,7 +52,6 @@
 #include "hu_stuff.h"
 #include "st_stuff.h"
 #include "am_map.h"
-#include "m_misc.h" // STRIFE
 
 // Needs access to LFB.
 #include "v_video.h"
@@ -117,17 +115,17 @@
 int             timelimit;
 
 boolean         paused; 
-boolean         sendpause;             	// send a pause event next tic 
-boolean         sendsave;             	// send a save event next tic 
+boolean         sendpause;              // send a pause event next tic 
+boolean         sendsave;               // send a save event next tic 
 boolean         usergame;               // ok to save / end game 
  
 boolean         timingdemo;             // if true, exit with report on completion 
 boolean         nodrawers;              // for comparative timing purposes 
-int             starttime;          	// for comparative timing purposes  	 
+int             starttime;              // for comparative timing purposes 
  
 boolean         viewactive; 
  
-boolean         deathmatch;           	// only if started as net death 
+boolean         deathmatch;             // only if started as net death 
 boolean         netgame;                // only true if packets are broadcast 
 boolean         playeringame[MAXPLAYERS]; 
 player_t        players[MAXPLAYERS]; 
@@ -149,15 +147,15 @@
 byte*		demobuffer;
 byte*		demo_p;
 byte*		demoend; 
-boolean         singledemo;            	// quit after playing a demo from cmdline 
+boolean         singledemo;             // quit after playing a demo from cmdline 
  
 boolean         precache = true;        // if true, load all graphics at start 
 
 boolean         testcontrols = false;    // Invoked by setup to test controls
  
-wbstartstruct_t wminfo;               	// parms for world map / intermission 
+wbstartstruct_t wminfo;                 // parms for world map / intermission 
  
-byte		consistancy[MAXPLAYERS][BACKUPTICS]; 
+byte            consistancy[MAXPLAYERS][BACKUPTICS]; 
  
 #define MAXPLMOVE		(forwardmove[1]) 
  
@@ -1341,23 +1339,23 @@
 void G_DeathMatchSpawnPlayer (int playernum) 
 { 
     int             i,j; 
-    int				selections; 
-	 
+    int             selections; 
+
     selections = deathmatch_p - deathmatchstarts; 
     if (selections < 4) 
-	I_Error ("Only %i deathmatch spots, 4 required", selections); 
- 
+        I_Error ("Only %i deathmatch spots, 4 required", selections); 
+
     for (j=0 ; j<20 ; j++) 
     { 
-	i = P_Random() % selections; 
-	if (G_CheckSpot (playernum, &deathmatchstarts[i]) ) 
-	{ 
-	    deathmatchstarts[i].type = playernum+1; 
-	    P_SpawnPlayer (&deathmatchstarts[i]); 
-	    return; 
-	} 
+        i = P_Random() % selections; 
+        if (G_CheckSpot (playernum, &deathmatchstarts[i]) ) 
+        { 
+            deathmatchstarts[i].type = playernum+1; 
+            P_SpawnPlayer (&deathmatchstarts[i]); 
+            return; 
+        } 
     } 
- 
+
     // no good spot, so the player will probably get stuck 
     P_SpawnPlayer (&playerstarts[playernum]); 
 } 
@@ -1819,8 +1817,8 @@
 
     dword_86280 = eax0;
 
-    // STRIFE-TODO: yeah good luck making THIS work on Linux.
-    if(M_CheckParm(DEH_String("-cdrom")))
+#ifdef _WIN32
+    if(M_CheckParm("-cdrom") > 0)
     {
         sprintf(savepath2, "c:\\strife.cd\\strfsav%d.ssg\\", 6);
         v5 = dword_86280;
@@ -1827,6 +1825,7 @@
         dirstr = "c:\\strife.cd\\strfsav%d.ssg\\";
     }
     else
+#endif
     {
         sprintf(savepath2, "strfsav%d.ssg\\", 6);
         v5 = dword_86280;
--- a/src/strife/m_saves.c
+++ b/src/strife/m_saves.c
@@ -37,15 +37,29 @@
 #else
 #error Need an include for dirent.h!
 #endif
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
 
 #include "z_zone.h"
 #include "i_system.h"
 #include "d_player.h"
 #include "deh_str.h"
+#include "doomstat.h"
 #include "m_misc.h"
+#include "m_saves.h"
 #include "p_dialog.h"
 
 //
+// File Paths
+//
+// Strife maintains multiple file paths related to savegames.
+//
+char *savepath;
+char *savepath2;
+char *loadpath;
+
+//
 // ClearTmp
 //
 // Clear the temporary save directory
@@ -52,6 +66,32 @@
 //
 void ClearTmp(void)
 {
+    DIR *sp2dir = NULL;
+    struct dirent *f = NULL;
+
+    if(savepath2 == NULL)
+        I_Error("you fucked up savedir man!");
+
+    if(!(sp2dir = opendir(savepath2)))
+        I_Error("ClearTmp: Couldn't open dir %s", savepath2);
+
+    while((f = readdir(sp2dir)))
+    {
+        char *filepath = NULL;
+
+        // haleyjd: skip "." and ".." without assuming they're the
+        // first two entries like the original code did.
+        if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
+            continue;
+
+        // haleyjd: use M_SafeFilePath, not sprintf
+        filepath = M_SafeFilePath(savepath2, f->d_name);
+        remove(filepath);
+
+        Z_Free(filepath);
+    }
+
+    closedir(sp2dir);
 }
 
 //
@@ -61,16 +101,50 @@
 //
 void ClearSlot(void)
 {
+    if(savepath == NULL)
+        I_Error("userdir is fucked up man!");
+
+    // STRIFE-TODO
 }
 
 //
 // FromCurr
 //
-// Moving files from one directory to another...
-// STRIFE-TODO: figure out exactly what this is for.
+// Copying files from savepath2 to savepath
 //
 void FromCurr(void)
 {
+    DIR *sp2dir = NULL;
+    struct dirent *f = NULL;
+
+    if(!(sp2dir = opendir(savepath2)))
+        I_Error("FromCurr: Couldn't open dir %s", savepath2);
+
+    while((f = readdir(sp2dir)))
+    {
+        byte *filebuffer  = NULL;
+        int   filelen     = 0;
+        char *srcfilename = NULL;
+        char *dstfilename = NULL;
+
+        // haleyjd: skip "." and ".." without assuming they're the
+        // first two entries like the original code did.
+        if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
+            continue;
+
+        // haleyjd: use M_SafeFilePath, NOT sprintf.
+        srcfilename = M_SafeFilePath(savepath2, f->d_name);
+        dstfilename = M_SafeFilePath(savepath,  f->d_name);
+
+        filelen = M_ReadFile(srcfilename, &filebuffer);
+        M_WriteFile(dstfilename, filebuffer, filelen);
+
+        Z_Free(filebuffer);
+        Z_Free(srcfilename);
+        Z_Free(dstfilename);
+    }
+
+    closedir(sp2dir);
 }
 
 //
@@ -80,6 +154,7 @@
 //
 void sub_1B2F4(void)
 {
+    // STRIFE-TODO
 }
 
 //
@@ -89,6 +164,27 @@
 //
 void M_SaveMoveMapToHere(void)
 {
+    char *mapsave  = NULL;
+    char *heresave = NULL;
+    char tmpnum[33];
+
+    // haleyjd: no itoa available...
+    memset(tmpnum, 0, sizeof(tmpnum));
+    sprintf(tmpnum, "%d", gamemap);
+
+    // haleyjd: use M_SafeFilePath, not sprintf
+    mapsave  = M_SafeFilePath(savepath, tmpnum);
+    heresave = M_SafeFilePath(savepath, "here");
+
+    // haleyjd: use M_FileExists, not access
+    if(M_FileExists(mapsave))
+    {
+        remove(heresave);
+        rename(mapsave, heresave);
+    }
+
+    Z_Free(mapsave);
+    Z_Free(heresave);
 }
 
 //
@@ -98,6 +194,25 @@
 //
 void M_SaveMoveHereToMap(void)
 {
+    char *mapsave  = NULL;
+    char *heresave = NULL;
+    char tmpnum[33];
+
+    // haleyjd: no itoa available...
+    memset(tmpnum, 0, sizeof(tmpnum));
+    sprintf(tmpnum, "%d", gamemap);
+
+    mapsave  = M_SafeFilePath(savepath2, tmpnum);
+    heresave = M_SafeFilePath(savepath2, "here");
+
+    if(M_FileExists(heresave))
+    {
+        remove(mapsave);
+        rename(heresave, mapsave);
+    }
+
+    Z_Free(mapsave);
+    Z_Free(heresave);
 }
 
 //
@@ -107,10 +222,15 @@
 //
 boolean M_SaveMisObj(const char *path)
 {
-    char destpath[100]; // WARNING: not large enough for modern file paths!
+    boolean result;
+    char *destpath = NULL;
 
-    DEH_snprintf(destpath, sizeof(destpath), "%smis_obj", path);
-    return M_WriteFile(destpath, mission_objective, OBJECTIVE_LEN);
+    // haleyjd 20110210: use M_SafeFilePath, not sprintf
+    destpath = M_SafeFilePath(path, "mis_obj");
+    result   = M_WriteFile(destpath, mission_objective, OBJECTIVE_LEN);
+
+    Z_Free(destpath);
+    return result;
 }
 
 //
@@ -120,6 +240,199 @@
 //
 void M_ReadMisObj(void)
 {
+    FILE *f = NULL;
+    char *srcpath = NULL;
+
+    // haleyjd: use M_SafeFilePath, not sprintf
+    srcpath = M_SafeFilePath(savepath2, "mis_obj");
+
+    if((f = fopen(srcpath, "rb")))
+    {
+        fread(mission_objective, 1, 300, f);
+        fclose(f);
+    }
+
+    Z_Free(srcpath);
+}
+
+//=============================================================================
+//
+// Original Routines
+//
+// haleyjd - None of the below code is derived from Strife itself, but has been
+// adapted or created in order to provide secure, portable filepath handling
+// for the purposes of savegame support. This is partially needed to allow for
+// differences in Choco due to it being multiplatform. The rest exists because
+// I cannot stand programming in an impoverished ANSI C environment that
+// calls sprintf on fixed-size buffers. :P
+//
+
+//
+// M_Calloc
+//
+// haleyjd 20110210 - original routine
+// Because Choco doesn't have Z_Calloc O_o
+//
+void *M_Calloc(size_t n1, size_t n2)
+{
+    return (n1 *= n2) ? memset(Z_Malloc(n1, PU_STATIC, NULL), 0, n1) : NULL;
+}
+
+//
+// M_StringAlloc
+//
+// haleyjd: This routine takes any number of strings and a number of extra
+// characters, calculates their combined length, and calls Z_Alloca to create
+// a temporary buffer of that size. This is extremely useful for allocation of
+// file paths, and is used extensively in d_main.c.  The pointer returned is
+// to a temporary Z_Alloca buffer, which lives until the next main loop
+// iteration, so don't cache it. Note that this idiom is not possible with the
+// normal non-standard alloca function, which allocates stack space.
+//
+// [STRIFE] - haleyjd 20110210
+// This routine is taken from the Eternity Engine and adapted to do without
+// Z_Alloca. I need secure string concatenation for filepath handling. The
+// only difference from use in EE is that the pointer returned in *str must
+// be manually freed.
+//
+int M_StringAlloc(char **str, int numstrs, size_t extra, const char *str1, ...)
+{
+    va_list args;
+    size_t len = extra;
+
+    if(numstrs < 1)
+        I_Error("M_StringAlloc: invalid input\n");
+
+    len += strlen(str1);
+
+    --numstrs;
+
+    if(numstrs != 0)
+    {   
+        va_start(args, str1);
+
+        while(numstrs != 0)
+        {
+            const char *argstr = va_arg(args, const char *);
+
+            len += strlen(argstr);
+
+            --numstrs;
+        }
+
+        va_end(args);
+    }
+
+    ++len;
+
+    *str = (char *)(M_Calloc(1, len));
+
+    return len;
+}
+
+//
+// M_NormalizeSlashes
+//
+// Remove trailing slashes, translate backslashes to slashes
+// The string to normalize is passed and returned in str
+//
+// killough 11/98: rewritten
+//
+// [STRIFE] - haleyjd 20110210: Borrowed from Eternity and adapted to respect 
+// the DIR_SEPARATOR define used by Choco Doom. This routine originated in
+// BOOM.
+//
+void M_NormalizeSlashes(char *str)
+{
+    char *p;
+   
+    // Convert all slashes/backslashes to DIR_SEPARATOR
+    for(p = str; *p; p++)
+    {
+        if((*p == '/' || *p == '\\') && *p != DIR_SEPARATOR)
+            *p = DIR_SEPARATOR;
+    }
+
+    // Remove trailing slashes
+    while(p > str && *--p == DIR_SEPARATOR)
+        *p = 0;
+
+    // Collapse multiple slashes
+    for(p = str; (*str++ = *p); )
+        if(*p++ == DIR_SEPARATOR)
+            while(*p == DIR_SEPARATOR)
+                p++;
+}
+
+//
+// M_SafeFilePath
+//
+// haleyjd 20110210 - original routine.
+// This routine performs safe, portable concatenation of a base file path
+// with another path component or file name. The returned string is Z_Malloc'd
+// and should be freed when it has exhausted its usefulness.
+//
+char *M_SafeFilePath(const char *basepath, const char *newcomponent)
+{
+    int   newstrlen = 0;
+    char *newstr = NULL;
+
+    // Always throw in a slash. M_NormalizeSlashes will remove it in the case
+    // that either basepath or newcomponent includes a redundant slash at the
+    // end or beginning respectively.
+    newstrlen = M_StringAlloc(&newstr, 3, 1, basepath, "/", newcomponent);
+    snprintf(newstr, newstrlen, "%s/%s", basepath, newcomponent);
+    M_NormalizeSlashes(newstr);
+
+    return newstr;
+}
+
+// 
+// M_GetFilePath
+//
+// haleyjd: STRIFE-FIXME: Temporary?
+// Code borrowed from Eternity, and modified to return separator char
+//
+char M_GetFilePath(const char *fn, char *dest, size_t len)
+{
+    boolean found_slash = false;
+    char *p;
+    char sepchar = '\0';
+
+    memset(dest, 0, len);
+
+    p = dest + len - 1;
+
+    strncpy(dest, fn, len);
+
+    while(p >= dest)
+    {
+        if(*p == '/' || *p == '\\')
+        {
+            sepchar = *p;
+            found_slash = true; // mark that the path ended with a slash
+            *p = '\0';
+            break;
+        }
+        *p = '\0';
+        p--;
+    }
+
+    // haleyjd: in the case that no slash was ever found, yet the
+    // path string is empty, we are dealing with a file local to the
+    // working directory. The proper path to return for such a string is
+    // not "", but ".", since the format strings add a slash now. When
+    // the string is empty but a slash WAS found, we really do want to
+    // return the empty string, since the path is relative to the root.
+    if(!found_slash && *dest == '\0')
+        *dest = '.';
+
+    // if a separator is not found, default to forward, because Windows 
+    // supports that too.
+    if(sepchar == '\0') 
+        sepchar = '/';
+
+    return sepchar;
 }
 
 // EOF
--- a/src/strife/m_saves.h
+++ b/src/strife/m_saves.h
@@ -31,7 +31,15 @@
 #ifndef M_SAVES_H__
 #define M_SAVES_H__
 
+// Strife Savegame Functions
 boolean M_SaveMisObj(const char *path);
+
+// Custom Utilities for Filepath Handling
+void *M_Calloc(size_t n1, size_t n2);
+void  M_NormalizeSlashes(char *str);
+int   M_StringAlloc(char **str, int numstrs, size_t extra, const char *str1, ...);
+char *M_SafeFilePath(const char *basepath, const char *newcomponent);
+char  M_GetFilePath(const char *fn, char *dest, size_t len);
 
 #endif
 
--- a/src/strife/p_enemy.c
+++ b/src/strife/p_enemy.c
@@ -315,7 +315,7 @@
                            actor->y-actor->target->y) - 64*FRACUNIT;
     
     if (!actor->info->meleestate)
-        dist -= 128*FRACUNIT;	// no melee attack, so fire more
+        dist -= 128*FRACUNIT;       // no melee attack, so fire more
 
     dist >>= 16;
 
@@ -669,7 +669,7 @@
         dir = DI_SOUTHEAST;
         while(1)
         {
-            // haleyjd 09/05/10: P_TryWalk -> P_Move, missing random code.
+            // haleyjd 09/05/10: missing random code.
             if(dir != opposite[actor->movedir])
             {
                 actor->movedir = dir;
--- a/src/strife/s_sound.c
+++ b/src/strife/s_sound.c
@@ -538,7 +538,8 @@
       ++c;
    }
 
-   return h;}
+   return h;
+}
 
 static voiceinfo_t *voices[NUMVOICECHAINS];
 
@@ -618,7 +619,6 @@
     // Because of constness problems...
     strncpy(lumpnamedup, lumpname, 9);
     lumpnamedup[8] = '\0';
-
 
     if((lumpnum = W_CheckNumForName(lumpnamedup)) != -1)
     {