Initial commit of Command & Conquer Generals and Command & Conquer Generals Zero Hour source code.

This commit is contained in:
LFeenanEA 2025-02-27 17:34:39 +00:00
parent 2e338c00cb
commit 3d0ee53a05
No known key found for this signature in database
GPG key ID: C6EBE8C2EA08F7E0
6072 changed files with 2283311 additions and 0 deletions

View file

@ -0,0 +1,367 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "debug.h"
#include "expander.h"
#include "KVPair.h"
#include "misc.h"
#include <iostream>
#include <list>
#include <stdlib.h>
#include <stdio.h>
//=============================================================================
std::string tableRow;
//=============================================================================
static void exitWait(void)
{
system("PAUSE");
}
//=============================================================================
#define LINESIZE 1024
static bool getNextLine(FILE *fp, char *line, int& frame, int& index) {
if (!fp)
return false;
char buf[LINESIZE];
while (fgets(buf, LINESIZE-1, fp) != NULL)
{
int len = strlen(buf);
if (buf[len-1] == '\n')
buf[len-1] = '\0';
if (sscanf(buf, "%d:%d ", &frame, &index) == 2)
{
strcpy(line, buf);
return true;
}
}
fclose(fp);
return false;
}
//=============================================================================
static std::string readInFile(const char *fname) {
FILE *fp = fopen(fname, "rt");
if (!fp)
return "";
std::string ret;
char buf[LINESIZE];
while (fgets(buf, LINESIZE-1, fp) != NULL)
{
ret.append(buf);
}
fclose(fp);
return ret;
}
//=============================================================================
static FILE *ofp = NULL;
void dumpQueued(void);
static void outputLine(const char *line)
{
dumpQueued();
//cout << line << endl;
if (ofp)
{
fputs(line, ofp);
}
}
//=============================================================================
static void outputLine(int frame, int index, int linkNum,
const char *class1, const char *line1,
const char *class2, const char *line2, bool same = false)
{
dumpQueued();
if (!line1)
line1 = "&nbsp;";
if (!line2)
line2 = "&nbsp;";
if (!class1)
class1 = "";
if (!class2)
class2 = "";
Expander e("((", "))");
e.addExpansion("LEFTCLASS", class1);
e.addExpansion("LEFTLINE", line1);
e.addExpansion("RIGHTCLASS", class2);
e.addExpansion("RIGHTLINE", line2);
if (same)
{
e.addExpansion("NAME", "");
e.addExpansion("PREV", intToString(linkNum-1));
e.addExpansion("NEXT", intToString(linkNum));
}
else
{
e.addExpansion("NAME", intToString(linkNum));
e.addExpansion("PREV", intToString(linkNum-1));
e.addExpansion("NEXT", intToString(linkNum+1));
}
std::string out;
e.expand(tableRow, out);
const char *buf = out.c_str();
//cout << buf << endl;
if (ofp)
{
fputs(buf, ofp);
}
}
//=============================================================================
std::list<std::string> queuedLines;
static void queueLine(int frame, int index, const char *line1)
{
if (!line1)
line1 = "&nbsp;";
Expander e("((", "))");
e.addExpansion("LEFTCLASS", "leftHistory");
e.addExpansion("LEFTLINE", line1);
e.addExpansion("RIGHTCLASS", "rightHistory");
e.addExpansion("RIGHTLINE", line1);
e.addExpansion("NAME", "");
e.addExpansion("PREV", intToString(0));
e.addExpansion("NEXT", intToString(1));
std::string out;
e.expand(tableRow, out);
queuedLines.push_back(out);
if (queuedLines.size() > 150)
queuedLines.pop_front();
//cout << buf << endl;
}
void dumpQueued(void)
{
while (!queuedLines.empty())
{
std::list<std::string>::iterator it = queuedLines.begin();
const char *buf = (*it).c_str();
//cout << buf << endl;
if (ofp)
{
fputs(buf, ofp);
}
queuedLines.pop_front();
}
}
//=============================================================================
int main(int argc, char *argv[])
{
atexit(exitWait);
const char *inFname[2];
const char *outFname = "out.html";
FILE *ifp[2] = {NULL, NULL};
std::string header, footer;
if (argc != 7)
{
cout << "Usage: munkeeDiff top.html row.html bottom.html in1.txt in2.txt out.txt" << endl;
header = readInFile("top.html");
tableRow = readInFile("row.html");
footer = readInFile("bottom.html");
inFname[0] = "test1.txt";
inFname[1] = "test2.txt";
//return 0;
}
else
{
header = readInFile(argv[1]);
tableRow = readInFile(argv[2]);
footer = readInFile(argv[3]);
inFname[0] = argv[4];
inFname[1] = argv[5];
outFname = argv[6];
}
ifp[0] = fopen(inFname[0], "rt");
if (!ifp[0])
{
cout << "could not open " << inFname[0] << endl;
return 1;
}
ifp[1] = fopen(inFname[1], "rt");
if (!ifp[1])
{
fclose(ifp[0]);
cout << "could not open " << inFname[1] << endl;
return 1;
}
ofp = fopen(outFname, "wt");
char lastLine[2][LINESIZE];
int lastFrame[2] = {-1, -1};
int lastIndex[2] = {-1, -1};
bool fileOk[2] = {true, true};
outputLine(header.c_str());
int linkNum = 1;
int numDiffs = 0;
bool seenRight = false;
bool seenLeft = false;
while (fileOk[0] || fileOk[1])
{
for (int i=0; i<2; ++i)
{
if (fileOk[i] == true && lastFrame[i] < 0)
{
fileOk[i] = getNextLine(ifp[i], lastLine[i],
lastFrame[i], lastIndex[i]);
}
}
if (fileOk[0] && fileOk[1])
{
if (lastFrame[0] < lastFrame[1] ||
(lastFrame[0]==lastFrame[1] && lastIndex[0] < lastIndex[1]))
{
//if (!seenLeft)
//cout << "Seen left on " << lastFrame[0] << ":" << lastIndex[0] << endl;
//seenLeft = true;
if (seenRight && seenLeft)
{
outputLine(lastFrame[0], lastIndex[0], linkNum++,
"leftOnly", lastLine[0], NULL, NULL);
++numDiffs;
}
lastFrame[0] = -1;
}
else if (lastFrame[1] < lastFrame[0] ||
(lastFrame[1]==lastFrame[0] && lastIndex[1] < lastIndex[0]))
{
//if (!seenRight)
//cout << "Seen right on " << lastFrame[1] << ":" << lastIndex[1] << endl;
//seenRight = true;
if (seenRight && seenLeft)
{
outputLine(lastFrame[1], lastIndex[1], linkNum++,
NULL, NULL, "rightOnly", lastLine[1]);
++numDiffs;
}
lastFrame[1] = -1;
}
else
{
int res = strcmp(lastLine[0], lastLine[1]);
if (res!=0)
{
if (!seenLeft || !seenRight)
cout << "Seen both on " << lastFrame[0] << ":" << lastIndex[0] << endl;
seenLeft = seenRight = true;
outputLine(lastFrame[0], lastIndex[0], linkNum++,
"leftDiff", lastLine[0], "rightDiff", lastLine[1]);
++numDiffs;
}
else
{
//if (!seenLeft || !seenRight)
// cout << "Seen both on " << lastFrame[0] << ":" << lastIndex[0] << endl;
//seenLeft = seenRight = true;
static bool printedFirst = false;
if (!printedFirst)
{
outputLine(lastFrame[0], lastIndex[0], linkNum,
"leftSame", lastLine[0], "rightSame", lastLine[1], true);
printedFirst = true;
}
else if (seenLeft && seenRight)
{
outputLine(lastFrame[0], lastIndex[0], linkNum,
"leftSame", lastLine[0], "rightSame", lastLine[1], true);
++numDiffs;
}
else
queueLine(lastFrame[0], lastIndex[0], lastLine[0]);
//++numDiffs;
}
lastFrame[0] = -1;
lastFrame[1] = -1;
}
}
else if (fileOk[0])
{
//if (!seenLeft)
//cout << "Seen left on " << lastFrame[0] << ":" << lastIndex[0] << endl;
//seenLeft = true;
if (seenRight && seenLeft)
{
outputLine(lastFrame[0], lastIndex[0], linkNum++,
"leftOnly", lastLine[0], NULL, NULL);
++numDiffs;
}
lastFrame[0] = -1;
}
else if (fileOk[1])
{
//if (!seenRight)
//cout << "Seen right on " << lastFrame[1] << ":" << lastIndex[1] << endl;
//seenRight = true;
if (seenRight && seenLeft)
{
outputLine(lastFrame[1], lastIndex[1], linkNum++,
NULL, NULL, "rightOnly", lastLine[1]);
++numDiffs;
}
lastFrame[1] = -1;
}
if (numDiffs > 1000)
break;
}
Expander e("((", "))");
e.addExpansion("LAST", intToString(linkNum-1));
e.addExpansion("BOTTOM", intToString(linkNum));
std::string out;
e.expand(footer, out);
outputLine(out.c_str());
if (ofp)
{
fclose(ofp);
}
return 0;
}

