-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgameLinker.cpp
More file actions
225 lines (185 loc) · 6.75 KB
/
Copy pathgameLinker.cpp
File metadata and controls
225 lines (185 loc) · 6.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
//to build: g++ -o gameLinker.exe gameLinker.cpp
// INCLUDES ///////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <vector>
#include <string>
#include <filesystem>
#include <iostream>
#include <fstream>
#include <algorithm>
#include <sys/stat.h>
#include <sstream>
#include <cstdlib>
// NAMESPACE ////////////////////////////////////////////////////////////////////
namespace fs = std::filesystem;
using namespace std;
// TYPEDEFS /////////////////////////////////////////////////////////////////////
typedef struct {
std::string address;
std::string symbol;
} symbolDef;
// DEFINES //////////////////////////////////////////////////////////////////////
#define ENDLINE "\n***********************************************************\n\n"
// PROTOTYPES ///////////////////////////////////////////////////////////////////
void failOut (string msg);
bool parseViceMonListLine(const std::string& line, symbolDef &out);
std::string scanTemplateLine(const std::string& line);
std::string replaceVar(const std::string& line, std::size_t n);
std::string replaceExtsub(const std::string& line, std::size_t start, std::size_t end);
static std::string trim(const std::string& s);
// GLOBALS /////////////////////////////////////////////////////////////////////
std::string TEMPLATEFILE;
std::string MONLISTFILE;
std::string OUTFILE;
std::vector<symbolDef> symbolList;
int main(int argc, char *argv[])
{
cout << "\n\n***********************************************************\nFEARlabs Prog8 GameLinker Utility\n\n";
if (argc != 4)
{
std::cerr
<< "gameLinker: Invalid parameters\n"
<< "Usage: gameLinker <template-file> <monlist-file> <output-file>\n" << ENDLINE;
return EXIT_FAILURE;
}
// assign in the order TEMPLATEFILE MONLISTFILE OUTFILE
TEMPLATEFILE = argv[1];
MONLISTFILE = argv[2];
OUTFILE = argv[3];
//delete the output files
filesystem::remove(OUTFILE);
//open the vice-mon-list file
cout << "Open: " << MONLISTFILE << "\n";
ifstream viceMonListStream(MONLISTFILE);
if(!viceMonListStream)
failOut ("Cannot open .vice-mon-list file");
//injest the symbols + addresses
string line;
symbolDef e;
while (std::getline(viceMonListStream, line))
{
if (parseViceMonListLine(line, e))
{
e.address.insert(e.address.begin(), '$');
symbolList.push_back(e);
}
}
std::cout << "Collected " << symbolList.size() << " entries:\n\n";
//open the template file
cout << "Open: " << TEMPLATEFILE << "\n";
ifstream templateStream(TEMPLATEFILE);
if(!templateStream)
failOut ("Cannot open template file");
cout << "Parsing template and writing output...\n";
ofstream outputStream(OUTFILE);
if(!outputStream)
failOut ("Cannot open output file");
outputStream << "; Generated by FEARlabs Prog8 GameLinker from " << TEMPLATEFILE << "\n\n";
//now parse the template and build the output
while (std::getline(templateStream, line))
{
outputStream << scanTemplateLine(line) << "\n";
}
cout << "\n...DONE writing " << OUTFILE << ENDLINE;
return EXIT_SUCCESS;
}
bool parseViceMonListLine(const std::string& line, symbolDef &out)
{
std::istringstream iss(line);
std::string prefix;
if (!(iss >> prefix >> out.address >> out.symbol)) {
std::cout << "...Ignoring: \"" << line << "\"\n";
return false;
}
if (prefix != "al") {
std::cout << "...Ignoring: \"" << line << "\"\n";
return false;
}
std::string extra;
if (iss >> extra) {
std::cout << "...Ignoring: \"" << line << "\"\n";
return false;
}
return true;
}
std::string scanTemplateLine(const std::string& line)
{
// skip leading whitespace (spaces, tabs, etc.)
std::size_t pos = line.find_first_not_of(" \t\r\n\f\v");
if (pos == std::string::npos) return line;
// if first non-ws is '&'
if (line[pos] == '&') {
std::size_t eq = line.find('=', pos + 1);
if (eq != std::string::npos && eq + 1 < line.size()) {
return replaceVar(line, eq + 1);
}
}
// otherwise check for "extsub"
constexpr char keyword[] = "extsub";
constexpr std::size_t kwlen = sizeof(keyword) - 1;
if (line.size() >= pos + kwlen && line.compare(pos, kwlen, keyword) == 0) {
std::size_t eq = line.find('=', pos + kwlen);
if (eq != std::string::npos && eq > pos + kwlen) {
return replaceExtsub(line, pos + kwlen, eq - 1); // end is char before '='
}
}
return line;
}
std::string replaceVar(const std::string& line, std::size_t n)
{
// 1) extract & trim the symbol name
std::string sym = trim(line.substr(n));
// 2) look it up in symbolList
for (const auto& def : symbolList) {
if (def.symbol == sym) {
// 3) rebuild the line: keep everything up to `n`, then insert address
return line.substr(0, n) + " " + def.address;
}
}
// 4) not found → warn & return original
std::cout << "... WARNING: Symbol not found " << sym << "\n";
return line;
}
std::string replaceExtsub(const std::string& line, std::size_t start, std::size_t end)
{
// 1) grab & trim the raw symbol text
std::string raw = line.substr(start, end - start + 1);
std::string sym = trim(raw);
// 2) look up in symbolList
for (const auto& def : symbolList) {
if (def.symbol == sym) {
// 3a) compute original "field" width in columns
int origWidth = 0;
for (std::size_t i = start; i <= end; ++i) {
origWidth += (line[i] == '\t' ? 4 : 1);
}
// 3b) how many spaces to pad so address+pad == origWidth
int newLen = int(def.address.size()) + 1;
int padCount = origWidth - newLen;
if (padCount < 0) padCount = 0;
// 3c) build the replacement: address + padding
std::string replacement = " "
+ def.address
+ std::string(padCount, ' ');
// 3d) splice it back together
return line.substr(0, start)
+ replacement
+ line.substr(end + 1);
}
}
// 4) not found
std::cout << "... WARNING: Symbol not found " << sym << "\n";
return line;
}
static std::string trim(const std::string& s)
{
auto first = s.find_first_not_of(" \t\n\r");
if (first == std::string::npos) return "";
auto last = s.find_last_not_of (" \t\n\r");
return s.substr(first, last - first + 1);
}
void failOut (string msg)
{
cout << "\n*** ERROR! ***: " << msg << "\n" << ENDLINE;
exit(EXIT_FAILURE);
}