foxygit / doom Log in
commit 4767ddccafca1a1c50bc097284df1328d478882a
Merge: af48a630 aa35a71b
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Mon May 3 17:07:45 2010 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Mon May 3 17:07:45 2010 +0000

    Merge from trunk.

    Subversion-branch: /branches/raven-branch
    Subversion-revision: 1931

 NEWS                |  24 ++++++
 src/deh_str.c       | 227 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/deh_str.h       |   9 +++
 src/doom/am_map.c   |   6 +-
 src/doom/d_main.c   |  34 ++++----
 src/doom/d_net.c    |  10 +--
 src/doom/f_finale.c |   2 +-
 src/doom/g_game.c   |   4 +
 src/doom/hu_stuff.c |   2 +-
 src/doom/m_menu.c   |   4 +-
 src/doom/p_saveg.c  |  24 +++++-
 src/doom/p_saveg.h  |   1 +
 src/doom/p_setup.c  |   4 +-
 src/doom/st_stuff.c |  22 ++---
 src/doom/wi_stuff.c |  47 +++++------
 src/m_argv.c        |   2 +-
 src/net_client.c    |   3 +-
 17 files changed, 355 insertions(+), 70 deletions(-)

diff --cc src/deh_str.c
index 0baaa7e8,00000000..9bd429b6
mode 100644,000000..100644
--- a/src/deh_str.c
+++ b/src/deh_str.c
@@@ -1,181 -1,0 +1,408 @@@
 +// Emacs style mode select   -*- C++ -*-
 +//-----------------------------------------------------------------------------
 +//
 +// Copyright(C) 2005 Simon Howard
 +//
 +// This program is free software; you can redistribute it and/or
 +// modify it under the terms of the GNU General Public License
 +// as published by the Free Software Foundation; either version 2
 +// of the License, or (at your option) any later version.
 +//
 +// This program is distributed in the hope that it will be useful,
 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +// GNU General Public License for more details.
 +//
 +// You should have received a copy of the GNU General Public License
 +// along with this program; if not, write to the Free Software
 +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 +// 02111-1307, USA.
 +//
 +//-----------------------------------------------------------------------------
 +//
 +// Parses Text substitution sections in dehacked files
 +//
 +//-----------------------------------------------------------------------------
 +
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <string.h>
++#include <stdarg.h>
 +
 +#include "doomtype.h"
 +#include "deh_str.h"
 +
 +#include "z_zone.h"
 +
 +typedef struct
 +{
 +    char *from_text;
 +    char *to_text;
 +} deh_substitution_t;
 +
 +static deh_substitution_t **hash_table = NULL;
 +static int hash_table_entries;
 +static int hash_table_length = -1;
 +
 +// This is the algorithm used by glib
 +
 +static unsigned int strhash(char *s)
 +{
 +    char *p = s;
 +    unsigned int h = *p;
 +
 +    if (h)
 +    {
 +        for (p += 1; *p; p++)
 +            h = (h << 5) - h + *p;
 +    }
 +
 +    return h;
 +}
 +
 +// Look up a string to see if it has been replaced with something else
 +// This will be used throughout the program to substitute text
 +
 +char *DEH_String(char *s)
 +{
 +    int entry;
 +
 +    // Fallback if we have not initialized the hash table yet
 +
 +    if (hash_table_length < 0)
 +	return s;
 +
 +    entry = strhash(s) % hash_table_length;
 +
 +    while (hash_table[entry] != NULL)
 +    {
 +        if (!strcmp(hash_table[entry]->from_text, s))
 +        {
 +            // substitution found!
 +
 +            return hash_table[entry]->to_text;
 +        }
 +
 +        entry = (entry + 1) % hash_table_length;
 +    }
 +
 +    // no substitution found
 +
 +    return s;
 +}
 +
 +static void InitHashTable(void)
 +{
 +    // init hash table
 +
 +    hash_table_entries = 0;
 +    hash_table_length = 16;
 +    hash_table = Z_Malloc(sizeof(deh_substitution_t *) * hash_table_length,
 +                          PU_STATIC, NULL);
 +    memset(hash_table, 0, sizeof(deh_substitution_t *) * hash_table_length);
 +}
 +
 +static void DEH_AddToHashtable(deh_substitution_t *sub);
 +
 +static void IncreaseHashtable(void)
 +{
 +    deh_substitution_t **old_table;
 +    int old_table_length;
 +    int i;
 +
 +    // save the old table
 +
 +    old_table = hash_table;
 +    old_table_length = hash_table_length;
 +
 +    // double the size
 +
 +    hash_table_length *= 2;
 +    hash_table = Z_Malloc(sizeof(deh_substitution_t *) * hash_table_length,
 +                          PU_STATIC, NULL);
 +    memset(hash_table, 0, sizeof(deh_substitution_t *) * hash_table_length);
 +
 +    // go through the old table and insert all the old entries
 +
 +    for (i=0; i<old_table_length; ++i)
 +    {
 +        if (old_table[i] != NULL)
 +        {
 +            DEH_AddToHashtable(old_table[i]);
 +        }
 +    }
 +
 +    // free the old table
 +
 +    Z_Free(old_table);
 +}
 +
 +static void DEH_AddToHashtable(deh_substitution_t *sub)
 +{
 +    int entry;
 +
 +    // if the hash table is more than 60% full, increase its size
 +
 +    if ((hash_table_entries * 10) / hash_table_length > 6)
 +    {
 +        IncreaseHashtable();
 +    }
 +
 +    // find where to insert it
 +
 +    entry = strhash(sub->from_text) % hash_table_length;
 +
 +    while (hash_table[entry] != NULL)
 +    {
 +        entry = (entry + 1) % hash_table_length;
 +    }
 +
 +    hash_table[entry] = sub;
 +    ++hash_table_entries;
 +}
 +
 +void DEH_AddStringReplacement(char *from_text, char *to_text)
 +{
 +    deh_substitution_t *sub;
 +
 +    // Initialize the hash table if this is the first time
 +
 +    if (hash_table_length < 0)
 +    {
 +        InitHashTable();
 +    }
 +
 +    sub = Z_Malloc(sizeof(*sub), PU_STATIC, 0);
 +
 +    sub->from_text = from_text;
 +    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);