View file

@ -0,0 +1,152 @@
# Microsoft Developer Studio Project File - Name="CRCDiff" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=CRCDiff - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "CRCDiff.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "CRCDiff.mak" CFG="CRCDiff - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "CRCDiff - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "CRCDiff - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "CRCDiff"
# PROP Scc_LocalPath "."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "CRCDiff - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "CRCDiff - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
!ENDIF
# Begin Target
# Name "CRCDiff - Win32 Release"
# Name "CRCDiff - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\CRCDiff.cpp
# End Source File
# Begin Source File
SOURCE=.\debug.cpp
# End Source File
# Begin Source File
SOURCE=.\expander.cpp
# End Source File
# Begin Source File
SOURCE=.\KVPair.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\debug.h
# End Source File
# Begin Source File
SOURCE=.\expander.h
# End Source File
# Begin Source File
SOURCE=.\KVPair.h
# End Source File
# Begin Source File
SOURCE=.\misc.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# Begin Group "html"
# PROP Default_Filter ".css;.html"
# Begin Source File
SOURCE=.\bottom.html
# End Source File
# Begin Source File
SOURCE=.\out.html
# End Source File
# Begin Source File
SOURCE=.\row.html
# End Source File
# Begin Source File
SOURCE=.\style.css
# End Source File
# Begin Source File
SOURCE=.\top.html
# End Source File
# End Group
# End Target
# End Project

