shithub: choc

Download patch

ref: 62b5c602821cee8ac703ebe6362f3e1fc6d9ad3c
parent: e85edb9e6fcdc77d69d1b4d9f14f705a03e753e1
author: Simon Howard <fraggle@gmail.com>
date: Sat Mar 29 16:08:31 EDT 2014

misc: Add string utility functions.

It's more readable to write "M_StringEndsWith(..." than doing a bunch of
pointer arithmetic, and this is a common pattern. Also add
M_StringStartsWith, M_StringJoin and M_StringCopy. The latter is a
safe alternative for strcpy() that works the same as OpenBSD's
strlcpy(). Use these functions in a few places where it makes sense.

--- a/src/d_iwad.c
+++ b/src/d_iwad.c
@@ -423,7 +423,7 @@
 
     // As a special case, the "directory" may refer directly to an
     // IWAD file if the path comes from DOOMWADDIR or DOOMWADPATH.
-    
+
     if (DirIsFile(dir, iwadname) && M_FileExists(dir))
     {
         return strdup(dir);
@@ -432,15 +432,14 @@
     // Construct the full path to the IWAD if it is located in
     // this directory, and check if it exists.
 
-    filename = malloc(strlen(dir) + strlen(iwadname) + 3);
-
     if (!strcmp(dir, "."))
     {
-        strcpy(filename, iwadname);
+        filename = strdup(iwadname);
     }
     else
     {
-        sprintf(filename, "%s%c%s", dir, DIR_SEPARATOR, iwadname);
+        char sep[] = {DIR_SEPARATOR, '\0'};
+        filename = M_StringJoin(dir, sep, iwadname);
     }
 
     if (M_FileExists(filename))
--- a/src/doom/d_main.c
+++ b/src/doom/d_main.c
@@ -1352,19 +1352,19 @@
 
     if (p)
     {
-        if (!strcasecmp(myargv[p+1] + strlen(myargv[p+1]) - 4, ".lmp"))
+        if (M_StringEndsWith(myargv[p + 1], ".lmp"))
         {
-            strcpy(file, myargv[p + 1]);
+            M_StringCopy(file, myargv[p + 1], sizeof(file));
         }
         else
         {
-	    sprintf (file,"%s.lmp", myargv[p+1]);
+            snprintf(file, sizeof(file), "%s.lmp", myargv[p+1]);
         }
 
-	if (D_AddFile (file))
+        if (D_AddFile(file))
         {
-            strncpy(demolumpname, lumpinfo[numlumps - 1].name, 8);
-            demolumpname[8] = '\0';
+            M_StringCopy(demolumpname, lumpinfo[numlumps - 1].name,
+                         sizeof(demolumpname));
 
             printf("Playing demo %s.\n", file);
         }
@@ -1374,10 +1374,8 @@
             // the demo in the same way as Vanilla Doom.  This makes
             // tricks like "-playdemo demo1" possible.
 
-            strncpy(demolumpname, myargv[p + 1], 8);
-            demolumpname[8] = '\0';
+            M_StringCopy(demolumpname, myargv[p + 1], sizeof(demolumpname));
         }
-
     }
 
     I_AtExit((atexit_func_t) G_CheckDemoStatus, true);
@@ -1686,8 +1684,8 @@
 	
     if (startloadgame >= 0)
     {
-        strcpy(file, P_SaveGameFile(startloadgame));
-	G_LoadGame (file);
+        M_StringCopy(file, P_SaveGameFile(startloadgame), sizeof(file));
+	G_LoadGame(file);
     }
 	
     if (gameaction != ga_loadgame )
--- a/src/i_pcsound.c
+++ b/src/i_pcsound.c
@@ -30,7 +30,7 @@
 
 #include "deh_str.h"
 #include "i_sound.h"
-
+#include "m_misc.h"
 #include "w_wad.h"
 #include "z_zone.h"
 
@@ -253,11 +253,11 @@
 
     if (use_sfx_prefix)
     {
-        sprintf(namebuf, "dp%s", DEH_String(sfx->name));
+        snprintf(namebuf, sizeof(namebuf), "dp%s", DEH_String(sfx->name));
     }
     else
     {
-        strcpy(namebuf, DEH_String(sfx->name));
+        M_StringCopy(namebuf, DEH_String(sfx->name), sizeof(namebuf));
     }
 
     return W_GetNumForName(namebuf);