++}
++
diff --cc src/deh_str.h
index 986536de,ae9ab917..06bcb420
--- a/src/deh_str.h
+++ b/src/deh_str.h
@@@ -24,23 -24,42 +24,32 @@@
  //
  //-----------------------------------------------------------------------------

 +#ifndef DEH_STR_H
 +#define DEH_STR_H

++#include <stdio.h>
+
 -#include <string.h>
 +#include "doomfeatures.h"

 -int		myargc;
 -char**		myargv;
 +// Used to do dehacked text substitutions throughout the program

 -// From doomdef.h -- no need to include it all!
 -#ifdef _WIN32
 -#define snprintf _snprintf
 -#define vsnprintf _vsnprintf
 -#define strcasecmp stricmp
 -#define strncasecmp strnicmp
 -#else
 -#include <strings.h>
 -#endif
 +#ifdef FEATURE_DEHACKED

 -//
 -// M_CheckParm
 -// Checks for the given parameter
 -// in the program's command line arguments.
 -// Returns the argument number (1 to argc-1)
 -// or 0 if not present
 -int M_CheckParm (char *check)
 -{
 -    int		i;
 +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);

 -    for (i = 1;i<myargc;i++)
 -    {
 -	if ( !strcasecmp(check, myargv[i]) )
 -	    return i;
 -    }
+
 -    return 0;
 -}
 +#else

 +#define DEH_String(x) (x)