View file

@ -0,0 +1,197 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** 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 3 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, see <http://www.gnu.org/licenses/>.
*/
// ---------------------------------------------------------------------------
// File: KVPair.cpp
// Author: Matthew D. Campbell
// Creation Date: 9/4/2002
// Description: Key/Value Pair class
// ---------------------------------------------------------------------------
#include "misc.h"
#include "KVPair.h"
#include "debug.h"
#include <stdio.h>
std::string intToString(int val)
{
std::string s = "";
bool neg = (val < 0);
if (val < 0)
{
val = -val;
}
if (val == 0)
return "0";
char buf[2];
buf[1] = 0;
while (val)
{
buf[0] = '0' + val%10;
val /= 10;
s.insert(0, buf);
}
if (neg)
s.insert(0, "-");
return s;
}
static std::string trim(std::string s, const std::string& delim)
{
unsigned int i;
i = s.find_first_not_of(delim);
if (i != s.npos)
{
s = s.substr(i);
}
i = s.find_last_not_of(delim);
if (i>=0 && i<s.npos)
{
s = s.substr(0, i+1);
}
return s;
}
static KeyValueMap parseIntoKVPairs( std::string s, const std::string& delim )
{
KeyValueMap m;
bool done = false;
std::string kv, k, v;
while (!done)
{
int comma;
comma = s.find_first_of(delim, 0);
if (comma < 1)
{
done = true;
kv = s;
}
else
{
kv = s.substr(0, comma);
s = s.substr(comma+1);
}
s = trim(s, delim);
kv = trim(kv, delim);
if (!kv.empty())
{
int equals = kv.find_first_of('=', 0);
if (equals < 1)
{
done = true;
}
else
{
k = trim(trim(kv.substr(0, equals), delim), " \t");
v = trim(trim(kv.substr(equals+1), delim), " \t");
if (!k.empty() && !v.empty())
{
m[k] = v;
}
}
}
}
return m;
}
KVPairClass::KVPairClass( void )
{}
KVPairClass::KVPairClass( const std::string& in, const std::string& delim )
{
set( in, delim );
}
void KVPairClass::set( const std::string& in, const std::string& delim )
{
m_map = parseIntoKVPairs( in, delim );
}
void KVPairClass::readFromFile( const std::string& in, const std::string& delim )
{
m_map.clear();
FILE *fp = fopen(in.c_str(), "rb");
if (fp)
{
std::string s = "";
fseek(fp, 0, SEEK_END);
int len = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *buf = new char[len + 1];
memset(buf, 0, len+1);
fread(buf, 1, len, fp);
fclose(fp);
s.append(buf);
delete[] buf;
set(s, delim);
}
}
std::string KVPairClass::getStringVal( const std::string& key ) const
{
KeyValueMap::const_iterator it = m_map.find(key);
if (it == m_map.end())
{
return "";
}
return it->second;
}
bool KVPairClass::getString( const std::string& key, std::string& val ) const
{
std::string tmp = getStringVal(key);
if (tmp.empty())
{
return false;
}
val = tmp;
return true;
}
bool KVPairClass::getInt( const std::string& key, int& val ) const
{
std::string tmp = getStringVal(key);
if (tmp.empty())
{
return false;
}
val = atoi(tmp.c_str());
return true;
}
bool KVPairClass::getUnsignedInt( const std::string& key, unsigned int& val ) const
{
std::string tmp = getStringVal(key);
if (tmp.empty())
{
return false;
}
val = atoi(tmp.c_str());
return true;
}

