ref: 4767ddccafca1a1c50bc097284df1328d478882a
parent: af48a6309cf1f03b5136e26a5fc27a38e490d808
parent: aa35a71bd05536f82ce23887f7e84decc7f850a7
author: Simon Howard <fraggle@gmail.com>
date: Mon May 3 13:07:45 EDT 2010
Merge from trunk. Subversion-branch: /branches/raven-branch Subversion-revision: 1931
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,27 @@
+1.4.0 (2010-??-??):
+
+ The biggest change in this version is the addition of OPL
+ emulation. This emulates Vanilla Doom's MIDI playback when
+ using a Yamaha OPL synthesizer chip, as was found on
+ SoundBlaster compatible cards.
+
+ A software OPL emulator is included as most modern computers do
+ not have a hardware OPL chip any more. If you do have one, you
+ can configure Chocolate Doom to use it; see README.OPL.
+
+ The OPL playback feature is not yet perfect or 100% complete,
+ but is judged to be good enough for general use. If you find
+ music that does not play back properly, please report it as a
+ bug.
+
+ Other changes:
+ * The REJECT overflow emulation code from PrBoom+ has been
+ imported. This fixes demo desync on some demos, although
+ others will still desync.
+ * Warnings are now generated for invalid dehacked replacements of
+ printf format strings. Some potential buffer overflows are
+ also checked.
+
1.3.0 (2010-02-10):
* Chocolate Doom now runs on Windows Mobile/Windows CE!
--- a/src/deh_str.c
+++ b/src/deh_str.c
@@ -27,6 +27,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdarg.h>
#include "doomtype.h"
#include "deh_str.h"
@@ -177,5 +178,231 @@
sub->to_text = to_text;
DEH_AddToHashtable(sub);
+}
+
+typedef enum
+{
+ FORMAT_ARG_INVALID,
+ FORMAT_ARG_INT,
+ FORMAT_ARG_FLOAT,
+ FORMAT_ARG_CHAR,
+ FORMAT_ARG_STRING,
+ FORMAT_ARG_PTR,
+ FORMAT_ARG_SAVE_POS
+} format_arg_t;
+
+// Get the type of a format argument.
+// We can mix-and-match different format arguments as long as they
+// are for the same data type.
+
+static format_arg_t FormatArgumentType(char c)
+{
+ switch (c)
+ {
+ case 'd': case 'i': case 'o': case 'u': case 'x': case 'X':
+ return FORMAT_ARG_INT;
+
+ case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
+ case 'a': case 'A':
+ return FORMAT_ARG_FLOAT;
+
+ case 'c': case 'C':
+ return FORMAT_ARG_CHAR;
+
+ case 's': case 'S':
+ return FORMAT_ARG_STRING;
+
+ case 'p':
+ return FORMAT_ARG_PTR;
+
+ case 'n':
+ return FORMAT_ARG_SAVE_POS;
+
+ default:
+ return FORMAT_ARG_INVALID;
+ }
+}
+
+// Given the specified string, get the type of the first format
+// string encountered.
+
+static format_arg_t NextFormatArgument(char **str)
+{
+ format_arg_t argtype;
+
+ // Search for the '%' starting the next string.
+
+ while (**str != '\0')
+ {
+ if (**str == '%')
+ {
+ ++*str;
+
+ // Don't stop for double-%s.
+
+ if (**str != '%')
+ {
+ break;
+ }
+ }
+
+ ++*str;
+ }
+
+ // Find the type of the format string.
+
+ while (**str != '\0')
+ {
+ argtype = FormatArgumentType(**str);
+
+ if (argtype != FORMAT_ARG_INVALID)
+ {
+ ++*str;
+
+ return argtype;
+ }
+
+ ++*str;
+ }
+
+ // Stop searching, we have reached the end.
+
+ *str = NULL;
+
+ return FORMAT_ARG_INVALID;
+}
+
+// Check if the specified argument type is a valid replacement for
+// the original.
+
+static boolean ValidArgumentReplacement(format_arg_t original,
+ format_arg_t replacement)
+{
+ // In general, the original and replacement types should be
+ // identical. However, there are some cases where the replacement
+ // is valid and the types don't match.
+
+ // Characters can be represented as ints.
+
+ if (original == FORMAT_ARG_CHAR && replacement == FORMAT_ARG_INT)
+ {
+ return true;
+ }
+
+ // Strings are pointers.
+
+ if (original == FORMAT_ARG_STRING && replacement == FORMAT_ARG_PTR)
+ {
+ return true;
+ }
+
+ return original == replacement;
+}
+
+// Return true if the specified string contains no format arguments.
+
+static boolean ValidFormatReplacement(char *original, char *replacement)
+{
+ char *rover1;
+ char *rover2;
+ int argtype1, argtype2;
+
+ // Check each argument in turn and compare types.
+
+ rover1 = original; rover2 = replacement;
+
+ for (;;)
+ {
+ argtype1 = NextFormatArgument(&rover1);
+ argtype2 = NextFormatArgument(&rover2);
+
+ if (argtype2 == FORMAT_ARG_INVALID)
+ {
+ // No more arguments left to read from the replacement string.
+
+ break;
+ }
+ else if (argtype1 == FORMAT_ARG_INVALID)
+ {
+ // Replacement string has more arguments than the original.
+
+ return false;
+ }
+ else if (!ValidArgumentReplacement(argtype1, argtype2))
+ {
+ // Not a valid replacement argument.
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Get replacement format string, checking arguments.
+
+static char *FormatStringReplacement(char *s)
+{
+ char *repl;
+
+ repl = DEH_String(s);
+
+ if (!ValidFormatReplacement(s, repl))
+ {
+ printf("WARNING: Unsafe dehacked replacement provided for "
+ "printf format string: %s\n", s);
+
+ return s;
+ }
+
+ return repl;
+}
+
+// printf(), performing a replacement on the format string.
+
+void DEH_printf(char *fmt, ...)
+{
+ va_list args;
+ char *repl;
+
+ repl = FormatStringReplacement(fmt);
+
+ va_start(args, fmt);
+
+ vprintf(repl, args);
+
+ va_end(args);
+}
+
+// fprintf(), performing a replacement on the format string.
+
+void DEH_fprintf(FILE *fstream, char *fmt, ...)
+{
+ va_list args;
+ char *repl;
+
+ repl = FormatStringReplacement(fmt);
+
+ va_start(args, fmt);
+
+ vfprintf(fstream, repl, args);
+
+ va_end(args);
+}
+
+// snprintf(), performing a replacement on the format string.
+
+void DEH_snprintf(char *buffer, size_t len, char *fmt, ...)
+{
+ va_list args;
+ char *repl;
+
+ repl = FormatStringReplacement(fmt);
+
+ va_start(args, fmt);
+
+ vsnprintf(buffer, len, repl, args);
+
+ va_end(args);
}
--- a/src/deh_str.h
+++ b/src/deh_str.h
@@ -27,6 +27,8 @@
#ifndef DEH_STR_H
#define DEH_STR_H
+#include <stdio.h>
+
#include "doomfeatures.h"
// Used to do dehacked text substitutions throughout the program
@@ -34,11 +36,18 @@
#ifdef FEATURE_DEHACKED
char *DEH_String(char *s);
+void DEH_printf(char *fmt, ...);
+void DEH_fprintf(FILE *fstream, char *fmt, ...);
+void DEH_snprintf(char *buffer, size_t len, char *fmt, ...);
void DEH_AddStringReplacement(char *from_text, char *to_text);
+
#else
#define DEH_String(x) (x)
+#define DEH_printf printf
+#define DEH_fprintf fprintf
+#define DEH_snprintf snprintf
#endif
--- a/src/doom/am_map.c
+++ b/src/doom/am_map.c
@@ -500,7 +500,7 @@
for (i=0;i<10;i++)
{
- sprintf(namebuf, DEH_String("AMMNUM%d"), i);
+ DEH_snprintf(namebuf, 9, "AMMNUM%d", i);
marknums[i] = W_CacheLumpName(namebuf, PU_STATIC);
}
@@ -513,7 +513,7 @@
for (i=0;i<10;i++)
{
- sprintf(namebuf, DEH_String("AMMNUM%d"), i);
+ DEH_snprintf(namebuf, 9, "AMMNUM%d", i);
W_ReleaseLumpName(namebuf);
}
}
@@ -1020,7 +1020,7 @@
|| fl->b.x < 0 || fl->b.x >= f_w
|| fl->b.y < 0 || fl->b.y >= f_h)
{
- fprintf(stderr, DEH_String("fuck %d \r"), fuck++);
+ DEH_fprintf(stderr, "fuck %d \r", fuck++);
return;
}
--- a/src/doom/d_main.c
+++ b/src/doom/d_main.c
@@ -1068,7 +1068,7 @@
I_PrintBanner(PACKAGE_STRING);
- printf (DEH_String("Z_Init: Init zone memory allocation daemon. \n"));
+ DEH_printf("Z_Init: Init zone memory allocation daemon. \n");
Z_Init ();
#ifdef FEATURE_MULTIPLAYER
@@ -1187,7 +1187,7 @@
deathmatch = 2;
if (devparm)
- printf(DEH_String(D_DEVSTR));
+ DEH_printf(D_DEVSTR);
// find which dir to use for config files
@@ -1235,7 +1235,7 @@
scale = 10;
if (scale > 400)
scale = 400;
- printf (DEH_String("turbo scale: %i%%\n"),scale);
+ DEH_printf("turbo scale: %i%%\n", scale);
forwardmove[0] = forwardmove[0]*scale/100;
forwardmove[1] = forwardmove[1]*scale/100;
sidemove[0] = sidemove[0]*scale/100;
@@ -1243,11 +1243,11 @@
}
// init subsystems
- printf(DEH_String("V_Init: allocate screens.\n"));
- V_Init();
+ DEH_printf("V_Init: allocate screens.\n");
+ V_Init ();
// Load configuration files before initialising other subsystems.
- printf(DEH_String("M_LoadDefaults: Load system defaults.\n"));
+ DEH_printf("M_LoadDefaults: Load system defaults.\n");
M_SetConfigFilenames("default.cfg", PROGRAM_PREFIX "doom.cfg");
D_BindVariables();
M_LoadDefaults();
@@ -1255,7 +1255,7 @@
// Save configuration at exit.
I_AtExit(M_SaveDefaults, false);
- printf (DEH_String("W_Init: Init WADfiles.\n"));
+ DEH_printf("W_Init: Init WADfiles.\n");
D_AddFile(iwadfile);
modifiedgame = W_ParseCommandLine();
@@ -1451,8 +1451,8 @@
if (p && p < myargc-1 && deathmatch)
{
- printf(DEH_String("Austin Virtual Gaming: Levels will end "
- "after 20 minutes\n"));
+ DEH_printf("Austin Virtual Gaming: Levels will end "
+ "after 20 minutes\n");
timelimit = 20;
}
@@ -1534,16 +1534,16 @@
I_PrintStartupBanner(gamedescription);
PrintDehackedBanners();
- printf (DEH_String("M_Init: Init miscellaneous info.\n"));
+ DEH_printf("M_Init: Init miscellaneous info.\n");
M_Init ();
- printf (DEH_String("R_Init: Init DOOM refresh daemon - "));
+ DEH_printf("R_Init: Init DOOM refresh daemon - ");
R_Init ();
- printf (DEH_String("\nP_Init: Init Playloop state.\n"));
+ DEH_printf("\nP_Init: Init Playloop state.\n");
P_Init ();
- printf (DEH_String("I_Init: Setting up machine state.\n"));
+ DEH_printf("I_Init: Setting up machine state.\n");
I_CheckIsScreensaver();
I_InitTimer();
I_InitJoystick();
@@ -1553,18 +1553,18 @@
NET_Init ();
#endif
- printf (DEH_String("S_Init: Setting up sound.\n"));
+ DEH_printf("S_Init: Setting up sound.\n");
S_Init (sfxVolume * 8, musicVolume * 8);
- printf (DEH_String("D_CheckNetGame: Checking network game status.\n"));
+ DEH_printf("D_CheckNetGame: Checking network game status.\n");
D_CheckNetGame ();
PrintGameVersion();
- printf (DEH_String("HU_Init: Setting up heads up display.\n"));
+ DEH_printf("HU_Init: Setting up heads up display.\n");
HU_Init ();
- printf (DEH_String("ST_Init: Init status bar.\n"));
+ DEH_printf("ST_Init: Init status bar.\n");
ST_Init ();
// If Doom II without a MAP01 lump, this is a store demo.
--- a/src/doom/d_net.c
+++ b/src/doom/d_net.c
@@ -374,17 +374,17 @@
++num_players;
}
- printf (DEH_String("startskill %i deathmatch: %i startmap: %i startepisode: %i\n"),
- startskill, deathmatch, startmap, startepisode);
+ DEH_printf("startskill %i deathmatch: %i startmap: %i startepisode: %i\n",
+ startskill, deathmatch, startmap, startepisode);
- printf(DEH_String("player %i of %i (%i nodes)\n"),
- consoleplayer+1, num_players, num_players);
+ DEH_printf("player %i of %i (%i nodes)\n",
+ consoleplayer+1, num_players, num_players);
// Show players here; the server might have specified a time limit
if (timelimit > 0)
{
- printf(DEH_String("Levels will end after %d minute"),timelimit);
+ DEH_printf("Levels will end after %d minute", timelimit);
if (timelimit > 1)
printf("s");
printf(".\n");
--- a/src/doom/f_finale.c
+++ b/src/doom/f_finale.c
@@ -663,7 +663,7 @@
laststage = stage;
}
- sprintf (name, DEH_String("END%i"), stage);
+ DEH_snprintf(name, 10, "END%i", stage);
V_DrawPatch((SCREENWIDTH - 13 * 8) / 2,
(SCREENHEIGHT - 8 * 8) / 2,
W_CacheLumpName (name,PU_CACHE));
--- a/src/doom/g_game.c
+++ b/src/doom/g_game.c
@@ -1428,6 +1428,8 @@
return;
}
+ savegame_error = false;
+
if (!P_ReadSaveGameHeader())
{
fclose(save_stream);
@@ -1494,6 +1496,8 @@
{
return;
}
+
+ savegame_error = false;
P_WriteSaveGameHeader(savedescription);
--- a/src/doom/hu_stuff.c
+++ b/src/doom/hu_stuff.c
@@ -302,7 +302,7 @@
j = HU_FONTSTART;
for (i=0;i<HU_FONTSIZE;i++)
{
- sprintf(buffer, DEH_String("STCFN%.3d"), j++);
+ DEH_snprintf(buffer, 9, "STCFN%.3d", j++);
hu_font[i] = (patch_t *) W_CacheLumpName(buffer, PU_STATIC);
}
--- a/src/doom/m_menu.c
+++ b/src/doom/m_menu.c
@@ -707,7 +707,7 @@
quickSaveSlot = -2; // means to pick a slot now
return;
}
- sprintf(tempstring,DEH_String(QSPROMPT),savegamestrings[quickSaveSlot]);
+ DEH_snprintf(tempstring, 80, QSPROMPT, savegamestrings[quickSaveSlot]);
M_StartMessage(tempstring,M_QuickSaveResponse,true);
}
@@ -739,7 +739,7 @@
M_StartMessage(DEH_String(QSAVESPOT),NULL,false);
return;
}
- sprintf(tempstring,DEH_String(QLPROMPT),savegamestrings[quickSaveSlot]);
+ DEH_snprintf(tempstring, 80, QLPROMPT, savegamestrings[quickSaveSlot]);
M_StartMessage(tempstring,M_QuickLoadResponse,true);
}
--- a/src/doom/p_saveg.c
+++ b/src/doom/p_saveg.c
@@ -44,6 +44,7 @@
FILE *save_stream;
int savegamelength;
+boolean savegame_error;
// Get the filename of a temporary file to write the savegame to. After
// the file has been successfully saved, it will be renamed to the
@@ -75,7 +76,7 @@
filename = malloc(strlen(savegamedir) + 32);
}
- sprintf(basename, DEH_String(SAVEGAMENAME "%d.dsg"), slot);
+ DEH_snprintf(basename, 32, SAVEGAMENAME "%d.dsg", slot);
sprintf(filename, "%s%s", savegamedir, basename);
@@ -88,14 +89,31 @@
{
byte result;
- fread(&result, 1, 1, save_stream);
+ if (fread(&result, 1, 1, save_stream) < 1)
+ {
+ if (!savegame_error)
+ {
+ fprintf(stderr, "saveg_read8: Unexpected end of file while "
+ "reading save game\n");
+ savegame_error = true;
+ }
+ }
+
return result;
}
static void saveg_write8(byte value)
{
- fwrite(&value, 1, 1, save_stream);
+ if (fwrite(&value, 1, 1, save_stream) < 1)
+ {
+ if (!savegame_error)
+ {
+ fprintf(stderr, "saveg_write8: Error while writing save game\n");
+
+ savegame_error = true;
+ }
+ }
}
static short saveg_read16(void)
--- a/src/doom/p_saveg.h
+++ b/src/doom/p_saveg.h
@@ -64,6 +64,7 @@
void P_UnArchiveSpecials (void);
extern FILE *save_stream;
+extern boolean savegame_error;
#endif
--- a/src/doom/p_setup.c
+++ b/src/doom/p_setup.c
@@ -774,9 +774,9 @@
if ( gamemode == commercial)
{
if (map<10)
- sprintf (lumpname, DEH_String("map0%i"), map);
+ DEH_snprintf(lumpname, 9, "map0%i", map);
else
- sprintf (lumpname, DEH_String("map%i"), map);
+ DEH_snprintf(lumpname, 9, "map%i", map);
}
else
{
--- a/src/doom/st_stuff.c
+++ b/src/doom/st_stuff.c
@@ -1085,10 +1085,10 @@
// Load the numbers, tall and short
for (i=0;i<10;i++)
{
- sprintf(namebuf, DEH_String("STTNUM%d"), i);
+ DEH_snprintf(namebuf, 9, "STTNUM%d", i);
callback(namebuf, &tallnum[i]);
- sprintf(namebuf, DEH_String("STYSNUM%d"), i);
+ DEH_snprintf(namebuf, 9, "STYSNUM%d", i);
callback(namebuf, &shortnum[i]);
}
@@ -1100,7 +1100,7 @@
// key cards
for (i=0;i<NUMCARDS;i++)
{
- sprintf(namebuf, DEH_String("STKEYS%d"), i);
+ DEH_snprintf(namebuf, 9, "STKEYS%d", i);
callback(namebuf, &keys[i]);
}
@@ -1110,7 +1110,7 @@
// arms ownership widgets
for (i=0; i<6; i++)
{
- sprintf(namebuf, DEH_String("STGNUM%d"), i+2);
+ DEH_snprintf(namebuf, 9, "STGNUM%d", i+2);
// gray #
callback(namebuf, &arms[i][0]);
@@ -1120,7 +1120,7 @@
}
// face backgrounds for different color players
- sprintf(namebuf, DEH_String("STFB%d"), consoleplayer);
+ DEH_snprintf(namebuf, 9, "STFB%d", consoleplayer);
callback(namebuf, &faceback);
// status bar background bits
@@ -1132,23 +1132,23 @@
{
for (j=0; j<ST_NUMSTRAIGHTFACES; j++)
{
- sprintf(namebuf, DEH_String("STFST%d%d"), i, j);
+ DEH_snprintf(namebuf, 9, "STFST%d%d", i, j);
callback(namebuf, &faces[facenum]);
++facenum;
}
- sprintf(namebuf, DEH_String("STFTR%d0"), i); // turn right
+ DEH_snprintf(namebuf, 9, "STFTR%d0", i); // turn right
callback(namebuf, &faces[facenum]);
++facenum;
- sprintf(namebuf, DEH_String("STFTL%d0"), i); // turn left
+ DEH_snprintf(namebuf, 9, "STFTL%d0", i); // turn left
callback(namebuf, &faces[facenum]);
++facenum;
- sprintf(namebuf, DEH_String("STFOUCH%d"), i); // ouch!
+ DEH_snprintf(namebuf, 9, "STFOUCH%d", i); // ouch!
callback(namebuf, &faces[facenum]);
++facenum;
- sprintf(namebuf, DEH_String("STFEVL%d"), i); // evil grin ;)
+ DEH_snprintf(namebuf, 9, "STFEVL%d", i); // evil grin ;)
callback(namebuf, &faces[facenum]);
++facenum;
- sprintf(namebuf, DEH_String("STFKILL%d"), i); // pissed off
+ DEH_snprintf(namebuf, 9, "STFKILL%d", i); // pissed off
callback(namebuf, &faces[facenum]);
++facenum;
}
--- a/src/doom/wi_stuff.c
+++ b/src/doom/wi_stuff.c
@@ -1571,16 +1571,16 @@
if (gamemode == commercial)
{
for (i=0 ; i<NUMCMAPS ; i++)
- {
- sprintf(name, DEH_String("CWILV%2.2d"), i);
+ {
+ DEH_snprintf(name, 9, "CWILV%2.2d", i);
callback(name, &lnames[i]);
- }
+ }
}
else
{
for (i=0 ; i<NUMMAPS ; i++)
{
- sprintf(name, DEH_String("WILV%d%d"), wbs->epsd, i);
+ DEH_snprintf(name, 9, "WILV%d%d", wbs->epsd, i);
callback(name, &lnames[i]);
}
@@ -1592,7 +1592,7 @@
// splat
callback(DEH_String("WISPLAT"), &splat[0]);
-
+
if (wbs->epsd < 3)
{
for (j=0;j<NUMANIMS[wbs->epsd];j++)
@@ -1601,17 +1601,16 @@
for (i=0;i<a->nanims;i++)
{
// MONDO HACK!
- if (wbs->epsd != 1 || j != 8)
+ if (wbs->epsd != 1 || j != 8)
{
// animations
- sprintf(name, DEH_String("WIA%d%.2d%.2d"),
- wbs->epsd, j, i);
+ DEH_snprintf(name, 9, "WIA%d%.2d%.2d", wbs->epsd, j, i);
callback(name, &a->p[i]);
}
else
{
// HACK ALERT!
- a->p[i] = anims[1][4].p[i];
+ a->p[i] = anims[1][4].p[i];
}
}
}
@@ -1624,7 +1623,7 @@
for (i=0;i<10;i++)
{
// numbers 0-9
- sprintf(name, DEH_String("WINUM%d"), i);
+ DEH_snprintf(name, 9, "WINUM%d", i);
callback(name, &num[i]);
}
@@ -1665,13 +1664,13 @@
callback(DEH_String("WICOLON"), &colon);
// "time"
- callback(DEH_String("WITIME"), &timepatch);
+ callback(DEH_String("WITIME"), &timepatch);
// "sucks"
- callback(DEH_String("WISUCKS"), &sucks);
+ callback(DEH_String("WISUCKS"), &sucks);
// "par"
- callback(DEH_String("WIPAR"), &par);
+ callback(DEH_String("WIPAR"), &par);
// "killers" (vertical)
callback(DEH_String("WIKILRS"), &killers);
@@ -1680,16 +1679,16 @@
callback(DEH_String("WIVCTMS"), &victims);
// "total"
- callback(DEH_String("WIMSTT"), &total);
+ callback(DEH_String("WIMSTT"), &total);
for (i=0 ; i<MAXPLAYERS ; i++)
{
// "1,2,3,4"
- sprintf(name, DEH_String("STPB%d"), i);
+ DEH_snprintf(name, 9, "STPB%d", i);
callback(name, &p[i]);
// "1,2,3,4"
- sprintf(name, DEH_String("WIBP%d"), i+1);
+ DEH_snprintf(name, 9, "WIBP%d", i+1);
callback(name, &bp[i]);
}
@@ -1697,19 +1696,21 @@
if (gamemode == commercial)
{
- strcpy(name, DEH_String("INTERPIC"));
+ strncpy(name, DEH_String("INTERPIC"), 9);
+ name[8] = '\0';
}
else if (gamemode == retail && wbs->epsd == 3)
{
- strcpy(name, DEH_String("INTERPIC"));
+ strncpy(name, DEH_String("INTERPIC"), 9);
+ name[8] = '\0';
}
- else
+ else
{
- sprintf(name, DEH_String("WIMAP%d"), wbs->epsd);
+ DEH_snprintf(name, 9, "WIMAP%d", wbs->epsd);
}
-
+
// Draw backdrop and save to a temporary buffer
-
+
callback(name, &background);
}
@@ -1722,7 +1723,7 @@
{
if (gamemode == commercial)
{
- NUMCMAPS = 32;
+ NUMCMAPS = 32;
lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMCMAPS,
PU_STATIC, NULL);
}
--- a/src/m_argv.c
+++ b/src/m_argv.c
@@ -101,7 +101,7 @@
size = M_FileLength(handle);
// Read in the entire file
- // Allocate one byte extra - this is incase there is an argument
+ // Allocate one byte extra - this is in case there is an argument
// at the end of the response file, in which case a '\0' will be
// needed.
--- a/src/net_client.c
+++ b/src/net_client.c
@@ -196,7 +196,8 @@
// Do this the same way as Vanilla Doom does, to allow dehacked
// replacements of this message
- strcpy(exitmsg, DEH_String("Player 1 left the game"));
+ strncpy(exitmsg, DEH_String("Player 1 left the game"), sizeof(exitmsg));
+ exitmsg[sizeof(exitmsg) - 1] = '\0';
exitmsg[7] += player - players;