++#define DEH_printf printf
++#define DEH_fprintf fprintf
++#define DEH_snprintf snprintf

 +#endif

 +#endif /* #ifndef DEH_STR_H */

diff --cc src/doom/d_main.c
index c6099da9,671c4e9c..3fee8439
--- a/src/doom/d_main.c
+++ b/src/doom/d_main.c
@@@ -1066,9 -817,9 +1066,9 @@@ void D_DoomMain (void

      // print banner

 -    PrintBanner(PACKAGE_STRING);
 +    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
@@@ -1243,21 -970,167 +1243,21 @@@
      }

      // 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_ApplyPlatformDefaults();
 -    M_LoadDefaults ();              // load before initing other systems
 +    M_SetConfigFilenames("default.cfg", PROGRAM_PREFIX "doom.cfg");
 +    D_BindVariables();
 +    M_LoadDefaults();
 +
 +    // 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);
 -
 -#ifdef FEATURE_WAD_MERGE
 -
 -    // Merged PWADs are loaded first, because they are supposed to be
 -    // modified IWADs.
 -
 -    //!
 -    // @arg <files>
 -    // @category mod
 -    //
 -    // Simulates the behavior of deutex's -merge option, merging a PWAD
 -    // into the main IWAD.  Multiple files may be specified.
 -    //
 -
 -    p = M_CheckParm("-merge");
 -
 -    if (p > 0)
 -    {
 -        for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
 -        {
 -            char *filename;
 -
 -            filename = D_TryFindWADByName(myargv[p]);
 -
 -            printf(" merging %s\n", filename);
 -            W_MergeFile(filename);
 -        }
 -    }
 -
 -    // NWT-style merging:
 -
 -    // NWT's -merge option:
 -
 -    //!
 -    // @arg <files>
 -    // @category mod
 -    //
 -    // Simulates the behavior of NWT's -merge option.  Multiple files
 -    // may be specified.
 -
 -    p = M_CheckParm("-nwtmerge");
 -
 -    if (p > 0)
 -    {
 -        for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
 -        {
 -            char *filename;
 -
 -            filename = D_TryFindWADByName(myargv[p]);
 -
 -            printf(" performing NWT-style merge of %s\n", filename);
 -            W_NWTDashMerge(filename);
 -        }
 -    }
 -
 -    // Add flats
 -
 -    //!
 -    // @arg <files>
 -    // @category mod
 -    //
 -    // Simulates the behavior of NWT's -af option, merging flats into
 -    // the main IWAD directory.  Multiple files may be specified.
 -    //
 -
 -    p = M_CheckParm("-af");
 -
 -    if (p > 0)
 -    {
 -        for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
 -        {
 -            char *filename;
 -
 -            filename = D_TryFindWADByName(myargv[p]);
 -
 -            printf(" merging flats from %s\n", filename);
 -            W_NWTMergeFile(filename, W_NWT_MERGE_FLATS);
 -        }
 -    }
 -
 -    //!
 -    // @arg <files>
 -    // @category mod
 -    //
 -    // Simulates the behavior of NWT's -as option, merging sprites
 -    // into the main IWAD directory.  Multiple files may be specified.
 -    //
 -
 -    p = M_CheckParm("-as");
 -
 -    if (p > 0)
 -    {
 -        for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
 -        {
 -            char *filename;
 -
 -            filename = D_TryFindWADByName(myargv[p]);
 -
 -            printf(" merging sprites from %s\n", filename);
 -            W_NWTMergeFile(filename, W_NWT_MERGE_SPRITES);
 -        }
 -    }
 -
 -    //!
 -    // @arg <files>
 -    // @category mod
 -    //
 -    // Equivalent to "-af <files> -as <files>".
 -    //
 -
 -    p = M_CheckParm("-aa");
 -
 -    if (p > 0)
 -    {
 -        for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
 -        {
 -            char *filename;
 -
 -            filename = D_TryFindWADByName(myargv[p]);
 -
 -            printf(" merging sprites and flats from %s\n", filename);
 -            W_NWTMergeFile(filename, W_NWT_MERGE_SPRITES | W_NWT_MERGE_FLATS);
 -        }
 -    }
 -
 -#endif
 -
 -    //!
 -    // @arg <files>
 -    // @vanilla
 -    //
 -    // Load the specified PWAD files.
 -    //
 -
 -    p = M_CheckParm ("-file");
 -    if (p)
 -    {
 -	// the parms after p are wadfile/lump names,
 -	// until end of parms or another - preceded parm
 -	modifiedgame = true;            // homebrew levels
 -	while (++p != myargc && myargv[p][0] != '-')
 -        {
 -            char *filename;
 -
 -            filename = D_TryFindWADByName(myargv[p]);
 -
 -	    D_AddFile(filename);
 -        }
 -    }
 -
 -    // Debug:
 -//    W_PrintDirectory();
 +    modifiedgame = W_ParseCommandLine();

      // add any files specified on the command line with -file wadfile
      // to the wad list