View file

@ -0,0 +1,53 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** 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 3 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, see <http://www.gnu.org/licenses/>.
*/
// ---------------------------------------------------------------------------
// File: KVPair.h
// Author: Matthew D. Campbell
// Creation Date: 9/4/2002
// Description: Key/Value Pair class
// ---------------------------------------------------------------------------
#ifndef __KVPAIR_H__
#define __KVPAIR_H__
#include <map>
#include <string>
typedef std::map<std::string, std::string> KeyValueMap;
class KVPairClass
{
public:
KVPairClass( void );
KVPairClass( const std::string& in, const std::string& delim );
void set( const std::string& in, const std::string& delim );
void readFromFile( const std::string& in, const std::string& delim );
std::string getStringVal( const std::string& key ) const;
bool getString( const std::string& key, std::string& val ) const;
bool getInt( const std::string& key, int& val ) const;
bool getUnsignedInt( const std::string& key, unsigned int& val ) const;
protected:
KeyValueMap m_map;
};
#endif // __KVPAIR_H__

View file

@ -0,0 +1,5 @@
</table>
<hr>
<a name="#((BOTTOM))"><a name="#BOTTOM"><a href="#((LAST))">Last</a></a></a>
</body>
</html>

View file

@ -0,0 +1,43 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** 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 3 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, see <http://www.gnu.org/licenses/>.
*/
// FILE: debug.cpp ////////////////////////////////////////////////////////
// Minmal debug info
// Author: Matthew D. Campbell, Sept 2002
#include <windows.h>
#include "debug.h"
#include <cstdio>
#ifdef DEBUG
void DebugLog(const char *fmt, ...)
{
static char buffer[1024];
va_list va;
va_start( va, fmt );
vsnprintf(buffer, 1024, fmt, va );
buffer[1023] = 0;
va_end( va );
printf( "%s", buffer );
OutputDebugString( buffer );
}
#endif // DEBUG

View file

@ -0,0 +1,40 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** 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 3 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, see <http://www.gnu.org/licenses/>.
*/
// FILE: debug.h //////////////////////////////////////////////////////////////
// Minimal debug info
// Author: Matthew D. Campbell, Sept 2002
#ifndef __DEBUG_H__
#define __DEBUG_H__
#ifdef DEBUG
#include <cstdarg>
void DebugLog( const char *fmt, ... );
#define DEBUG_LOG(x) DebugLog x
#else // DEBUG
#define DEBUG_LOG(x) {}
#endif // DEBUG
#endif // __DEBUG_H__

View file