--- a/src/i_sdlsound.c
+++ b/src/i_sdlsound.c
@@ -43,6 +43,7 @@
 #include "i_system.h"
 #include "i_swap.h"
 #include "m_argv.h"
+#include "m_misc.h"
 #include "w_wad.h"
 #include "z_zone.h"
 
@@ -717,7 +718,7 @@
     return true;
 }
 
-static void GetSfxLumpName(sfxinfo_t *sfx, char *buf)
+static void GetSfxLumpName(sfxinfo_t *sfx, char *buf, size_t buf_len)
 {
     // Linked sfx lumps? Get the lump number for the sound linked to.
 
@@ -731,11 +732,11 @@
 
     if (use_sfx_prefix)
     {
-        sprintf(buf, "ds%s", DEH_String(sfx->name));
+        snprintf(buf, buf_len, "ds%s", DEH_String(sfx->name));
     }
     else
     {
-        strcpy(buf, DEH_String(sfx->name));
+        M_StringCopy(buf, DEH_String(sfx->name), buf_len);
     }
 }
 
@@ -765,7 +766,7 @@
             fflush(stdout);
         }
 
-        GetSfxLumpName(&sounds[i], namebuf);
+        GetSfxLumpName(&sounds[i], namebuf, sizeof(buf));
 
         sounds[i].lumpnum = W_CheckNumForName(namebuf);
 
@@ -815,7 +816,7 @@
 {
     char namebuf[9];
 
-    GetSfxLumpName(sfx, namebuf);
+    GetSfxLumpName(sfx, namebuf, sizeof(namebuf));
 
     return W_GetNumForName(namebuf);
 }
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -298,21 +298,23 @@
 
 //
 // String replace function.
-// Returns a Z_Malloc()ed string.
 //
 
 char *M_StringReplace(char *haystack, char *needle, char *replacement)
 {
-    char *result, *p, *dst;
+    char *result, *p;
+    char *dst;
     size_t needle_len = strlen(needle);
-    int n;
+    size_t result_len, dst_len;
 
-    // Count number of occurrences of 'p':
+    // Iterate through occurrences of 'needle' and calculate the size of
+    // the new string.
+    result_len = strlen(haystack) + 1;
+    p = haystack;
 
-    for (p = haystack, n = 0;; ++n)
+    for (;;)
     {
         p = strstr(p, needle);
-
         if (p == NULL)
         {
             break;
@@ -319,16 +321,19 @@
         }
 
         p += needle_len;
+        result_len += strlen(replacement) - needle_len;
     }
 
     // Construct new string.
 
-    result = Z_Malloc(strlen(haystack)
-                      + (strlen(replacement) - needle_len) * n
-                      + 1,
-                      PU_STATIC, NULL);
+    result = malloc(result_len);
+    if (result == NULL)
+    {
+        I_Error("M_StringReplace: Failed to allocate new string");
+        return NULL;
+    }
 
-    dst = result;
+    dst = result; dst_len = result_len;
     p = haystack;
 
     while (*p != '\0')
@@ -335,18 +340,94 @@
     {
         if (!strncmp(p, needle, needle_len))
         {
-            strcpy(dst, replacement);
-            dst += strlen(replacement);
+            M_StringCopy(dst, replacement, dst_len);
             p += needle_len;
+            dst += strlen(replacement);
+            dst_len -= strlen(replacement);
         }
         else
         {
             *dst = *p;
-            ++dst;
+            ++dst; --dst_len;
             ++p;
         }
     }
-    *dst = '\0';
+
+    return result;
+}
+
+// Safe string copy function that works like OpenBSD's strlcpy().
+// Returns true if the string was not truncated.
+
+boolean M_StringCopy(char *dest, char *src, size_t dest_size)
+{
+    strncpy(dest, src, dest_size);
+    dest[dest_size - 1] = '\0';
+    return strlen(dest) == strlen(src);
+}
+
+// Returns true if 's' begins with the specified prefix.
+
+boolean M_StringStartsWith(char *s, char *prefix)
+{
+    return strlen(s) > strlen(prefix)
+        && strncmp(s, prefix, strlen(prefix)) == 0;
+}
+
+// Returns true if 's' ends with the specified suffix.
+
+boolean M_StringEndsWith(char *s, char *suffix)
+{
+    return strlen(s) >= strlen(suffix)
+        && strcmp(s + strlen(s) - strlen(suffix), suffix) == 0;
+}
+
+// Return a newly-malloced string with all the strings given as arguments
+// concatenated together.
+
+char *M_StringJoin(char *s, ...)
+{
+    char *result, *v;
+    va_list args;
+    size_t result_len;
+
+    result_len = strlen(s) + 1;
+
+    va_start(args, s);
+    for (;;)
+    {
+        v = va_arg(args, char *);
+        if (v == NULL)
+        {
+            break;
+        }
+
+        result_len += strlen(v);
+    }
+    va_end(args);
+
+    result = malloc(result_len);
+
+    if (result == NULL)
+    {
+        I_Error("M_StringJoin: Failed to allocate new string.");
+        return NULL;
+    }
+
+    M_StringCopy(result, s, result_len);
+
+    va_start(args, s);
+    for (;;)
+    {
+        v = va_arg(args, char *);
+        if (v == NULL)
+        {
+            break;
+        }
+
+        strncat(result, v, result_len);
+    }
+    va_end(args);
 
     return result;
 }
