ref: 366f45c10a632443767cbda6f7b2f3d98a60d60b
parent: 204814c7bb16a8ad45435a15328072681978ea57
author: Fabian Greffrath <fabian@greffrath.com>
date: Mon Sep 8 06:48:56 EDT 2014
add parser for [STRINGS] sections in BEX files
--- a/src/deh_io.c
+++ b/src/deh_io.c
@@ -19,6 +19,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#include "i_system.h"
#include "m_misc.h"
@@ -224,7 +225,7 @@
// Read a whole line
-char *DEH_ReadLine(deh_context_t *context)
+char *DEH_ReadLine(deh_context_t *context, boolean extended)
{
int c;
int pos;
@@ -245,6 +246,40 @@
if (pos >= context->readbuffer_size)
{
IncreaseReadBuffer(context);
+ }
+
+ // extended string support
+ if (extended && c == '\\')
+ {
+ escaped:
+ c = DEH_GetChar(context);
+
+ // "\n" in the middle of a string indicates an internal linefeed
+ if (c == 'n')
+ {
+ context->readbuffer[pos] = '\n';
+ ++pos;
+ continue;
+ }
+
+ // values to be assigned may be split onto multiple lines by ending
+ // each line that is to be continued with a backslash
+ if (c == '\n')
+ {
+ // blanks before the backslash are included in the string
+ // but indentation after the linefeed is not
+ do
+ {
+ c = DEH_GetChar(context);
+ } while (isspace(c) && c != '\n');
+
+ // if the next non-space character after an escaped linefeed
+ // is another backslash, repeat again
+ if (c == '\\')
+ {
+ goto escaped;
+ }
+ }
}
if (c == '\n')
--- a/src/deh_io.h
+++ b/src/deh_io.h
@@ -24,7 +24,7 @@
deh_context_t *DEH_OpenLump(int lumpnum);
void DEH_CloseFile(deh_context_t *context);
int DEH_GetChar(deh_context_t *context);
-char *DEH_ReadLine(deh_context_t *context);
+char *DEH_ReadLine(deh_context_t *context, boolean extended);
void DEH_Error(deh_context_t *context, char *msg, ...);
void DEH_Warning(deh_context_t *context, char *msg, ...);
--- a/src/deh_main.c
+++ b/src/deh_main.c
@@ -175,7 +175,7 @@
// Read the first line
- line = DEH_ReadLine(context);
+ line = DEH_ReadLine(context, false);
if (line == NULL)
{
@@ -244,7 +244,7 @@
{
// read a new line
- line = DEH_ReadLine(context);
+ line = DEH_ReadLine(context, current_section == GetSectionByName("[STRINGS]"));
// end of file?
--- a/src/doom/Makefile.am
+++ b/src/doom/Makefile.am
@@ -63,6 +63,7 @@
FEATURE_DEHACKED_SOURCE_FILES = \
deh_ammo.c \
+deh_bexstr.c \
deh_cheat.c \
deh_doom.c \
deh_frame.c \
--- /dev/null
+++ b/src/doom/deh_bexstr.c
@@ -1,0 +1,376 @@
+//
+// Copyright(C) 2005-2014 Simon Howard
+// Copyright(C) 2014 Fabian Greffrath
+//
+// 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.
+//
+//
+// Parses [STRINGS] sections in BEX files
+//
+
+#include <stdio.h>
+#include <string.h>
+
+#include "deh_defs.h"
+#include "deh_io.h"
+#include "deh_main.h"
+
+#include "dstrings.h"
+
+typedef struct {
+ char *macro;
+ char *string;
+} bex_string;
+
+// mnemonic keys table
+static bex_string bex_stringtable[] = {
+ // part 1 - general initialization and prompts
+ {"D_DEVSTR", D_DEVSTR},
+ {"D_CDROM", D_CDROM},
+ {"QUITMSG", QUITMSG},
+ {"LOADNET", LOADNET},
+ {"QLOADNET", QLOADNET},
+ {"QSAVESPOT", QSAVESPOT},
+ {"SAVEDEAD", SAVEDEAD},
+ {"QSPROMPT", QSPROMPT},
+ {"QLPROMPT", QLPROMPT},
+ {"NEWGAME", NEWGAME},
+ {"NIGHTMARE", NIGHTMARE},
+ {"SWSTRING", SWSTRING},
+ {"MSGOFF", MSGOFF},
+ {"MSGON", MSGON},
+ {"NETEND", NETEND},
+ {"ENDGAME", ENDGAME},
+ {"DETAILHI", DETAILHI},
+ {"DETAILLO", DETAILLO},
+ {"GAMMALVL0", GAMMALVL0},
+ {"GAMMALVL1", GAMMALVL1},
+ {"GAMMALVL2", GAMMALVL2},
+ {"GAMMALVL3", GAMMALVL3},
+ {"GAMMALVL4", GAMMALVL4},
+ {"EMPTYSTRING", EMPTYSTRING},
+ {"GGSAVED", GGSAVED},
+ {"SAVEGAMENAME", SAVEGAMENAME},
+ // part 2 - messages when the player gets things
+ {"GOTARMOR", GOTARMOR},
+ {"GOTMEGA", GOTMEGA},
+ {"GOTHTHBONUS", GOTHTHBONUS},
+ {"GOTARMBONUS", GOTARMBONUS},
+ {"GOTSTIM", GOTSTIM},
+ {"GOTMEDINEED", GOTMEDINEED},
+ {"GOTMEDIKIT", GOTMEDIKIT},
+ {"GOTSUPER", GOTSUPER},
+ {"GOTBLUECARD", GOTBLUECARD},
+ {"GOTYELWCARD", GOTYELWCARD},
+ {"GOTREDCARD", GOTREDCARD},
+ {"GOTBLUESKUL", GOTBLUESKUL},
+ {"GOTYELWSKUL", GOTYELWSKUL},
+ {"GOTREDSKULL", GOTREDSKULL},
+ {"GOTINVUL", GOTINVUL},
+ {"GOTBERSERK", GOTBERSERK},
+ {"GOTINVIS", GOTINVIS},
+ {"GOTSUIT", GOTSUIT},
+ {"GOTMAP", GOTMAP},
+ {"GOTVISOR", GOTVISOR},
+ {"GOTMSPHERE", GOTMSPHERE},
+ {"GOTCLIP", GOTCLIP},
+ {"GOTCLIPBOX", GOTCLIPBOX},
+ {"GOTROCKET", GOTROCKET},
+ {"GOTROCKBOX", GOTROCKBOX},
+ {"GOTCELL", GOTCELL},
+ {"GOTCELLBOX", GOTCELLBOX},
+ {"GOTSHELLS", GOTSHELLS},
+ {"GOTSHELLBOX", GOTSHELLBOX},
+ {"GOTBACKPACK", GOTBACKPACK},
+ {"GOTBFG9000", GOTBFG9000},
+ {"GOTCHAINGUN", GOTCHAINGUN},
+ {"GOTCHAINSAW", GOTCHAINSAW},
+ {"GOTLAUNCHER", GOTLAUNCHER},
+ {"GOTPLASMA", GOTPLASMA},
+ {"GOTSHOTGUN", GOTSHOTGUN},
+ {"GOTSHOTGUN2", GOTSHOTGUN2},
+ // part 3 - messages when keys are needed
+ {"PD_BLUEO", PD_BLUEO},
+ {"PD_REDO", PD_REDO},
+ {"PD_YELLOWO", PD_YELLOWO},
+ {"PD_BLUEK", PD_BLUEK},
+ {"PD_REDK", PD_REDK},
+ {"PD_YELLOWK", PD_YELLOWK},
+ // part 4 - multiplayer messaging
+ {"HUSTR_MSGU", HUSTR_MSGU},
+ {"HUSTR_MESSAGESENT", HUSTR_MESSAGESENT},
+ {"HUSTR_CHATMACRO0", HUSTR_CHATMACRO0},
+ {"HUSTR_CHATMACRO1", HUSTR_CHATMACRO1},
+ {"HUSTR_CHATMACRO2", HUSTR_CHATMACRO2},
+ {"HUSTR_CHATMACRO3", HUSTR_CHATMACRO3},
+ {"HUSTR_CHATMACRO4", HUSTR_CHATMACRO4},
+ {"HUSTR_CHATMACRO5", HUSTR_CHATMACRO5},
+ {"HUSTR_CHATMACRO6", HUSTR_CHATMACRO6},
+ {"HUSTR_CHATMACRO7", HUSTR_CHATMACRO7},
+ {"HUSTR_CHATMACRO8", HUSTR_CHATMACRO8},
+ {"HUSTR_CHATMACRO9", HUSTR_CHATMACRO9},
+ {"HUSTR_TALKTOSELF1", HUSTR_TALKTOSELF1},
+ {"HUSTR_TALKTOSELF2", HUSTR_TALKTOSELF2},
+ {"HUSTR_TALKTOSELF3", HUSTR_TALKTOSELF3},
+ {"HUSTR_TALKTOSELF4", HUSTR_TALKTOSELF4},
+ {"HUSTR_TALKTOSELF5", HUSTR_TALKTOSELF5},
+ {"HUSTR_PLRGREEN", HUSTR_PLRGREEN},
+ {"HUSTR_PLRINDIGO", HUSTR_PLRINDIGO},
+ {"HUSTR_PLRBROWN", HUSTR_PLRBROWN},
+ {"HUSTR_PLRRED", HUSTR_PLRRED},
+ // part 5 - level names in the automap
+ {"HUSTR_E1M1", HUSTR_E1M1},
+ {"HUSTR_E1M2", HUSTR_E1M2},
+ {"HUSTR_E1M3", HUSTR_E1M3},
+ {"HUSTR_E1M4", HUSTR_E1M4},
+ {"HUSTR_E1M5", HUSTR_E1M5},
+ {"HUSTR_E1M6", HUSTR_E1M6},
+ {"HUSTR_E1M7", HUSTR_E1M7},
+ {"HUSTR_E1M8", HUSTR_E1M8},
+ {"HUSTR_E1M9", HUSTR_E1M9},
+ {"HUSTR_E2M1", HUSTR_E2M1},
+ {"HUSTR_E2M2", HUSTR_E2M2},
+ {"HUSTR_E2M3", HUSTR_E2M3},
+ {"HUSTR_E2M4", HUSTR_E2M4},
+ {"HUSTR_E2M5", HUSTR_E2M5},
+ {"HUSTR_E2M6", HUSTR_E2M6},
+ {"HUSTR_E2M7", HUSTR_E2M7},
+ {"HUSTR_E2M8", HUSTR_E2M8},
+ {"HUSTR_E2M9", HUSTR_E2M9},
+ {"HUSTR_E3M1", HUSTR_E3M1},
+ {"HUSTR_E3M2", HUSTR_E3M2},
+ {"HUSTR_E3M3", HUSTR_E3M3},
+ {"HUSTR_E3M4", HUSTR_E3M4},
+ {"HUSTR_E3M5", HUSTR_E3M5},
+ {"HUSTR_E3M6", HUSTR_E3M6},
+ {"HUSTR_E3M7", HUSTR_E3M7},
+ {"HUSTR_E3M8", HUSTR_E3M8},
+ {"HUSTR_E3M9", HUSTR_E3M9},
+ {"HUSTR_E4M1", HUSTR_E4M1},
+ {"HUSTR_E4M2", HUSTR_E4M2},
+ {"HUSTR_E4M3", HUSTR_E4M3},
+ {"HUSTR_E4M4", HUSTR_E4M4},
+ {"HUSTR_E4M5", HUSTR_E4M5},
+ {"HUSTR_E4M6", HUSTR_E4M6},
+ {"HUSTR_E4M7", HUSTR_E4M7},
+ {"HUSTR_E4M8", HUSTR_E4M8},
+ {"HUSTR_E4M9", HUSTR_E4M9},
+ {"HUSTR_1", HUSTR_1},
+ {"HUSTR_2", HUSTR_2},
+ {"HUSTR_3", HUSTR_3},
+ {"HUSTR_4", HUSTR_4},
+ {"HUSTR_5", HUSTR_5},
+ {"HUSTR_6", HUSTR_6},
+ {"HUSTR_7", HUSTR_7},
+ {"HUSTR_8", HUSTR_8},
+ {"HUSTR_9", HUSTR_9},
+ {"HUSTR_10", HUSTR_10},
+ {"HUSTR_11", HUSTR_11},
+ {"HUSTR_12", HUSTR_12},
+ {"HUSTR_13", HUSTR_13},
+ {"HUSTR_14", HUSTR_14},
+ {"HUSTR_15", HUSTR_15},
+ {"HUSTR_16", HUSTR_16},
+ {"HUSTR_17", HUSTR_17},
+ {"HUSTR_18", HUSTR_18},
+ {"HUSTR_19", HUSTR_19},
+ {"HUSTR_20", HUSTR_20},
+ {"HUSTR_21", HUSTR_21},
+ {"HUSTR_22", HUSTR_22},
+ {"HUSTR_23", HUSTR_23},
+ {"HUSTR_24", HUSTR_24},
+ {"HUSTR_25", HUSTR_25},
+ {"HUSTR_26", HUSTR_26},
+ {"HUSTR_27", HUSTR_27},
+ {"HUSTR_28", HUSTR_28},
+ {"HUSTR_29", HUSTR_29},
+ {"HUSTR_30", HUSTR_30},
+ {"HUSTR_31", HUSTR_31},
+ {"HUSTR_32", HUSTR_32},
+ {"PHUSTR_1", PHUSTR_1},
+ {"PHUSTR_2", PHUSTR_2},
+ {"PHUSTR_3", PHUSTR_3},
+ {"PHUSTR_4", PHUSTR_4},
+ {"PHUSTR_5", PHUSTR_5},
+ {"PHUSTR_6", PHUSTR_6},
+ {"PHUSTR_7", PHUSTR_7},
+ {"PHUSTR_8", PHUSTR_8},
+ {"PHUSTR_9", PHUSTR_9},
+ {"PHUSTR_10", PHUSTR_10},
+ {"PHUSTR_11", PHUSTR_11},
+ {"PHUSTR_12", PHUSTR_12},
+ {"PHUSTR_13", PHUSTR_13},
+ {"PHUSTR_14", PHUSTR_14},
+ {"PHUSTR_15", PHUSTR_15},
+ {"PHUSTR_16", PHUSTR_16},
+ {"PHUSTR_17", PHUSTR_17},
+ {"PHUSTR_18", PHUSTR_18},
+ {"PHUSTR_19", PHUSTR_19},
+ {"PHUSTR_20", PHUSTR_20},
+ {"PHUSTR_21", PHUSTR_21},
+ {"PHUSTR_22", PHUSTR_22},
+ {"PHUSTR_23", PHUSTR_23},
+ {"PHUSTR_24", PHUSTR_24},
+ {"PHUSTR_25", PHUSTR_25},
+ {"PHUSTR_26", PHUSTR_26},
+ {"PHUSTR_27", PHUSTR_27},
+ {"PHUSTR_28", PHUSTR_28},
+ {"PHUSTR_29", PHUSTR_29},
+ {"PHUSTR_30", PHUSTR_30},
+ {"PHUSTR_31", PHUSTR_31},
+ {"PHUSTR_32", PHUSTR_32},
+ {"THUSTR_1", THUSTR_1},
+ {"THUSTR_2", THUSTR_2},
+ {"THUSTR_3", THUSTR_3},
+ {"THUSTR_4", THUSTR_4},
+ {"THUSTR_5", THUSTR_5},
+ {"THUSTR_6", THUSTR_6},
+ {"THUSTR_7", THUSTR_7},
+ {"THUSTR_8", THUSTR_8},
+ {"THUSTR_9", THUSTR_9},
+ {"THUSTR_10", THUSTR_10},
+ {"THUSTR_11", THUSTR_11},
+ {"THUSTR_12", THUSTR_12},
+ {"THUSTR_13", THUSTR_13},
+ {"THUSTR_14", THUSTR_14},
+ {"THUSTR_15", THUSTR_15},
+ {"THUSTR_16", THUSTR_16},
+ {"THUSTR_17", THUSTR_17},
+ {"THUSTR_18", THUSTR_18},
+ {"THUSTR_19", THUSTR_19},
+ {"THUSTR_20", THUSTR_20},
+ {"THUSTR_21", THUSTR_21},
+ {"THUSTR_22", THUSTR_22},
+ {"THUSTR_23", THUSTR_23},
+ {"THUSTR_24", THUSTR_24},
+ {"THUSTR_25", THUSTR_25},
+ {"THUSTR_26", THUSTR_26},
+ {"THUSTR_27", THUSTR_27},
+ {"THUSTR_28", THUSTR_28},
+ {"THUSTR_29", THUSTR_29},
+ {"THUSTR_30", THUSTR_30},
+ {"THUSTR_31", THUSTR_31},
+ {"THUSTR_32", THUSTR_32},
+ // part 6 - messages as a result of toggling states
+ {"AMSTR_FOLLOWON", AMSTR_FOLLOWON},
+ {"AMSTR_FOLLOWOFF", AMSTR_FOLLOWOFF},
+ {"AMSTR_GRIDON", AMSTR_GRIDON},
+ {"AMSTR_GRIDOFF", AMSTR_GRIDOFF},
+ {"AMSTR_MARKEDSPOT", AMSTR_MARKEDSPOT},
+ {"AMSTR_MARKSCLEARED", AMSTR_MARKSCLEARED},
+ {"STSTR_MUS", STSTR_MUS},
+ {"STSTR_NOMUS", STSTR_NOMUS},
+ {"STSTR_DQDON", STSTR_DQDON},
+ {"STSTR_DQDOFF", STSTR_DQDOFF},
+ {"STSTR_KFAADDED", STSTR_KFAADDED},
+ {"STSTR_FAADDED", STSTR_FAADDED},
+ {"STSTR_NCON", STSTR_NCON},
+ {"STSTR_NCOFF", STSTR_NCOFF},
+ {"STSTR_BEHOLD", STSTR_BEHOLD},
+ {"STSTR_BEHOLDX", STSTR_BEHOLDX},
+ {"STSTR_CHOPPERS", STSTR_CHOPPERS},
+ {"STSTR_CLEV", STSTR_CLEV},
+ // part 7 - episode intermission texts
+ {"E1TEXT", E1TEXT},
+ {"E2TEXT", E2TEXT},
+ {"E3TEXT", E3TEXT},
+ {"E4TEXT", E4TEXT},
+ {"C1TEXT", C1TEXT},
+ {"C2TEXT", C2TEXT},
+ {"C3TEXT", C3TEXT},
+ {"C4TEXT", C4TEXT},
+ {"C5TEXT", C5TEXT},
+ {"C6TEXT", C6TEXT},
+ {"P1TEXT", P1TEXT},
+ {"P2TEXT", P2TEXT},
+ {"P3TEXT", P3TEXT},
+ {"P4TEXT", P4TEXT},
+ {"P5TEXT", P5TEXT},
+ {"P6TEXT", P6TEXT},
+ {"T1TEXT", T1TEXT},
+ {"T2TEXT", T2TEXT},
+ {"T3TEXT", T3TEXT},
+ {"T4TEXT", T4TEXT},
+ {"T5TEXT", T5TEXT},
+ {"T6TEXT", T6TEXT},
+ // part 8 - creature names for the finale
+ {"CC_ZOMBIE", CC_ZOMBIE},
+ {"CC_SHOTGUN", CC_SHOTGUN},
+ {"CC_HEAVY", CC_HEAVY},
+ {"CC_IMP", CC_IMP},
+ {"CC_DEMON", CC_DEMON},
+ {"CC_LOST", CC_LOST},
+ {"CC_CACO", CC_CACO},
+ {"CC_HELL", CC_HELL},
+ {"CC_BARON", CC_BARON},
+ {"CC_ARACH", CC_ARACH},
+ {"CC_PAIN", CC_PAIN},
+ {"CC_REVEN", CC_REVEN},
+ {"CC_MANCU", CC_MANCU},
+ {"CC_ARCH", CC_ARCH},
+ {"CC_SPIDER", CC_SPIDER},
+ {"CC_CYBER", CC_CYBER},
+ {"CC_HERO", CC_HERO},
+ // part 9 - intermission tiled backgrounds
+ {"BGFLATE1", "FLOOR4_8"},
+ {"BGFLATE2", "SFLR6_1"},
+ {"BGFLATE3", "MFLR8_4"},
+ {"BGFLATE4", "MFLR8_3"},
+ {"BGFLAT06", "SLIME16"},
+ {"BGFLAT11", "RROCK14"},
+ {"BGFLAT20", "RROCK07"},
+ {"BGFLAT30", "RROCK17"},
+ {"BGFLAT15", "RROCK13"},
+ {"BGFLAT31", "RROCK19"},
+ {"BGCASTCALL", "BOSSBACK"},
+};
+
+static void *DEH_BEXStrStart(deh_context_t *context, char *line)
+{
+ char s[10];
+
+ if (sscanf(line, "%9s", s) == 0 || strncmp("[STRINGS]", s, sizeof(s)))
+ {
+ DEH_Warning(context, "Parse error on section start");
+ }
+
+ return NULL;
+}
+
+static void DEH_BEXStrParseLine(deh_context_t *context, char *line, void *tag)
+{
+ char *variable_name, *value;
+ int i;
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+ for (i = 0; i < arrlen(bex_stringtable); i++)
+ {
+ if (!strcmp(bex_stringtable[i].macro, variable_name))
+ {
+ DEH_AddStringReplacement(bex_stringtable[i].string, strdup(value));
+ }
+ }
+}
+
+deh_section_t deh_section_bexstr =
+{
+ "[STRINGS]",
+ NULL,
+ DEH_BEXStrStart,
+ DEH_BEXStrParseLine,
+ NULL,
+ NULL,
+};
--- a/src/doom/deh_doom.c
+++ b/src/doom/deh_doom.c
@@ -44,6 +44,8 @@
extern deh_section_t deh_section_thing;
// deh_weapon.c:
extern deh_section_t deh_section_weapon;
+// deh_bexstr.c:
+extern deh_section_t deh_section_bexstr;
//
// List of section types:
@@ -60,6 +62,7 @@
&deh_section_text,
&deh_section_thing,
&deh_section_weapon,
+ &deh_section_bexstr,
NULL
};