@ -0,0 +1,126 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** 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 3 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, see <http://www.gnu.org/licenses/>.
*/
// ---------------------------------------------------------------------------
// File: expander.cpp
// Author: Matthew D. Campbell
// Creation Date: 9/13/2002
// Description: Key/value pair template expansion class
// ---------------------------------------------------------------------------
#include "debug.h"
#include "expander.h"
Expander::Expander( const std::string& leftMarker, const std::string& rightMarker ) :
m_left(leftMarker), m_right(rightMarker)
{
}
void Expander::addExpansion( const std::string& key, const std::string val )
{
m_expansions[key] = val;
}
void Expander::clear( void )
{
m_expansions.clear();
}
void Expander::expand( const std::string& input,
std::string& output,
bool stripUnknown )
{
output = "";
unsigned int pos = input.find(m_left);
unsigned int lastpos = input.npos;
while (pos != input.npos)
{
// first, tack on the non-expansion part we just skipped over
if (pos > 0)
{
if (lastpos == input.npos)
{
// first time
output.append(input.substr(0, pos));
//DEBUG_LOG(("First time, output='%s'\n", output.c_str()));
}
else
{
// done this before
std::string sub = input.substr(lastpos, pos-lastpos);
//DEBUG_LOG(("*** lastpos = %d, pos=%d, sub='%s'\n", lastpos, pos, sub.c_str()));
output.append(sub);
//DEBUG_LOG(("output='%s'\n", output.c_str()));
}
}
else
{
//DEBUG_LOG(("pos == 0\n"));
}
// pos is the first position of a possible expansion
//DEBUG_LOG(("Looking for endpos via '%s' in '%s'\n", m_right.c_str(), input.substr(pos+m_left.length()).c_str()));
unsigned int endpos = input.find(m_right, pos+m_left.length());
//DEBUG_LOG(("substr is %d-%d of '%s'\n", pos, endpos, input.c_str()));
if (endpos != input.npos)
{
// found a complete token - expand it
std::string sub = input.substr(pos+m_left.length(), endpos-pos-m_left.length());
//DEBUG_LOG(("found token: '%s'\n", sub.c_str()));
ExpansionMap::iterator it = m_expansions.find(sub);
if (it == m_expansions.end())
{
// unknown key
if (stripUnknown)
{
//output.append("<<CENSORED>>");
}
else
{
output.append(input.substr(pos, endpos-pos+m_right.length()));
}
}
else
{
std::string toExpand = it->second;
std::string expanded = "";
//DEBUG_LOG(("###### expanding '%s'\n", toExpand.c_str()));
expand(toExpand, expanded, stripUnknown);
//DEBUG_LOG(("###### expanded '%s'\n", expanded.c_str()));
output.append(expanded);
}
}
lastpos = endpos+m_right.length();
pos = input.find(m_left, pos+m_left.length());
}
if (lastpos != input.npos)
{
// tack on last bit
output.append(input.substr(lastpos));
}
else if (!output.length() && pos == input.npos && lastpos == input.npos)
{
output = input;
}
}

View file

@ -0,0 +1,54 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** 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 3 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, see <http://www.gnu.org/licenses/>.
*/
// ---------------------------------------------------------------------------
// File: expander.h
// Author: Matthew D. Campbell
// Creation Date: 9/13/2002
// Description: Key/value pair template expansion class
// ---------------------------------------------------------------------------
#ifndef __EXPANDER_H__
#define __EXPANDER_H__
#include <map>
#include <hash_map>
#include <string>
typedef std::map<std::string, std::string> ExpansionMap;
class Expander
{
public:
Expander( const std::string& leftMarker, const std::string& rightMarker );
void addExpansion( const std::string& key, const std::string val );
void clear( void );
void expand( const std::string& input,
std::string& output,
bool stripUnknown = false );
protected:
ExpansionMap m_expansions;
std::string m_left;
std::string m_right;
};
#endif // __EXPANDER_H__

View file

@ -0,0 +1,34 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** 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 3 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, see <http://www.gnu.org/licenses/>.
*/
// ---------------------------------------------------------------------------
// File: misc.h
// Author: Matthew D. Campbell
// Creation Date: 9/12/2002
// Description: misc utils
// ---------------------------------------------------------------------------
#ifndef __MISC_H__
#define __MISC_H__
#include <string>
std::string intToString(int val);
#endif // __MISC_H__

View file

@ -0,0 +1,8 @@
<tr>
<td class=((LEFTCLASS))>((LEFTLINE))</td>
<td><a name="#((NAME))"><a href="#((PREV))">Prev</a></a></td>
<td><a href="#0">Top</a></td>
<td><a href="#BOTTOM">Bottom</a></td>
<td><a href="#((NEXT))">Next</a></td>
<td class=((RIGHTCLASS))>((RIGHTLINE))</td>
</tr>

View file

@ -0,0 +1,5 @@
td {font-family:monospace; font-size:x-small}
td.leftHistory {color:blue}
td.rightHistory {color:blue}
td.leftDiff {color:red}
td.rightDiff {color:red}

View file

@ -0,0 +1,9 @@
<html>
<head>
<LINK REL=StyleSheet HREF="style.css" TYPE="text/css">
</head>
<body>
<a name="#0">Top</a>
<a href="#1">First</a>
<hr>
<table width=100% border=2>