--- a/src/m_misc.h
+++ b/src/m_misc.h
@@ -43,7 +43,11 @@
 void M_ExtractFileBase(char *path, char *dest);
 void M_ForceUppercase(char *text);
 char *M_StrCaseStr(char *haystack, char *needle);
+boolean M_StringCopy(char *dest, char *src, size_t dest_size);
 char *M_StringReplace(char *haystack, char *needle, char *replacement);
+char *M_StringJoin(char *s, ...);
+boolean M_StringStartsWith(char *s, char *prefix);
+boolean M_StringEndsWith(char *s, char *suffix);
 char *M_OEMToUTF8(const char *ansi);
 
 #endif
--- a/src/net_packet.c
+++ b/src/net_packet.c
@@ -24,6 +24,7 @@
 //-----------------------------------------------------------------------------
 
 #include <string.h>
+#include "m_misc.h"
 #include "net_packet.h"
 #include "z_zone.h"
 
@@ -280,10 +281,13 @@
 void NET_WriteString(net_packet_t *packet, char *string)
 {
     byte *p;
+    size_t string_size;
 
+    string_size = strlen(string) + 1;
+
     // Increase the packet size until large enough to hold the string
 
-    while (packet->len + strlen(string) + 1 > packet->alloced)
+    while (packet->len + string_size > packet->alloced)
     {
         NET_IncreasePacket(packet);
     }
@@ -290,9 +294,9 @@
 
     p = packet->data + packet->len;
 
-    strcpy((char *) p, string);
+    M_StringCopy((char *) p, string, string_size);
 
-    packet->len += strlen(string) + 1;
+    packet->len += string_size;
 }
 
 
--- a/src/net_structrw.c
+++ b/src/net_structrw.c
@@ -27,7 +27,7 @@
 #include <ctype.h>
 
 #include "doomtype.h"
-
+#include "m_misc.h"
 #include "net_packet.h"
 #include "net_structrw.h"
 
@@ -493,7 +493,7 @@
             return false;
         }
 
-        strcpy(data->player_names[i], s);
+        M_StringCopy(data->player_names[i], s, MAXPLAYERNAME);
 
         s = NET_ReadString(packet);
 
@@ -502,7 +502,7 @@
             return false;
         }
 
-        strcpy(data->player_addrs[i], s);
+        M_StringCopy(data->player_addrs[i], s, MAXPLAYERNAME);
     }
 
     return NET_ReadSHA1Sum(packet, data->wad_sha1sum)
--- a/src/setup/mainmenu.c
+++ b/src/setup/mainmenu.c
@@ -329,7 +329,7 @@
 
     TXT_SetDesktopTitle(title);
 
-    Z_Free(title);
+    free(title);
 }
 
 // Initialize the textscreen library.
--- a/src/w_merge.c
+++ b/src/w_merge.c
@@ -33,6 +33,7 @@
 
 #include "doomtype.h"
 #include "i_system.h"
+#include "m_misc.h"
 #include "w_merge.h"
 #include "w_wad.h"
 #include "z_zone.h"
@@ -718,7 +719,7 @@
             // Replace this entry with an empty string.  This is what
             // nwt -merge does.
 
-            strcpy(iwad_sprites.lumps[i].name, "");
+            M_StringCopy(iwad_sprites.lumps[i].name, "", 8);
         }
     }