asar coverage - build #141


src/asar/
File: src/asar/main.cpp
Date: 2024-01-23 10:47:37
Lines:
460/561
82.0%
Functions:
19/22
86.4%
Branches:
535/905
59.1%

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