368 lines
8.3 KiB
C++
368 lines
8.3 KiB
C++
/*
|
|
** Command & Conquer Generals Zero Hour(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 = " ";
|
|
if (!line2)
|
|
line2 = " ";
|
|
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 = " ";
|
|
|
|
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;
|
|
}
|