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);
}
}