asar coverage - build #291


src/asar/
File: src/asar/main.cpp
Date: 2025-03-10 01:11:53
Lines:
460/561
82.0%
Functions:
19/22
86.4%
Branches:
505/901
56.0%

Line Branch Exec Source
1 // "because satanism is best defeated by summoning a bigger satan"
2 // ~Alcaro, 2019 (discussing Asar)
3 #include "addr2line.h"
4 #include "std-includes.h"
5 #include "libsmw.h"
6 #include "libstr.h"
7 #include "assocarr.h"
8 #include "autoarray.h"
9 #include "asar.h"
10 #include "virtualfile.h"
11 #include "warnings.h"
12 #include "platform/file-helpers.h"
13 #include "assembleblock.h"
14 #include "asar_math.h"
15 #include "macro.h"
16 #include <cstdint>
17
18 // randomdude999: remember to also update the .rc files (in res/windows/) when changing this.
19 // Couldn't find a way to automate this without shoving the version somewhere in the CMake files
20 const int asarver_maj=1;
21 const int asarver_min=9;
22 const int asarver_bug=1;
23 const bool asarver_beta=false;
24 bool default_math_pri=false;
25 bool default_math_round_off=false;
26 extern bool suppress_all_warnings;
27
28 #ifdef _I_RELEASE
29 extern char blockbetareleases[(!asarver_beta)?1:-1];
30 #endif
31 #ifdef _I_DEBUG
32 extern char blockreleasedebug[(asarver_beta)?1:-1];
33 #endif
34
35 unsigned const char * romdata_r;
36 int romlen_r;
37
38 int pass;
39
40 int optimizeforbank=-1;
41 int optimize_dp = optimize_dp_flag::NONE;
42 bool set_optimize_dp = false;
43 int dp_base = 0;
44 int optimize_address = optimize_address_flag::DEFAULT;
45 bool set_optimize_address = false;
46
47 string thisfilename;
48 int thisline;
49 const char * thisblock;
50
51 string callerfilename;
52 int callerline=-1;
53
54 bool errored=false;
55 bool ignoretitleerrors=false;
56
57 volatile int recursioncount=0;
58
59 virtual_filesystem* filesystem = nullptr;
60
61 AddressToLineMapping addressToLineMapping;
62
63 200 int get_version_int()
64 {
65 200 return asarver_maj * 10000 + asarver_min * 100 + asarver_bug;
66 }
67
68 56 bool setmapper()
69 {
70 56 int maxscore=-99999;
71 56 mapper_t bestmap=lorom;
72 56 mapper_t maps[]={lorom, hirom, exlorom, exhirom};
73
2/2
✓ Branch 0 taken 224 times.
✓ Branch 1 taken 56 times.
280 for (size_t mapid=0;mapid<sizeof(maps)/sizeof(maps[0]);mapid++)
74 {
75 224 mapper=maps[mapid];
76 224 int score=0;
77 224 int highbits=0;
78 224 bool foundnull=false;
79
2/2
✓ Branch 0 taken 4704 times.
✓ Branch 1 taken 224 times.
4928 for (int i=0;i<21;i++)
80 {
81 4704 unsigned char c=romdata[snestopc(0x00FFC0+i)];
82
3/4
✓ Branch 0 taken 3400 times.
✓ Branch 1 taken 1304 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3400 times.
4704 if (foundnull && c) score-=4;//according to some documents, NUL terminated names are possible - but they shouldn't appear in the middle of the name
83
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4704 times.
4704 if (c>=128) highbits++;
84
2/2
✓ Branch 0 taken 810 times.
✓ Branch 1 taken 3894 times.
4704 else if (is_upper(c)) score+=3;
85
2/2
✓ Branch 0 taken 324 times.
✓ Branch 1 taken 3570 times.
3894 else if (c==' ') score+=2;
86
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3570 times.
3570 else if (is_digit(c)) score+=1;
87
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3570 times.
3570 else if (is_lower(c)) score+=1;
88
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3570 times.
3570 else if (c=='-') score+=1;
89
1/2
✓ Branch 0 taken 3570 times.
✗ Branch 1 not taken.
3570 else if (!c) foundnull=true;
90 else score-=3;
91 }
92
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 224 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
224 if (highbits>0 && highbits<=14) score-=21;//high bits set on some, but not all, bytes = unlikely to be a ROM
93
4/4
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 168 times.
✓ Branch 3 taken 56 times.
280 if ((romdata[snestopc(0x00FFDE)]^romdata[snestopc(0x00FFDC)])!=0xFF ||
94
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
224 (romdata[snestopc(0x00FFDF)]^romdata[snestopc(0x00FFDD)])!=0xFF) score=-99999;//checksum doesn't match up to 0xFFFF? Not a ROM.
95 //too lazy to check the real checksum
96
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 168 times.
224 if (score>maxscore)
97 {
98 56 maxscore=score;
99 56 bestmap=mapper;
100 }
101 }
102 56 mapper=bestmap;
103
104 //detect oddball mappers
105 56 int mapperbyte=romdata[snestopc(0x00FFD5)];
106 56 int romtypebyte=romdata[snestopc(0x00FFD6)];
107
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 if (mapper==lorom)
108 {
109
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
56 if (mapperbyte==0x23 && (romtypebyte==0x32 || romtypebyte==0x34 || romtypebyte==0x35)) mapper=sa1rom;
110 }
111 56 return (maxscore>=0);
112 }
113
114 186 string getdecor()
115 {
116 186 string e;
117
2/4
✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 186 times.
✗ Branch 3 not taken.
186 if (thisfilename)
118 {
119
2/4
✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 186 times.
✗ Branch 3 not taken.
186 e+=STR thisfilename;
120
5/10
✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 186 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 186 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 186 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 186 times.
✗ Branch 9 not taken.
186 if (thisline!=-1) e+=STR ":"+dec(thisline+1);
121
10/18
✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 158 times.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 28 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 28 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 28 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 28 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 28 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 28 times.
✗ Branch 17 not taken.
186 if (callerfilename) e+=STR" (called from "+callerfilename+":"+dec(callerline+1)+")";
122
1/2
✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
186 e+=": ";
123 }
124 186 return e;
125 }
126
127 6 asar_error_id vfile_error_to_error_id(virtual_file_error vfile_error)
128 {
129
1/5
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 switch (vfile_error)
130 {
131 case vfe_doesnt_exist:
132 return error_id_file_not_found;
133 case vfe_access_denied:
134 return error_id_failed_to_open_file_access_denied;
135 6 case vfe_not_regular_file:
136 6 return error_id_failed_to_open_not_regular_file;
137 case vfe_unknown:
138 case vfe_none:
139 case vfe_num_errors:
140 return error_id_failed_to_open_file;
141 }
142
143 return error_id_failed_to_open_file;
144 }
145
146 6 virtual_file_error asar_get_last_io_error()
147 {
148
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (filesystem != nullptr)
149 {
150 6 return filesystem->get_last_error();
151 }
152
153 return vfe_unknown;
154 }
155
156 static bool freespaced;
157 952 static int getlenforlabel(int insnespos, int thislabel, bool exists)
158 {
159
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 952 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
952 if (warnxkas && (((unsigned int)(thislabel^insnespos)&0xFFFF0000)==0))
160 asar_throw_warning(1, warning_id_xkas_label_access);
161 952 unsigned int bank = thislabel>>16;
162 952 unsigned int word = thislabel&0xFFFF;
163 unsigned int relaxed_bank;
164
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 940 times.
952 if(optimizeforbank >= 0) {
165 12 relaxed_bank = optimizeforbank;
166 } else {
167
2/2
✓ Branch 0 taken 802 times.
✓ Branch 1 taken 138 times.
940 if((insnespos & 0xff000000) == 0) {
168 802 relaxed_bank = insnespos >> 16;
169 } else {
170
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 36 times.
138 if(freespace_is_freecode) relaxed_bank = 0;
171 36 else relaxed_bank = 0x40;
172 }
173 }
174
2/2
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 812 times.
952 if (!exists)
175 {
176
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 20 times.
140 if (!freespaced) freespaceextra++;
177 140 freespaced=true;
178 140 return 2;
179 }
180
5/6
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 800 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
812 else if((optimize_dp == optimize_dp_flag::RAM) && bank == 0x7E && (word-dp_base < 0x100))
181 {
182 6 return 1;
183 }
184
6/8
✓ Branch 0 taken 260 times.
✓ Branch 1 taken 546 times.
✓ Branch 2 taken 260 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 260 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 30 times.
✓ Branch 7 taken 230 times.
806 else if(optimize_dp == optimize_dp_flag::ALWAYS && (bank == 0x7E || !(bank & 0x40)) && (word-dp_base < 0x100))
185 {
186 30 return 1;
187 }
188 776 else if (
189 // if we should optimize ram accesses...
190
4/4
✓ Branch 0 taken 740 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 282 times.
✓ Branch 3 taken 458 times.
776 (optimize_address == optimize_address_flag::RAM || optimize_address == optimize_address_flag::MIRRORS)
191 // and we're in a bank with ram mirrors... (optimizeforbank=0x7E is checked later)
192
2/2
✓ Branch 0 taken 300 times.
✓ Branch 1 taken 18 times.
318 && !(relaxed_bank & 0x40)
193 // and the label is in low RAM
194
3/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 282 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
300 && bank == 0x7E && word < 0x2000)
195 {
196 18 return 2;
197 }
198 758 else if (
199 // if we should optimize mirrors...
200
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 482 times.
758 optimize_address == optimize_address_flag::MIRRORS
201 // we're in a bank with ram mirrors...
202
2/2
✓ Branch 0 taken 264 times.
✓ Branch 1 taken 12 times.
276 && !(relaxed_bank & 0x40)
203 // and the label is in a mirrored section
204
3/4
✓ Branch 0 taken 264 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 240 times.
264 && !(bank & 0x40) && word < 0x8000)
205 {
206 24 return 2;
207 }
208
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 726 times.
734 else if (optimizeforbank>=0)
209 {
210 // if optimizing for a specific bank:
211 // if the label is in freespace, never optimize
212
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if ((unsigned int)thislabel&0xFF000000) return 3;
213
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 else if (bank==(unsigned int)optimizeforbank) return 2;
214 8 else return 3;
215 }
216
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 606 times.
726 else if ((unsigned int)(thislabel|insnespos)&0xFF000000)
217 {
218 // optimize only if the label is in the same freespace
219
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 28 times.
120 if ((unsigned int)(thislabel^insnespos)&0xFF000000) return 3;
220 28 else return 2;
221 }
222
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 560 times.
606 else if ((thislabel^insnespos)&0xFF0000){ return 3; }
223 560 else { return 2;}
224 }
225
226 5698 bool is_hex_constant(const char* str){
227
2/2
✓ Branch 0 taken 4736 times.
✓ Branch 1 taken 962 times.
5698 if (*str=='$')
228 {
229 4736 str++;
230
2/2
✓ Branch 0 taken 14856 times.
✓ Branch 1 taken 4736 times.
19592 while(is_xdigit(*str)) {
231 14856 str++;
232 }
233
1/2
✓ Branch 0 taken 4736 times.
✗ Branch 1 not taken.
4736 if(*str=='\0'){
234 4736 return true;
235 }
236 }
237 962 return false;
238 }
239
240 4702 int getlen(const char * orgstr, bool optimizebankextraction)
241 {
242 4702 const char * str=orgstr;
243 4702 freespaced=false;
244
245 4702 const char* posneglabel = str;
246
1/2
✓ Branch 0 taken 4702 times.
✗ Branch 1 not taken.
4702 string posnegname = posneglabelname(&posneglabel, false);
247
248
3/4
✓ Branch 0 taken 4702 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2351 times.
✓ Branch 3 taken 2351 times.
4702 if (posnegname.length() > 0)
249 {
250
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 120 times.
126 if (*posneglabel != '\0') goto notposneglabel;
251
252
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 80 times.
160 if (!pass) return 2;
253 80 snes_label label_data;
254 // RPG Hacker: Umm... what kind of magic constant is this?
255 80 label_data.pos = 31415926;
256
2/4
✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 80 times.
✗ Branch 3 not taken.
80 bool found = labelval(posnegname, &label_data);
257
1/2
✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
80 return getlenforlabel(snespos, (int)label_data.pos, found);
258 }
259 4579 notposneglabel:
260 4582 int len=0;
261
2/2
✓ Branch 0 taken 4868 times.
✓ Branch 1 taken 4582 times.
9450 while (*str)
262 {
263 4868 int thislen=0;
264 4868 bool maybebankextraction=(str==orgstr);
265
2/2
✓ Branch 0 taken 3584 times.
✓ Branch 1 taken 1284 times.
4868 if (*str=='$')
266 {
267 3584 str++;
268 int i;
269
2/2
✓ Branch 0 taken 12888 times.
✓ Branch 1 taken 3584 times.
16472 for (i=0;is_xdigit(str[i]);i++);
270 //if (i&1) warn(S dec(i)+"-digit hex value");//blocked in getnum instead
271 3584 thislen=(i+1)/2;
272 3584 str+=i;
273 }
274
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1284 times.
1284 else if (*str=='%')
275 {
276 str++;
277 int i;
278 for (i=0;str[i]=='0' || str[i]=='1';i++);
279 //if (i&7) warn(S dec(i)+"-digit binary value");
280 thislen=(i+7)/8;
281 str+=i;
282 }
283
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1284 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1284 else if (str[0]=='\'' && str[2]=='\'')
284 {
285 thislen=1;
286 str+=3;
287 }
288
2/2
✓ Branch 0 taken 206 times.
✓ Branch 1 taken 1078 times.
1284 else if (is_digit(*str))
289 {
290 206 int val=strtol(str, const_cast<char**>(&str), 10);
291
1/2
✓ Branch 0 taken 206 times.
✗ Branch 1 not taken.
206 if (val>=0) thislen=1;
292
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 188 times.
206 if (val>=256) thislen=2;
293
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 206 times.
206 if (val>=65536) thislen=3;
294
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 206 times.
206 if (val>=16777216) thislen=4;
295 }
296
7/10
✓ Branch 0 taken 206 times.
✓ Branch 1 taken 872 times.
✓ Branch 2 taken 206 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 206 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 206 times.
✓ Branch 8 taken 872 times.
✓ Branch 9 taken 206 times.
1078 else if (is_alpha(*str) || *str=='_' || *str=='.' || *str=='?')
297 {
298 872 snes_label thislabel;
299
1/2
✓ Branch 0 taken 872 times.
✗ Branch 1 not taken.
872 bool exists=labelval(&str, &thislabel);
300
1/2
✓ Branch 0 taken 872 times.
✗ Branch 1 not taken.
872 thislen=getlenforlabel(snespos, (int)thislabel.pos, exists);
301 }
302 206 else str++;
303
4/4
✓ Branch 0 taken 924 times.
✓ Branch 1 taken 3944 times.
✓ Branch 2 taken 644 times.
✓ Branch 3 taken 280 times.
4868 if (optimizebankextraction && maybebankextraction &&
304
3/6
✓ Branch 0 taken 644 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 644 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 644 times.
644 (!strcmp(str, ">>16") || !strcmp(str, "/65536") || !strcmp(str, "/$10000")))
305 return 1;
306
2/2
✓ Branch 0 taken 4614 times.
✓ Branch 1 taken 254 times.
4868 if (thislen>len) len=thislen;
307 }
308
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4582 times.
4582 if (len>3) return 3;
309 4582 return len;
310 4702 }
311
312 struct strcompare {
313 bool operator() (const char * lhs, const char * rhs) const
314 {
315 return strcmp(lhs, rhs)<0;
316 }
317 };
318
319 struct stricompare {
320 bool operator() (const char * lhs, const char * rhs) const
321 {
322 return stricmp(lhs, rhs)<0;
323 }
324 };
325
326 struct sourcefile {
327 char** contents;
328 int numlines;
329 };
330
331 static assocarr<sourcefile> filecontents;
332 assocarr<string> defines;
333 // needs to be separate because defines is reset between parsing arguments and patching
334 assocarr<string> clidefines;
335 assocarr<string> builtindefines;
336
337 1792 bool validatedefinename(const char * name)
338 {
339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1792 times.
1792 if (!name[0]) return false;
340
2/2
✓ Branch 0 taken 18058 times.
✓ Branch 1 taken 1792 times.
19850 for (int i = 0;name[i];i++)
341 {
342
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18058 times.
18058 if (!is_ualnum(name[i])) return false;
343 }
344
345 1792 return true;
346 }
347
348 1507484 void resolvedefines(string& out, const char * start)
349 {
350
2/2
✓ Branch 0 taken 1507482 times.
✓ Branch 1 taken 2 times.
1507484 recurseblock rec;
351 1507482 const char * here=start;
352
2/2
✓ Branch 0 taken 8621360 times.
✓ Branch 1 taken 1507470 times.
10128830 while (*here)
353 {
354
4/4
✓ Branch 0 taken 3102 times.
✓ Branch 1 taken 8618258 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 3090 times.
8621360 if (*here=='"' && emulatexkas)
355 {
356
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 asar_throw_warning(0, warning_id_feature_deprecated, "xkas define quotes", "removing the quotes generally does what you want");
357
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 out+=*here++;
358
4/6
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 36 times.
✓ Branch 5 taken 12 times.
48 while (*here && *here!='"') out+=*here++;
359
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 out+=*here++;
360 }
361
4/4
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 8621300 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 42 times.
8621348 else if (here[0] == '\\' && here[1] == '\\')
362 {
363 // allow using \\ as escape sequence
364
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 out += "\\";
365 6 here += 2;
366 }
367
4/4
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 8621300 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 12 times.
8621342 else if (here[0] == '\\' && here[1] == '!')
368 {
369 // allow using \! to escape !
370
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 out+="!";
371 30 here += 2;
372 }
373
2/2
✓ Branch 0 taken 635196 times.
✓ Branch 1 taken 7986116 times.
8621312 else if (*here=='!')
374 {
375
7/10
✓ Branch 0 taken 212796 times.
✓ Branch 1 taken 422400 times.
✓ Branch 2 taken 211236 times.
✓ Branch 3 taken 1560 times.
✓ Branch 4 taken 211038 times.
✓ Branch 5 taken 198 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 211038 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
635196 bool first=(here==start || (here>=start+4 && here[-1]==' ' && here[-2]==':' && here[-3]==' '));//check if it's the start of a block
376 635196 string defname;
377 635196 here++;
378
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 635088 times.
635196 if (*here=='{')
379 {
380 108 here++;
381 108 string unprocessedname;
382 108 int braces=1;
383 while (true)
384 {
385
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 1080 times.
1152 if (*here=='{') braces++;
386
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 972 times.
1152 if (*here=='}') braces--;
387
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1152 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1152 if (!*here) asar_throw_error(0, error_type_line, error_id_mismatched_braces);
388
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 1044 times.
1152 if (!braces) break;
389
1/2
✓ Branch 0 taken 1044 times.
✗ Branch 1 not taken.
1044 unprocessedname+=*here++;
390 }
391 108 here++;
392
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 resolvedefines(defname, unprocessedname);
393
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
108 if (!validatedefinename(defname)) asar_throw_error(0, error_type_line, error_id_invalid_define_name);
394 108 }
395 else
396 {
397
3/4
✓ Branch 0 taken 654816 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 654816 times.
✓ Branch 3 taken 635088 times.
1289904 while (is_ualnum(*here)) defname+=*here++;
398 }
399
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 635196 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
635196 if (warnxkas && here[0]=='(' && here[1]==')')
400 asar_throw_warning(0, warning_id_xkas_eat_parentheses);
401 //if (emulatexkas && here[0]=='(' && here[1]==')') here+=2;
402
403
2/2
✓ Branch 0 taken 317598 times.
✓ Branch 1 taken 317598 times.
635196 if (first)
404 {
405 enum {
406 null,
407 append,
408 expand,
409 domath,
410 setifnotset,
411 } mode;
412 if(0);
413
2/2
✓ Branch 0 taken 270 times.
✓ Branch 1 taken 422130 times.
422400 else if (stribegin(here, " = ")) { here+=3; mode=null; }
414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 422130 times.
422130 else if (stribegin(here, " += ")) { here+=4; mode=append; }
415
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 422130 times.
422130 else if (stribegin(here, " := ")) { here+=4; mode=expand; }
416
2/2
✓ Branch 0 taken 210966 times.
✓ Branch 1 taken 211164 times.
422130 else if (stribegin(here, " #= ")) { here+=4; mode=domath; }
417
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 211158 times.
211164 else if (stribegin(here, " ?= ")) { here+=4; mode=setifnotset; }
418 211158 else goto notdefineset;
419
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 211242 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
211242 if (emulatexkas && mode != null) asar_throw_warning(0, warning_id_convert_to_asar);
420 //else if (stribegin(here, " equ ")) here+=5;
421 211242 string val;
422
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 211200 times.
211242 if (*here=='"')
423 {
424 42 here++;
425 while (true)
426 {
427
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 246 times.
294 if (*here=='"')
428 {
429
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
48 if (!here[1] || here[1]==' ') break;
430
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 else if (here[1]=='"') here++;
431 else asar_throw_error(0, error_type_line, error_id_broken_define_declaration);
432 }
433
1/2
✓ Branch 0 taken 252 times.
✗ Branch 1 not taken.
252 val+=*here++;
434 }
435 42 here++;
436 }
437 else
438 {
439
4/6
✓ Branch 0 taken 848736 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 848736 times.
✓ Branch 3 taken 211200 times.
✓ Branch 4 taken 848736 times.
✗ Branch 5 not taken.
1059936 while (*here && *here!=' ') val+=*here++;
440 }
441 //if (strqchr(val.data(), ';')) *strqchr(val.data(), ';')=0;
442
2/8
✗ Branch 0 not taken.
✓ Branch 1 taken 211242 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 211242 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
211242 if (*here && !stribegin(here, " : ")) asar_throw_error(0, error_type_line, error_id_broken_define_declaration);
443
4/8
✓ Branch 0 taken 211242 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 211242 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 211242 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 211242 times.
✗ Branch 7 not taken.
211242 clean(val);
444
445 // RPG Hacker: throw an error if we're trying to overwrite built-in defines.
446
3/4
✓ Branch 0 taken 211242 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 211236 times.
211242 if (builtindefines.exists(defname))
447 {
448
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 asar_throw_error(0, error_type_line, error_id_overriding_builtin_define, defname.data());
449 }
450
451
3/6
✓ Branch 0 taken 264 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 210966 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
211236 switch (mode)
452 {
453 264 case null:
454 {
455
2/4
✓ Branch 0 taken 264 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 264 times.
✗ Branch 3 not taken.
264 defines.create(defname) = val;
456 264 break;
457 }
458 case append:
459 {
460 if (!defines.exists(defname)) asar_throw_error(0, error_type_line, error_id_define_not_found, defname.data());
461 string oldval = defines.find(defname);
462 val=oldval+val;
463 defines.create(defname) = val;
464 break;
465 }
466 case expand:
467 {
468 string newval;
469 resolvedefines(newval, val);
470 defines.create(defname) = newval;
471 break;
472 }
473 210966 case domath:
474 {
475 210966 string newval;
476
1/2
✓ Branch 0 taken 210966 times.
✗ Branch 1 not taken.
210966 resolvedefines(newval, val);
477
1/2
✓ Branch 0 taken 210966 times.
✗ Branch 1 not taken.
210966 double num= getnumdouble(newval);
478
5/6
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 210954 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
210966 if (foundlabel && !foundlabel_static) asar_throw_error(0, error_type_line, error_id_define_label_math);
479
3/6
✓ Branch 0 taken 210960 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 210960 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 210960 times.
✗ Branch 5 not taken.
210960 defines.create(defname) = ftostr(num);
480 210960 break;
481 210966 }
482 6 case setifnotset:
483 {
484
4/8
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
6 if (!defines.exists(defname)) defines.create(defname) = val;
485 6 break;
486 }
487 }
488 211242 }
489 else
490 {
491 318375 notdefineset:
492
4/6
✓ Branch 0 taken 423954 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 423918 times.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
423954 if (!defname) out+="!";
493 else
494 {
495
2/6
✓ Branch 0 taken 423918 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 423918 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
423918 if (!defines.exists(defname)) asar_throw_error(0, error_type_line, error_id_define_not_found, defname.data());
496 else {
497
2/4
✓ Branch 0 taken 423918 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 423918 times.
✗ Branch 3 not taken.
423918 string thisone = defines.find(defname);
498
1/2
✓ Branch 0 taken 423918 times.
✗ Branch 1 not taken.
423918 resolvedefines(out, thisone);
499 423918 }
500 }
501 }
502 635196 }
503
1/2
✓ Branch 0 taken 7986116 times.
✗ Branch 1 not taken.
7986116 else out+=*here++;
504 }
505 2261217 }
506
507 int repeatnext=1;
508
509 bool moreonline;
510 bool moreonlinecond;
511 int fakeendif;
512 bool asarverallowed;
513 bool istoplevel;
514
515 873878 void assembleline(const char * fname, int linenum, const char * line)
516 {
517
1/2
✓ Branch 0 taken 873878 times.
✗ Branch 1 not taken.
873878 recurseblock rec;
518 873878 bool moreonlinetmp=moreonline;
519 // randomdude999: redundant, assemblefile already converted the path to absolute
520 //string absolutepath = filesystem->create_absolute_path("", fname);
521
1/2
✓ Branch 0 taken 873878 times.
✗ Branch 1 not taken.
873878 string absolutepath = fname;
522
1/2
✓ Branch 0 taken 873878 times.
✗ Branch 1 not taken.
873878 thisfilename = absolutepath;
523 873878 thisline=linenum;
524 873878 thisblock= nullptr;
525 873878 single_line_for_tracker = 1;
526 try
527 {
528 873878 string tmp;
529
7/8
✓ Branch 0 taken 1032 times.
✓ Branch 1 taken 872846 times.
✓ Branch 2 taken 948 times.
✓ Branch 3 taken 84 times.
✓ Branch 4 taken 906 times.
✓ Branch 5 taken 42 times.
✓ Branch 6 taken 906 times.
✗ Branch 7 not taken.
873878 if(inmacro && numif == numtrue) tmp = replace_macro_args(line);
530
1/2
✓ Branch 0 taken 872930 times.
✗ Branch 1 not taken.
872930 else tmp = line;
531
4/8
✓ Branch 0 taken 873836 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 873836 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 873836 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 873836 times.
✗ Branch 7 not taken.
873836 clean(tmp);
532 873836 string out;
533
4/4
✓ Branch 0 taken 872162 times.
✓ Branch 1 taken 1674 times.
✓ Branch 2 taken 872148 times.
✓ Branch 3 taken 14 times.
873836 if (numif==numtrue) resolvedefines(out, tmp);
534
1/2
✓ Branch 0 taken 1674 times.
✗ Branch 1 not taken.
1674 else out=tmp;
535 // recheck quotes - defines can mess those up sometimes
536
4/6
✓ Branch 0 taken 873822 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 873816 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
873822 if (!confirmquotes(out)) asar_throw_error(0, error_type_line, error_id_mismatched_quotes);
537
1/2
✓ Branch 0 taken 873816 times.
✗ Branch 1 not taken.
873816 out.qreplace(": :", ": :", true);
538 //puts(out);
539
1/2
✓ Branch 0 taken 873816 times.
✗ Branch 1 not taken.
873816 autoptr<char**> blocks=qsplit(out.temp_raw(), " : ");
540 873816 moreonline=true;
541 873816 moreonlinecond=true;
542 873816 fakeendif=0;
543
2/2
✓ Branch 0 taken 875430 times.
✓ Branch 1 taken 873316 times.
1748746 for (int block=0;moreonline;block++)
544 {
545 875430 moreonline=(blocks[block+1] != nullptr);
546 875430 int repeatthis=repeatnext;
547 875430 repeatnext=1;
548
2/2
✓ Branch 0 taken 875430 times.
✓ Branch 1 taken 874930 times.
1750360 for (int i=0;i<repeatthis;i++)
549 {
550 try
551 {
552
1/2
✓ Branch 0 taken 875430 times.
✗ Branch 1 not taken.
875430 string stripped_block = blocks[block];
553
1/2
✓ Branch 0 taken 875430 times.
✗ Branch 1 not taken.
875430 strip_both(stripped_block, ' ', true);
554
555 875430 thisline=linenum;//do not optimize, this one is recursive
556 875430 thisblock = stripped_block.data();
557 875430 bool isspecialline = false;
558
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 875418 times.
875430 if (thisblock[0] == '@')
559 {
560
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 asar_throw_warning(0, warning_id_feature_deprecated, "prefixing Asar commands with @ or ;@", "remove the @ or ;@ prefix");
561
562 12 isspecialline = true;
563 12 thisblock++;
564
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 while (is_space(*thisblock))
565 {
566 thisblock++;
567 }
568 }
569
2/2
✓ Branch 0 taken 874788 times.
✓ Branch 1 taken 642 times.
875430 assembleblock(thisblock, isspecialline);
570
2/2
✓ Branch 0 taken 874786 times.
✓ Branch 1 taken 2 times.
874788 checkbankcross();
571 875430 }
572
2/2
✓ Branch 0 taken 500 times.
✓ Branch 1 taken 144 times.
644 catch (errblock&) {}
573
6/6
✓ Branch 0 taken 653166 times.
✓ Branch 1 taken 221764 times.
✓ Branch 2 taken 653154 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 653154 times.
✓ Branch 5 taken 221776 times.
874930 if (blocks[block][0]!='\0' && blocks[block][0]!='@') asarverallowed=false;
574 }
575
2/2
✓ Branch 0 taken 872908 times.
✓ Branch 1 taken 2022 times.
874930 if(single_line_for_tracker == 1) single_line_for_tracker = 0;
576 }
577
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 873316 times.
873316 if(fakeendif)
578 {
579 thisline = linenum;
580 thisblock = blocks[0];
581 asar_throw_warning(0, warning_id_feature_deprecated, "inline if statements without endif", "Add an \" : endif\" at the end of the line");
582 if (numif==numtrue) numtrue--;
583 numif--;
584 }
585 874898 }
586
2/2
✓ Branch 0 taken 502 times.
✓ Branch 1 taken 60 times.
562 catch (errline&) {}
587 873376 moreonline=moreonlinetmp;
588 1311068 }
589
590 int incsrcdepth=0;
591
592 // Returns true if a file is protected via
593 // an "includeonce".
594 1240 bool file_included_once(const char* file)
595 {
596
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 1198 times.
1438 for (int i = 0; i < includeonce.count; ++i)
597 {
598
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 198 times.
240 if (includeonce[i] == file)
599 {
600 42 return true;
601 }
602 }
603
604 1198 return false;
605 }
606
607 1210 void assemblefile(const char * filename, bool toplevel)
608 {
609 1210 incsrcdepth++;
610
1/2
✓ Branch 0 taken 1210 times.
✗ Branch 1 not taken.
1210 string absolutepath = filesystem->create_absolute_path(thisfilename, filename);
611
612
3/4
✓ Branch 0 taken 1210 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 1168 times.
1210 if (file_included_once(absolutepath))
613 {
614 42 return;
615 }
616
617
1/2
✓ Branch 0 taken 1168 times.
✗ Branch 1 not taken.
1168 string prevthisfilename = thisfilename;
618
1/2
✓ Branch 0 taken 1168 times.
✗ Branch 1 not taken.
1168 thisfilename = absolutepath;
619 1168 int prevline = thisline;
620 1168 thisline=-1;
621 1168 const char* prevthisblock = thisblock;
622 1168 thisblock= nullptr;
623 584 sourcefile file;
624 1168 file.contents = nullptr;
625 1168 file.numlines = 0;
626 1168 int startif=numif;
627
3/4
✓ Branch 0 taken 1168 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 230 times.
✓ Branch 3 taken 938 times.
1168 if (!filecontents.exists(absolutepath))
628 {
629
1/2
✓ Branch 0 taken 230 times.
✗ Branch 1 not taken.
230 char * temp= readfile(absolutepath, "");
630
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 230 times.
230 if (!temp)
631 {
632 // RPG Hacker: This is so that we hopefully always end up with a proper decor
633 // and get better error messages.
634 thisfilename = prevthisfilename;
635 thisline = prevline;
636 thisblock = prevthisblock;
637
638 asar_throw_error(0, error_type_null, vfile_error_to_error_id(asar_get_last_io_error()), filename);
639
640 return;
641 }
642
1/2
✓ Branch 0 taken 230 times.
✗ Branch 1 not taken.
230 file.contents =split(temp, "\n");
643
2/2
✓ Branch 0 taken 9494 times.
✓ Branch 1 taken 230 times.
9724 for (int i=0;file.contents[i];i++)
644 {
645 9494 file.numlines++;
646 9494 char * line= file.contents[i];
647 9494 char * comment=line;
648 9494 comment = strqchr(comment, ';');
649
2/2
✓ Branch 0 taken 2610 times.
✓ Branch 1 taken 9494 times.
12104 while (comment != nullptr)
650 {
651 2610 const char* comment_end = comment + strlen(comment);
652
2/2
✓ Branch 0 taken 2604 times.
✓ Branch 1 taken 6 times.
2610 if (comment_end - comment >= 2
653
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2604 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2604 && comment[1] == '[' && comment[2] == '['
654 && (comment_end[-1] != ']' || comment_end[-2] != ']'))
655 {
656 asar_throw_warning(0, warning_id_feature_deprecated, "comments starting with ;[[", "\";[[\" marks the start of a block comments in Asar 2.0 - either remove the \"[[\", or make sure the commented line ends on \"]]\"");
657 }
658
659
2/2
✓ Branch 0 taken 2606 times.
✓ Branch 1 taken 4 times.
2610 if (comment[1]!='@')
660 {
661 2606 comment[0]='\0';
662 }
663 else
664 {
665 4 comment[0] = ' ';
666 }
667 2610 comment = strqchr(comment, ';');
668 }
669
2/2
✓ Branch 0 taken 1408 times.
✓ Branch 1 taken 9494 times.
10902 while (strqchr(line, '\t')) *strqchr(line, '\t')=' ';
670
4/6
✓ Branch 0 taken 9494 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 9492 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
9494 if (!confirmquotes(line)) { thisline = i; thisblock = line; asar_throw_error(0, error_type_null, error_id_mismatched_quotes); line[0] = '\0'; }
671
1/2
✓ Branch 0 taken 9494 times.
✗ Branch 1 not taken.
9494 itrim(line, " ", " ", true); //todo make use strip
672 }
673
2/2
✓ Branch 0 taken 9494 times.
✓ Branch 1 taken 230 times.
9724 for(int i=0;file.contents[i];i++)
674 {
675 9494 char* line = file.contents[i];
676
7/8
✓ Branch 0 taken 1326 times.
✓ Branch 1 taken 8178 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 1316 times.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 9494 times.
9504 for (int j=1;strqrchr(line, ',') && !strqrchr(line, ',')[1] && file.contents[i+j];j++)
677 {
678 // not using strcat because the source and dest overlap here
679 10 char* otherline = file.contents[i+j];
680 10 char* line_end = line + strlen(line);
681
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 10 times.
138 while(*otherline) *line_end++ = *otherline++;
682 10 *line_end = '\0';
683 static char nullstr[]="";
684 10 file.contents[i+j]=nullstr;
685 }
686 }
687
1/2
✓ Branch 0 taken 230 times.
✗ Branch 1 not taken.
230 filecontents.create(absolutepath) = file;
688 } else { // filecontents.exists(absolutepath)
689
1/2
✓ Branch 0 taken 938 times.
✗ Branch 1 not taken.
938 file = filecontents.find(absolutepath);
690 }
691 1168 bool in_macro_def=false;
692 1168 asarverallowed=true;
693
3/4
✓ Branch 0 taken 873542 times.
✓ Branch 1 taken 666 times.
✓ Branch 2 taken 873542 times.
✗ Branch 3 not taken.
874208 for (int i=0;file.contents[i] && i<file.numlines;i++)
694 {
695 try
696 {
697
1/2
✓ Branch 0 taken 873542 times.
✗ Branch 1 not taken.
873542 thisfilename= absolutepath;
698 873542 thisline=i;
699 873542 thisblock= nullptr;
700 873542 istoplevel=toplevel;
701
5/6
✓ Branch 0 taken 156 times.
✓ Branch 1 taken 873386 times.
✓ Branch 2 taken 156 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 156 times.
✓ Branch 5 taken 873386 times.
873542 if (stribegin(file.contents[i], "macro ") && numif==numtrue)
702 {
703 // RPG Hacker: Commented out for Asar 1.81 backwards-compatibility.
704 // (From Asar 2.0 onwards, nested macro definitions will be well-defined).
705
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
156 if (in_macro_def /*|| inmacro*/) asar_throw_error(0, error_type_line, error_id_nested_macro_definition);
706 156 in_macro_def=true;
707
4/4
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 104 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 2 times.
156 if (!pass) startmacro(file.contents[i]+6);
708 }
709
7/8
✓ Branch 0 taken 436771 times.
✓ Branch 1 taken 436615 times.
✓ Branch 2 taken 156 times.
✓ Branch 3 taken 436615 times.
✓ Branch 4 taken 78 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 78 times.
✓ Branch 7 taken 436615 times.
873386 else if (!stricmp(file.contents[i], "endmacro") && numif==numtrue)
710 {
711
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
156 if (!in_macro_def) asar_throw_error(0, error_type_line, error_id_misplaced_endmacro);
712 156 in_macro_def=false;
713
3/4
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 104 times.
✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
156 if (!pass) endmacro(true);
714 }
715
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 872846 times.
873230 else if (in_macro_def)
716 {
717
3/4
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 256 times.
✓ Branch 2 taken 128 times.
✗ Branch 3 not taken.
384 if (!pass) tomacro(file.contents[i]);
718 }
719 else
720 {
721 872846 int prevnumif = numif;
722 872846 string connectedline;
723
1/2
✓ Branch 0 taken 872846 times.
✗ Branch 1 not taken.
872846 int skiplines = getconnectedlines<char**>(file.contents, i, connectedline);
724
2/2
✓ Branch 0 taken 872344 times.
✓ Branch 1 taken 502 times.
872846 assembleline(absolutepath, i, connectedline);
725
1/2
✓ Branch 0 taken 872344 times.
✗ Branch 1 not taken.
872344 thisfilename = absolutepath;
726 872344 i += skiplines;
727
15/18
✓ Branch 0 taken 449476 times.
✓ Branch 1 taken 422868 times.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 449416 times.
✓ Branch 4 taken 422928 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 211976 times.
✓ Branch 7 taken 210952 times.
✓ Branch 8 taken 211976 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 440 times.
✓ Branch 11 taken 211536 times.
✓ Branch 12 taken 211392 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 210960 times.
✓ Branch 15 taken 432 times.
✓ Branch 16 taken 210960 times.
✓ Branch 17 taken 661384 times.
872344 if ((numif != prevnumif || single_line_for_tracker == 3) && (whilestatus[numif].iswhile || whilestatus[numif].is_for) && whilestatus[numif].cond)
728
1/2
✓ Branch 0 taken 210960 times.
✗ Branch 1 not taken.
210960 i = whilestatus[numif].startline - 1;
729 872846 }
730 }
731
2/2
✓ Branch 0 taken 502 times.
✓ Branch 1 taken 2 times.
504 catch (errline&) {}
732 }
733 666 thisline++;
734 666 thisblock= nullptr;
735
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 666 times.
666 if (in_macro_def)
736 {
737 asar_throw_error(0, error_type_null, error_id_unclosed_macro);
738 if (!pass) endmacro(false);
739 }
740
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 666 times.
666 if (repeatnext!=1)
741 {
742 repeatnext=1;
743 asar_throw_error(0, error_type_null, error_id_rep_at_file_end);
744 }
745
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 666 times.
666 if (numif!=startif)
746 {
747 numif=startif;
748 numtrue=startif;
749 asar_throw_error(0, error_type_null, error_id_unclosed_if);
750 }
751 666 incsrcdepth--;
752
3/4
✓ Branch 0 taken 666 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 666 times.
✓ Branch 3 taken 42 times.
1712 }
753
754 200 void parse_std_includes(const char* textfile, autoarray<string>& outarray)
755 {
756 200 char* content = readfilenative(textfile);
757
758
1/2
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
200 if (content != nullptr)
759 {
760 200 char* pos = content;
761
762
2/2
✓ Branch 0 taken 400 times.
✓ Branch 1 taken 200 times.
600 while (pos[0] != '\0')
763 {
764 400 string stdinclude;
765
766 do
767 {
768
3/4
✓ Branch 0 taken 9900 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9700 times.
✓ Branch 3 taken 200 times.
9900 if (pos[0] != '\r' && pos[0] != '\n')
769 {
770
1/2
✓ Branch 0 taken 9700 times.
✗ Branch 1 not taken.
9700 stdinclude += pos[0];
771 }
772 9900 pos++;
773
4/4
✓ Branch 0 taken 9700 times.
✓ Branch 1 taken 200 times.
✓ Branch 2 taken 9500 times.
✓ Branch 3 taken 200 times.
9900 } while (pos[0] != '\0' && pos[0] != '\n');
774
775
2/4
✓ Branch 0 taken 400 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 400 times.
✗ Branch 3 not taken.
400 stdinclude = strip_whitespace(stdinclude);
776
777
2/2
✓ Branch 0 taken 200 times.
✓ Branch 1 taken 200 times.
400 if (stdinclude != "")
778 {
779
2/4
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 200 times.
200 if (!path_is_absolute(stdinclude))
780 {
781 stdinclude = dir(textfile) + stdinclude;
782 }
783
2/4
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 200 times.
✗ Branch 3 not taken.
200 outarray.append(normalize_path(stdinclude));
784 }
785 400 }
786
787 200 free(content);
788 }
789 200 }
790
791 200 void parse_std_defines(const char* textfile)
792 {
793
794 // RPG Hacker: add built-in defines.
795 // (They're not really standard defines, but I was lazy and this was
796 // one convenient place for doing it).
797 200 builtindefines.create("assembler") = "asar";
798
3/6
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 200 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 200 times.
✗ Branch 5 not taken.
200 builtindefines.create("assembler_ver") = dec(get_version_int());
799
800
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
200 if(textfile == nullptr) return;
801
802 200 char* content = readfilenative(textfile);
803
804
1/2
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
200 if (content != nullptr)
805 {
806 200 char* pos = content;
807
2/2
✓ Branch 0 taken 1200 times.
✓ Branch 1 taken 200 times.
1400 while (*pos != 0) {
808 1200 string define_name;
809 1200 string define_val;
810
811
4/4
✓ Branch 0 taken 12000 times.
✓ Branch 1 taken 800 times.
✓ Branch 2 taken 11600 times.
✓ Branch 3 taken 400 times.
12800 while (*pos != '=' && *pos != '\n') {
812
1/2
✓ Branch 0 taken 11600 times.
✗ Branch 1 not taken.
11600 define_name += *pos;
813 11600 pos++;
814 }
815
3/4
✓ Branch 0 taken 1200 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 800 times.
✓ Branch 3 taken 400 times.
1200 if (*pos != 0 && *pos != '\n') pos++; // skip =
816
3/4
✓ Branch 0 taken 5400 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4200 times.
✓ Branch 3 taken 1200 times.
5400 while (*pos != 0 && *pos != '\n') {
817
1/2
✓ Branch 0 taken 4200 times.
✗ Branch 1 not taken.
4200 define_val += *pos;
818 4200 pos++;
819 }
820
1/2
✓ Branch 0 taken 1200 times.
✗ Branch 1 not taken.
1200 if (*pos != 0)
821 1200 pos++; // skip \n
822 // clean define_name
823
2/4
✓ Branch 0 taken 1200 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1200 times.
✗ Branch 3 not taken.
1200 define_name = strip_whitespace(define_name);
824
2/4
✓ Branch 0 taken 1200 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1200 times.
✗ Branch 3 not taken.
1200 define_name = strip_prefix(define_name, '!', false); // remove leading ! if present
825
826
2/2
✓ Branch 0 taken 200 times.
✓ Branch 1 taken 1000 times.
1200 if (define_name == "")
827 {
828
1/2
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
200 if (define_val == "")
829 {
830 200 continue;
831 }
832
833 asar_throw_error(pass, error_type_null, error_id_stddefines_no_identifier);
834 }
835
836
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1000 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1000 if (!validatedefinename(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_invalid, "stddefines.txt", define_name.data());
837
838 // clean define_val
839 1000 const char* defval = define_val.data();
840 1000 string cleaned_defval;
841
842
2/2
✓ Branch 0 taken 200 times.
✓ Branch 1 taken 800 times.
1000 if (*defval == 0) {
843 // no value
844
2/6
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 200 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
200 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
845
2/4
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 200 times.
✗ Branch 3 not taken.
200 clidefines.create(define_name) = "";
846 200 continue;
847 }
848
849
3/4
✓ Branch 0 taken 400 times.
✓ Branch 1 taken 800 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 800 times.
1200 while (*defval == ' ' || *defval == '\t') defval++; // skip whitespace in beginning
850
2/2
✓ Branch 0 taken 200 times.
✓ Branch 1 taken 600 times.
800 if (*defval == '"') {
851 200 defval++; // skip opening quote
852
3/4
✓ Branch 0 taken 2600 times.
✓ Branch 1 taken 200 times.
✓ Branch 2 taken 2600 times.
✗ Branch 3 not taken.
2800 while (*defval != '"' && *defval != 0)
853
1/2
✓ Branch 0 taken 2600 times.
✗ Branch 1 not taken.
2600 cleaned_defval += *defval++;
854
855
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
200 if (*defval == 0) {
856 asar_throw_error(pass, error_type_null, error_id_mismatched_quotes);
857 }
858 200 defval++; // skip closing quote
859
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 200 times.
200 while (*defval == ' ' || *defval == '\t') defval++; // skip whitespace
860
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
200 if (*defval != 0 && *defval != '\n')
861 asar_throw_error(pass, error_type_null, error_id_stddefine_after_closing_quote);
862
863
2/6
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 200 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
200 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
864
2/4
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 200 times.
✗ Branch 3 not taken.
200 clidefines.create(define_name) = cleaned_defval;
865 200 continue;
866 }
867 else
868 {
869 // slightly hacky way to remove trailing whitespace
870 600 const char* defval_end = strchr(defval, '\n'); // slightly hacky way to get end of string or newline
871
1/2
✓ Branch 0 taken 600 times.
✗ Branch 1 not taken.
600 if (!defval_end) defval_end = strchr(defval, 0);
872 600 defval_end--;
873
3/4
✓ Branch 0 taken 200 times.
✓ Branch 1 taken 600 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 600 times.
800 while (*defval_end == ' ' || *defval_end == '\t') defval_end--;
874
2/4
✓ Branch 0 taken 600 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 600 times.
✗ Branch 3 not taken.
600 cleaned_defval = string(defval, (int)(defval_end - defval + 1));
875
876
2/6
✓ Branch 0 taken 600 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 600 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
600 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
877
2/4
✓ Branch 0 taken 600 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 600 times.
✗ Branch 3 not taken.
600 clidefines.create(define_name) = cleaned_defval;
878 600 continue;
879 600 }
880
881 1200 }
882 200 free(content);
883 }
884 }
885
886 bool checksum_fix_enabled = true;
887 bool force_checksum_fix = false;
888
889 #define cfree(x) free((void*)x)
890 52 static void clearmacro(const string & key, macrodata* & macro)
891 {
892 (void)key;
893 52 macro->lines.~autoarray();
894 52 cfree(macro->fname);
895 52 cfree(macro->arguments[0]);
896 52 cfree(macro->arguments);
897 52 cfree(macro);
898 52 }
899
900 230 static void clearfile(const string & key, sourcefile& filecontent)
901 {
902 (void)key;
903 230 cfree(*filecontent.contents);
904 230 cfree(filecontent.contents);
905 230 }
906
907 2000 static void adddefine(const string & key, string & value)
908 {
909
1/2
✓ Branch 0 taken 2000 times.
✗ Branch 1 not taken.
2000 if (!defines.exists(key)) defines.create(key) = value;
910 2000 }
911
912 static string symbolfile;
913
914 static void printsymbol_wla(const string& key, snes_label& label)
915 {
916 string line = hex2((label.pos & 0xFF0000)>>16)+":"+hex4(label.pos & 0xFFFF)+" "+key+"\n";
917 symbolfile += line;
918 }
919
920 static void printsymbol_nocash(const string& key, snes_label& label)
921 {
922 string line = hex8(label.pos & 0xFFFFFF)+" "+key+"\n";
923 symbolfile += line;
924 }
925
926 string create_symbols_file(string format, uint32_t romCrc){
927 format = lower(format);
928 symbolfile = "";
929 if(format == "wla")
930 {
931 symbolfile = "; wla symbolic information file\n";
932 symbolfile += "; generated by asar\n";
933
934 symbolfile += "\n[labels]\n";
935 labels.each(printsymbol_wla);
936
937 symbolfile += "\n[source files]\n";
938 const autoarray<AddressToLineMapping::FileInfo>& addrToLineFileList = addressToLineMapping.getFileList();
939 for (int i = 0; i < addrToLineFileList.count; ++i)
940 {
941 char addrToFileListStr[256];
942 snprintf(addrToFileListStr, 256, "%.4x %.8x %s\n",
943 i,
944 addrToLineFileList[i].fileCrc,
945 addrToLineFileList[i].filename.data()
946 );
947 symbolfile += addrToFileListStr;
948 }
949
950 symbolfile += "\n[rom checksum]\n";
951 {
952 char romCrcStr[32];
953 snprintf(romCrcStr, 32, "%.8x\n",
954 romCrc
955 );
956 symbolfile += romCrcStr;
957 }
958
959 symbolfile += "\n[addr-to-line mapping]\n";
960 const autoarray<AddressToLineMapping::AddrToLineInfo>& addrToLineInfo = addressToLineMapping.getAddrToLineInfo();
961 for (int i = 0; i < addrToLineInfo.count; ++i)
962 {
963 char addrToLineStr[32];
964 snprintf(addrToLineStr, 32, "%.2x:%.4x %.4x:%.8x\n",
965 (addrToLineInfo[i].addr & 0xFF0000) >> 16,
966 addrToLineInfo[i].addr & 0xFFFF,
967 addrToLineInfo[i].fileIdx & 0xFFFF,
968 addrToLineInfo[i].line & 0xFFFFFFFF
969 );
970 symbolfile += addrToLineStr;
971 }
972
973 }
974 else if (format == "nocash")
975 {
976 symbolfile = ";no$sns symbolic information file\n";
977 symbolfile += ";generated by asar\n";
978 symbolfile += "\n";
979 labels.each(printsymbol_nocash);
980 }
981 return symbolfile;
982 }
983
984 200 void reseteverything()
985 {
986 200 string str;
987 200 labels.reset();
988 200 defines.reset();
989
1/2
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
200 builtindefines.each(adddefine);
990
1/2
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
200 clidefines.each(adddefine);
991 200 structs.reset();
992
993
1/2
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
200 macros.each(clearmacro);
994 200 macros.reset();
995
996
1/2
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
200 filecontents.each(clearfile);
997 200 filecontents.reset();
998
999 200 writtenblocks.reset();
1000
1001 200 optimizeforbank=-1;
1002 200 optimize_dp = optimize_dp_flag::NONE;
1003 200 dp_base = 0;
1004 200 optimize_address = optimize_address_flag::DEFAULT;
1005
1006
1/2
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
200 closecachedfiles();
1007
1008 200 incsrcdepth=0;
1009 200 errored = false;
1010 200 checksum_fix_enabled = true;
1011 200 force_checksum_fix = false;
1012
1013 200 default_math_pri = false;
1014 200 default_math_round_off = false;
1015 200 suppress_all_warnings = false;
1016
1017 #undef free
1018 300 }
1019