@@@ -1530,23 -1419,35 +1530,23 @@@
                 " floor textures.  You may want to use the '-merge' command\n"
                 " line option instead of '-file'.\n");
      }
 -
 -    printf ("===========================================================================\n");
 -
 -    PrintBanner(gamedescription);
 -
 -
 -    printf (
 -	    "===========================================================================\n"
 -	    " " PACKAGE_NAME " is free software, covered by the GNU General Public\n"
 -            " License.  There is NO warranty; not even for MERCHANTABILITY or FITNESS\n"
 -            " FOR A PARTICULAR PURPOSE. You are welcome to change and distribute\n"
 -            " copies under certain conditions. See the source for more information.\n"
 -
 -	    "===========================================================================\n"
 -	);

 +    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_Init ();
 +    I_CheckIsScreensaver();
 +    I_InitTimer();
 +    I_InitJoystick();

  #ifdef FEATURE_MULTIPLAYER
      printf ("NET_Init: Init network subsystem.\n");
diff --cc src/doom/f_finale.c
index ece82b43,3f0082cb..dfbeafbe
--- a/src/doom/f_finale.c
+++ b/src/doom/f_finale.c
@@@ -663,10 -663,9 +663,10 @@@ void F_BunnyScroll (void
  	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,0,
 -	         W_CacheLumpName (name,PU_CACHE));
 +    V_DrawPatch((SCREENWIDTH - 13 * 8) / 2,
 +                (SCREENHEIGHT - 8 * 8) / 2,
 +                W_CacheLumpName (name,PU_CACHE));
  }

  static void F_ArtScreenDrawer(void)
diff --cc src/doom/wi_stuff.c
index 83f5052f,7c0ba312..45c09343
--- a/src/doom/wi_stuff.c
+++ b/src/doom/wi_stuff.c
@@@ -1693,24 -1710,6 +1692,26 @@@ static void WI_loadUnloadData(load_call
          callback(name, &bp[i]);
      }

 +    // Background image
 +
 +    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);
  }

  static void WI_loadCallback(char *name, patch_t **variable)
@@@ -1720,9 -1719,12 +1721,9 @@@

  void WI_loadData(void)
  {
 -    char bg_lumpname[9];
 -    patch_t *bg;
 -
      if (gamemode == commercial)
      {
- 	NUMCMAPS = 32;
+ 	NUMCMAPS = 32;
  	lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMCMAPS,
  				       PU_STATIC, NULL);
      }
diff --cc src/m_argv.c
index e2b551f1,7fc15863..79702e56
--- a/src/m_argv.c
+++ b/src/m_argv.c
@@@ -101,8 -89,8 +101,8 @@@ static void LoadResponseFile(int argv_i
      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
 +    // at the end of the response file, in which case a '\0' will be
      // needed.

      file = malloc(size + 1);