asar coverage - build #186


src/asar/
File: src/asar/main.cpp
Date: 2024-01-30 02:21:12
Lines:
469/570
82.3%
Functions:
20/23
87.0%
Branches:
540/911
59.3%

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 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 99 int get_version_int()
64 {
65 99 return asarver_maj * 10000 + asarver_min * 100 + asarver_bug;
66 }
67
68 56 bool setmapper()
69 {
70 28 int maxscore=-99999;
71 28 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 112 int score=0;
77 112 int highbits=0;
78 112 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 1700 times.
✓ Branch 1 taken 3004 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1700 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
2/2
✓ Branch 0 taken 1785 times.
✓ Branch 1 taken 1785 times.
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 84 times.
✓ Branch 3 taken 28 times.
252 if ((romdata[snestopc(0x00FFDE)]^romdata[snestopc(0x00FFDC)])!=0xFF ||
94
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
140 (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 28 maxscore=score;
99 28 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 190 string getdecor()
115 {
116 95 string e;
117
2/4
✓ Branch 0 taken 190 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 95 times.
✗ Branch 3 not taken.
190 if (thisfilename)
118 {
119
2/4
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 95 times.
✗ Branch 3 not taken.
190 e+=STR thisfilename;
120
5/10
✓ 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.
✓ Branch 6 taken 95 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 95 times.
✗ Branch 9 not taken.
285 if (thisline!=-1) e+=STR ":"+dec(thisline+1);
121
11/18
✓ Branch 0 taken 109 times.
✓ Branch 1 taken 81 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 81 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.
204 if (callerfilename) e+=STR" (called from "+callerfilename+":"+dec(callerline+1)+")";
122
1/2
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
190 e+=": ";
123 }
124 190 return e;
125 }
126
127
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)
128 {
129
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)
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 3 case vfe_not_regular_file:
136 3 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 1264 static int getlenforlabel(int insnespos, int thislabel, bool exists, bool use_asar2_settings)
158 {
159
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1264 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1264 if (warnxkas && (((unsigned int)(thislabel^insnespos)&0xFFFF0000)==0))
160 asar_throw_warning(1, warning_id_xkas_label_access);
161 1264 unsigned int bank = thislabel>>16;
162 1264 unsigned int word = thislabel&0xFFFF;
163 unsigned int relaxed_bank;
164 1264 int opt_dp = optimize_dp;
165 1264 int opt_addr = optimize_address;
166
2/2
✓ Branch 0 taken 632 times.
✓ Branch 1 taken 632 times.
1264 if(use_asar2_settings) {
167
2/2
✓ Branch 0 taken 428 times.
✓ Branch 1 taken 204 times.
632 if(!set_optimize_dp) opt_dp = optimize_dp_flag::ALWAYS;
168
2/2
✓ Branch 0 taken 428 times.
✓ Branch 1 taken 204 times.
632 if(!set_optimize_address) opt_addr = optimize_address_flag::MIRRORS;
169 }
170
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1252 times.
1264 if(optimizeforbank >= 0) {
171 12 relaxed_bank = optimizeforbank;
172 } else {
173
2/2
✓ Branch 0 taken 1012 times.
✓ Branch 1 taken 240 times.
1252 if((insnespos & 0xff000000) == 0) {
174 1012 relaxed_bank = insnespos >> 16;
175 } else {
176
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 120 times.
240 if(freespace_is_freecode) relaxed_bank = 0;
177 36 else relaxed_bank = 0x40;
178 }
179 }
180
2/2
✓ Branch 0 taken 160 times.
✓ Branch 1 taken 1104 times.
1264 if (!exists)
181 {
182
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 90 times.
160 if (!freespaced) freespaceextra++;
183 160 freespaced=true;
184 160 return 2;
185 }
186
5/6
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 1086 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
1104 else if((opt_dp == optimize_dp_flag::RAM) && bank == 0x7E && (word-dp_base < 0x100))
187 {
188 6 return 1;
189 }
190
6/8
✓ Branch 0 taken 386 times.
✓ Branch 1 taken 706 times.
✓ Branch 2 taken 386 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 386 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 193 times.
✓ Branch 7 taken 193 times.
1092 else if(opt_dp == optimize_dp_flag::ALWAYS && (bank == 0x7E || !(bank & 0x40)) && (word-dp_base < 0x100))
191 {
192 12 return 1;
193 }
194
2/2
✓ Branch 0 taken 498 times.
✓ Branch 1 taken 36 times.
1068 else if (
195 // if we should optimize ram accesses...
196
2/2
✓ Branch 0 taken 502 times.
✓ Branch 1 taken 530 times.
1032 (opt_addr == optimize_address_flag::RAM || opt_addr == optimize_address_flag::MIRRORS)
197 // and we're in a bank with ram mirrors... (optimizeforbank=0x7E is checked later)
198
2/2
✓ Branch 0 taken 502 times.
✓ Branch 1 taken 36 times.
538 && !(relaxed_bank & 0x40)
199 // and the label is in low RAM
200
3/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 466 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
502 && bank == 0x7E && word < 0x2000)
201 {
202 18 return 2;
203 }
204
2/2
✓ Branch 0 taken 454 times.
✓ Branch 1 taken 313 times.
767 else if (
205 // if we should optimize mirrors...
206 opt_addr == optimize_address_flag::MIRRORS
207 // we're in a bank with ram mirrors...
208
2/2
✓ Branch 0 taken 430 times.
✓ Branch 1 taken 24 times.
454 && !(relaxed_bank & 0x40)
209 // and the label is in a mirrored section
210
3/4
✓ Branch 0 taken 430 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 394 times.
430 && !(bank & 0x40) && word < 0x8000)
211 {
212 18 return 2;
213 }
214
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 988 times.
996 else if (optimizeforbank>=0)
215 {
216 // if optimizing for a specific bank:
217 // if the label is in freespace, never optimize
218
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if ((unsigned int)thislabel&0xFF000000) return 3;
219
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 else if (bank==(unsigned int)optimizeforbank) return 2;
220 4 else return 3;
221 }
222
2/2
✓ Branch 0 taken 196 times.
✓ Branch 1 taken 792 times.
988 else if ((unsigned int)(thislabel|insnespos)&0xFF000000)
223 {
224 // optimize only if the label is in the same freespace
225
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 98 times.
196 if ((unsigned int)(thislabel^insnespos)&0xFF000000) return 3;
226 20 else return 2;
227 }
228
2/2
✓ Branch 0 taken 396 times.
✓ Branch 1 taken 396 times.
792 else if ((thislabel^insnespos)&0xFF0000){ return 3; }
229 370 else { return 2;}
230 }
231
232 632 static int getlenforlabel_wrap(int insnespos, int thislabel, bool exists)
233 {
234 632 int oldlen = getlenforlabel(insnespos, thislabel, exists, false);
235 632 int newlen = getlenforlabel(insnespos, thislabel, exists, true);
236
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 632 times.
632 if(oldlen != newlen) asar_throw_warning(2, warning_id_optimization_settings, oldlen, newlen);
237 632 return oldlen;
238 }
239
240 3318 bool is_hex_constant(const char* str){
241
2/2
✓ Branch 0 taken 2732 times.
✓ Branch 1 taken 586 times.
3318 if (*str=='$')
242 {
243 2732 str++;
244
2/2
✓ Branch 0 taken 9540 times.
✓ Branch 1 taken 2732 times.
12272 while(is_xdigit(*str)) {
245 9540 str++;
246 }
247
2/2
✓ Branch 0 taken 1366 times.
✓ Branch 1 taken 1366 times.
2732 if(*str=='\0'){
248 1366 return true;
249 }
250 }
251 293 return false;
252 }
253
254 3060 int getlen(const char * orgstr, bool optimizebankextraction)
255 {
256 3060 const char * str=orgstr;
257 3060 freespaced=false;
258
259 3060 const char* posneglabel = str;
260
1/2
✓ Branch 0 taken 1530 times.
✗ Branch 1 not taken.
3060 string posnegname = posneglabelname(&posneglabel, false);
261
262
4/4
✓ Branch 0 taken 3027 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 1497 times.
✓ Branch 3 taken 33 times.
3060 if (posnegname.length() > 0)
263 {
264
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 60 times.
66 if (*posneglabel != '\0') goto notposneglabel;
265
266
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 30 times.
80 if (!pass) return 2;
267 20 snes_label label_data;
268 // RPG Hacker: Umm... what kind of magic constant is this?
269 40 label_data.pos = 31415926;
270
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);
271
1/2
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
40 return getlenforlabel_wrap(snespos, (int)label_data.pos, found);
272 }
273 2997 notposneglabel:
274 1500 int len=0;
275
2/2
✓ Branch 0 taken 3146 times.
✓ Branch 1 taken 3000 times.
6146 while (*str)
276 {
277 1573 int thislen=0;
278 3146 bool maybebankextraction=(str==orgstr);
279
2/2
✓ Branch 0 taken 2324 times.
✓ Branch 1 taken 822 times.
3146 if (*str=='$')
280 {
281 2324 str++;
282 int i;
283
2/2
✓ Branch 0 taken 9060 times.
✓ Branch 1 taken 2324 times.
11384 for (i=0;is_xdigit(str[i]);i++);
284 //if (i&1) warn(S dec(i)+"-digit hex value");//blocked in getnum instead
285 2324 thislen=(i+1)/2;
286 2324 str+=i;
287 }
288
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 822 times.
822 else if (*str=='%')
289 {
290 str++;
291 int i;
292 for (i=0;str[i]=='0' || str[i]=='1';i++);
293 //if (i&7) warn(S dec(i)+"-digit binary value");
294 thislen=(i+7)/8;
295 str+=i;
296 }
297
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]=='\'')
298 {
299 thislen=1;
300 str+=3;
301 }
302
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 698 times.
822 else if (is_digit(*str))
303 {
304 124 int val=strtol(str, const_cast<char**>(&str), 10);
305
1/2
✓ Branch 0 taken 124 times.
✗ Branch 1 not taken.
124 if (val>=0) thislen=1;
306
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 62 times.
124 if (val>=256) thislen=2;
307
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 71 times.
71 if (val>=65536) thislen=3;
308
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
62 if (val>=16777216) thislen=4;
309 }
310
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=='?')
311 {
312 296 snes_label thislabel;
313
1/2
✓ Branch 0 taken 592 times.
✗ Branch 1 not taken.
592 bool exists=labelval(&str, &thislabel);
314
1/2
✓ Branch 0 taken 592 times.
✗ Branch 1 not taken.
592 thislen=getlenforlabel_wrap(snespos, (int)thislabel.pos, exists);
315 }
316 106 else str++;
317
4/4
✓ Branch 0 taken 398 times.
✓ Branch 1 taken 2748 times.
✓ Branch 2 taken 164 times.
✓ Branch 3 taken 70 times.
3146 if (optimizebankextraction && maybebankextraction &&
318
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")))
319 return 1;
320
2/2
✓ Branch 0 taken 1508 times.
✓ Branch 1 taken 65 times.
1573 if (thislen>len) len=thislen;
321 }
322
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1500 times.
3000 if (len>3) return 3;
323 1500 return len;
324 3060 }
325
326 struct strcompare {
327 bool operator() (const char * lhs, const char * rhs) const
328 {
329 return strcmp(lhs, rhs)<0;
330 }
331 };
332
333 struct stricompare {
334 bool operator() (const char * lhs, const char * rhs) const
335 {
336 return stricmp(lhs, rhs)<0;
337 }
338 };
339
340 struct sourcefile {
341 char** contents;
342 int numlines;
343 };
344
345 static assocarr<sourcefile> filecontents;
346 assocarr<string> defines;
347 // needs to be separate because defines is reset between parsing arguments and patching
348 assocarr<string> clidefines;
349 assocarr<string> builtindefines;
350
351 1776 bool validatedefinename(const char * name)
352 {
353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1776 times.
1776 if (!name[0]) return false;
354
2/2
✓ Branch 0 taken 17886 times.
✓ Branch 1 taken 1776 times.
19662 for (int i = 0;name[i];i++)
355 {
356
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17886 times.
17886 if (!is_ualnum(name[i])) return false;
357 }
358
359 888 return true;
360 }
361
362 1507490 void resolvedefines(string& out, const char * start)
363 {
364
2/2
✓ Branch 0 taken 753744 times.
✓ Branch 1 taken 1 times.
753745 recurseblock rec;
365 753744 const char * here=start;
366
2/2
✓ Branch 0 taken 8621870 times.
✓ Branch 1 taken 1507476 times.
10129346 while (*here)
367 {
368
4/4
✓ Branch 0 taken 3126 times.
✓ Branch 1 taken 8618744 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 3114 times.
8621870 if (*here=='"' && emulatexkas)
369 {
370
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");
371
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 out+=*here++;
372
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++;
373
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 out+=*here++;
374 }
375
4/4
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 8621810 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 42 times.
8621858 else if (here[0] == '\\' && here[1] == '\\')
376 {
377 // allow using \\ as escape sequence
378
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
6 out += "\\";
379 6 here += 2;
380 }
381
4/4
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 8621810 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 12 times.
8621852 else if (here[0] == '\\' && here[1] == '!')
382 {
383 // allow using \! to escape !
384
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
30 out+="!";
385 30 here += 2;
386 }
387
2/2
✓ Branch 0 taken 635196 times.
✓ Branch 1 taken 7986626 times.
8621822 else if (*here=='!')
388 {
389
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
390 317598 string defname;
391 635196 here++;
392
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 635088 times.
635196 if (*here=='{')
393 {
394 108 here++;
395 54 string unprocessedname;
396 54 int braces=1;
397 while (true)
398 {
399
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 1080 times.
1152 if (*here=='{') braces++;
400
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 972 times.
1152 if (*here=='}') braces--;
401
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);
402
2/2
✓ Branch 0 taken 576 times.
✓ Branch 1 taken 576 times.
1152 if (!braces) break;
403
1/2
✓ Branch 0 taken 522 times.
✗ Branch 1 not taken.
1044 unprocessedname+=*here++;
404 }
405
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
108 here++;
406
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 resolvedefines(defname, unprocessedname);
407
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);
408 108 }
409 else
410 {
411
4/4
✓ Branch 0 taken 654816 times.
✓ Branch 1 taken 317544 times.
✓ Branch 2 taken 327408 times.
✓ Branch 3 taken 317544 times.
1289904 while (is_ualnum(*here)) defname+=*here++;
412 }
413
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]==')')
414 asar_throw_warning(0, warning_id_xkas_eat_parentheses);
415 //if (emulatexkas && here[0]=='(' && here[1]==')') here+=2;
416
417
2/2
✓ Branch 0 taken 317598 times.
✓ Branch 1 taken 317598 times.
635196 if (first)
418 {
419 enum {
420 null,
421 append,
422 expand,
423 domath,
424 setifnotset,
425 } mode;
426 if(0);
427
2/2
✓ Branch 0 taken 270 times.
✓ Branch 1 taken 422130 times.
422400 else if (stribegin(here, " = ")) { here+=3; mode=null; }
428
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 422130 times.
422130 else if (stribegin(here, " += ")) { here+=4; mode=append; }
429
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 422130 times.
422130 else if (stribegin(here, " := ")) { here+=4; mode=expand; }
430
2/2
✓ Branch 0 taken 210966 times.
✓ Branch 1 taken 211164 times.
422130 else if (stribegin(here, " #= ")) { here+=4; mode=domath; }
431
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 211158 times.
211164 else if (stribegin(here, " ?= ")) { here+=4; mode=setifnotset; }
432 211158 else goto notdefineset;
433
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);
434 //else if (stribegin(here, " equ ")) here+=5;
435 105621 string val;
436
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 211200 times.
211242 if (*here=='"')
437 {
438 42 here++;
439 while (true)
440 {
441
2/2
✓ Branch 0 taken 147 times.
✓ Branch 1 taken 147 times.
294 if (*here=='"')
442 {
443
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;
444
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 else if (here[1]=='"') here++;
445 else asar_throw_error(0, error_type_line, error_id_broken_define_declaration);
446 }
447
1/2
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
252 val+=*here++;
448 }
449 42 here++;
450 }
451 else
452 {
453
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++;
454 }
455 //if (strqchr(val.data(), ';')) *strqchr(val.data(), ';')=0;
456
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);
457
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);
458
459 // RPG Hacker: throw an error if we're trying to overwrite built-in defines.
460
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))
461 {
462
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());
463 }
464
465
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)
466 {
467 132 case null:
468 {
469
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;
470 132 break;
471 }
472 case append:
473 {
474 if (!defines.exists(defname)) asar_throw_error(0, error_type_line, error_id_define_not_found, defname.data());
475 string oldval = defines.find(defname);
476 val=oldval+val;
477 defines.create(defname) = val;
478 break;
479 }
480 case expand:
481 {
482 string newval;
483 resolvedefines(newval, val);
484 defines.create(defname) = newval;
485 break;
486 }
487 105483 case domath:
488 {
489 105483 string newval;
490
1/2
✓ Branch 0 taken 210966 times.
✗ Branch 1 not taken.
210966 resolvedefines(newval, val);
491
1/2
✓ Branch 0 taken 210966 times.
✗ Branch 1 not taken.
210966 double num= getnumdouble(newval);
492
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);
493
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);
494 105480 break;
495 210966 }
496 3 case setifnotset:
497 {
498
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;
499 3 break;
500 }
501 }
502 211242 }
503 else
504 {
505 318375 notdefineset:
506
5/6
✓ Branch 0 taken 211995 times.
✓ Branch 1 taken 211959 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 211959 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
423954 if (!defname) out+="!";
507 else
508 {
509
3/6
✓ Branch 0 taken 211959 times.
✓ Branch 1 taken 211959 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 211959 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());
510 else {
511
2/4
✓ Branch 0 taken 211959 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 211959 times.
✗ Branch 3 not taken.
423918 string thisone = defines.find(defname);
512
1/2
✓ Branch 0 taken 423918 times.
✗ Branch 1 not taken.
423918 resolvedefines(out, thisone);
513 423918 }
514 }
515 }
516 635196 }
517
1/2
✓ Branch 0 taken 3993313 times.
✗ Branch 1 not taken.
7986626 else out+=*here++;
518 }
519 2261226 }
520
521 int repeatnext=1;
522
523 bool moreonline;
524 bool moreonlinecond;
525 int fakeendif;
526 bool asarverallowed;
527 bool istoplevel;
528
529 873884 void assembleline(const char * fname, int linenum, const char * line)
530 {
531
1/2
✓ Branch 0 taken 436942 times.
✗ Branch 1 not taken.
436942 recurseblock rec;
532 873884 bool moreonlinetmp=moreonline;
533 // randomdude999: redundant, assemblefile already converted the path to absolute
534 //string absolutepath = filesystem->create_absolute_path("", fname);
535
1/2
✓ Branch 0 taken 436942 times.
✗ Branch 1 not taken.
436942 string absolutepath = fname;
536
1/2
✓ Branch 0 taken 436942 times.
✗ Branch 1 not taken.
436942 thisfilename = absolutepath;
537 873884 thisline=linenum;
538 873884 thisblock= nullptr;
539 873884 single_line_for_tracker = 1;
540 try
541 {
542 436942 string tmp;
543
7/8
✓ Branch 0 taken 1032 times.
✓ Branch 1 taken 872852 times.
✓ Branch 2 taken 948 times.
✓ Branch 3 taken 84 times.
✓ Branch 4 taken 906 times.
✓ Branch 5 taken 42 times.
✓ Branch 6 taken 453 times.
✗ Branch 7 not taken.
873884 if(inmacro && numif == numtrue) tmp = replace_macro_args(line);
544
1/2
✓ Branch 0 taken 436468 times.
✗ Branch 1 not taken.
436468 else tmp = line;
545
4/8
✓ Branch 0 taken 873842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 873842 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 873842 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 873842 times.
✗ Branch 7 not taken.
873842 clean(tmp);
546 436921 string out;
547
4/4
✓ Branch 0 taken 872168 times.
✓ Branch 1 taken 1674 times.
✓ Branch 2 taken 872154 times.
✓ Branch 3 taken 14 times.
873842 if (numif==numtrue) resolvedefines(out, tmp);
548
1/2
✓ Branch 0 taken 837 times.
✗ Branch 1 not taken.
837 else out=tmp;
549 // recheck quotes - defines can mess those up sometimes
550
4/6
✓ Branch 0 taken 873828 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 873822 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
873828 if (!confirmquotes(out)) asar_throw_error(0, error_type_line, error_id_mismatched_quotes);
551
1/2
✓ Branch 0 taken 873822 times.
✗ Branch 1 not taken.
873822 out.qreplace(": :", ": :", true);
552 //puts(out);
553
1/2
✓ Branch 0 taken 873822 times.
✗ Branch 1 not taken.
873822 autoptr<char**> blocks=qsplit(out.temp_raw(), " : ");
554 873822 moreonline=true;
555 873822 moreonlinecond=true;
556 873822 fakeendif=0;
557
2/2
✓ Branch 0 taken 875436 times.
✓ Branch 1 taken 873322 times.
1748758 for (int block=0;moreonline;block++)
558 {
559 875436 moreonline=(blocks[block+1] != nullptr);
560 875436 int repeatthis=repeatnext;
561 875436 repeatnext=1;
562
2/2
✓ Branch 0 taken 875436 times.
✓ Branch 1 taken 874936 times.
1750372 for (int i=0;i<repeatthis;i++)
563 {
564 try
565 {
566
1/2
✓ Branch 0 taken 437718 times.
✗ Branch 1 not taken.
875436 string stripped_block = blocks[block];
567
1/2
✓ Branch 0 taken 875436 times.
✗ Branch 1 not taken.
875436 strip_both(stripped_block, ' ', true);
568
569
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 437712 times.
875436 thisline=linenum;//do not optimize, this one is recursive
570 875436 thisblock = stripped_block.data();
571 437718 bool isspecialline = false;
572
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 875424 times.
875436 if (thisblock[0] == '@')
573 {
574
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");
575
576 6 isspecialline = true;
577 12 thisblock++;
578
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 while (is_space(*thisblock))
579 {
580 thisblock++;
581 }
582 }
583
2/2
✓ Branch 0 taken 874776 times.
✓ Branch 1 taken 660 times.
875436 assembleblock(thisblock, isspecialline);
584
2/2
✓ Branch 0 taken 874774 times.
✓ Branch 1 taken 2 times.
874776 checkbankcross();
585 875436 }
586
2/2
✓ Branch 0 taken 500 times.
✓ Branch 1 taken 162 times.
662 catch (errblock&) {}
587
6/6
✓ Branch 0 taken 653160 times.
✓ Branch 1 taken 221776 times.
✓ Branch 2 taken 653148 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 326574 times.
✓ Branch 5 taken 110894 times.
874936 if (blocks[block][0]!='\0' && blocks[block][0]!='@') asarverallowed=false;
588 }
589
2/2
✓ Branch 0 taken 872914 times.
✓ Branch 1 taken 2022 times.
874936 if(single_line_for_tracker == 1) single_line_for_tracker = 0;
590 }
591
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 873322 times.
873322 if(fakeendif)
592 {
593 thisline = linenum;
594 thisblock = blocks[0];
595 asar_throw_warning(0, warning_id_feature_deprecated, "inline if statements", "Add an \" : endif\" at the end of the line");
596 if (numif==numtrue) numtrue--;
597 numif--;
598 }
599 874904 }
600
2/2
✓ Branch 0 taken 502 times.
✓ Branch 1 taken 60 times.
562 catch (errline&) {}
601 873382 moreonline=moreonlinetmp;
602 1311077 }
603
604 int incsrcdepth=0;
605
606 // Returns true if a file is protected via
607 // an "includeonce".
608 1234 bool file_included_once(const char* file)
609 {
610
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 1192 times.
1432 for (int i = 0; i < includeonce.count; ++i)
611 {
612
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 120 times.
240 if (includeonce[i] == file)
613 {
614 21 return true;
615 }
616 }
617
618 596 return false;
619 }
620
621 1204 void assemblefile(const char * filename, bool toplevel)
622 {
623 1204 incsrcdepth++;
624
1/2
✓ Branch 0 taken 602 times.
✗ Branch 1 not taken.
1204 string absolutepath = filesystem->create_absolute_path(thisfilename, filename);
625
626
4/4
✓ Branch 0 taken 1183 times.
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 581 times.
1204 if (file_included_once(absolutepath))
627 {
628 21 return;
629 }
630
631
1/2
✓ Branch 0 taken 581 times.
✗ Branch 1 not taken.
581 string prevthisfilename = thisfilename;
632
1/2
✓ Branch 0 taken 581 times.
✗ Branch 1 not taken.
581 thisfilename = absolutepath;
633 1162 int prevline = thisline;
634 1162 thisline=-1;
635 1162 const char* prevthisblock = thisblock;
636 1162 thisblock= nullptr;
637 581 sourcefile file;
638 1162 file.contents = nullptr;
639 1162 file.numlines = 0;
640
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 467 times.
1162 int startif=numif;
641
4/4
✓ Branch 0 taken 695 times.
✓ Branch 1 taken 467 times.
✓ Branch 2 taken 114 times.
✓ Branch 3 taken 467 times.
1162 if (!filecontents.exists(absolutepath))
642 {
643
1/2
✓ Branch 0 taken 228 times.
✗ Branch 1 not taken.
228 char * temp= readfile(absolutepath, "");
644
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 228 times.
228 if (!temp)
645 {
646 // RPG Hacker: This is so that we hopefully always end up with a proper decor
647 // and get better error messages.
648 thisfilename = prevthisfilename;
649 thisline = prevline;
650 thisblock = prevthisblock;
651
652 asar_throw_error(0, error_type_null, vfile_error_to_error_id(asar_get_last_io_error()), filename);
653
654 return;
655 }
656
1/2
✓ Branch 0 taken 228 times.
✗ Branch 1 not taken.
228 file.contents =split(temp, "\n");
657
2/2
✓ Branch 0 taken 9496 times.
✓ Branch 1 taken 228 times.
9724 for (int i=0;file.contents[i];i++)
658 {
659 9496 file.numlines++;
660 4748 char * line= file.contents[i];
661 4748 char * comment=line;
662 9496 comment = strqchr(comment, ';');
663
2/2
✓ Branch 0 taken 2610 times.
✓ Branch 1 taken 9496 times.
12106 while (comment != nullptr)
664 {
665 2610 const char* comment_end = comment + strlen(comment);
666
2/2
✓ Branch 0 taken 2604 times.
✓ Branch 1 taken 6 times.
2610 if (comment_end - comment >= 2
667
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2604 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2604 && comment[1] == '[' && comment[2] == '['
668 && (comment_end[-1] != ']' || comment_end[-2] != ']'))
669 {
670 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 \"]]\"");
671 }
672
673
2/2
✓ Branch 0 taken 2606 times.
✓ Branch 1 taken 4 times.
2610 if (comment[1]!='@')
674 {
675 2606 comment[0]='\0';
676 }
677 else
678 {
679 4 comment[0] = ' ';
680 }
681 2610 comment = strqchr(comment, ';');
682 }
683
2/2
✓ Branch 0 taken 1408 times.
✓ Branch 1 taken 9496 times.
10904 while (strqchr(line, '\t')) *strqchr(line, '\t')=' ';
684
4/6
✓ Branch 0 taken 9496 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 9494 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
9496 if (!confirmquotes(line)) { thisline = i; thisblock = line; asar_throw_error(0, error_type_null, error_id_mismatched_quotes); line[0] = '\0'; }
685
1/2
✓ Branch 0 taken 9496 times.
✗ Branch 1 not taken.
9496 itrim(line, " ", " ", true); //todo make use strip
686 }
687
2/2
✓ Branch 0 taken 9496 times.
✓ Branch 1 taken 228 times.
9724 for(int i=0;file.contents[i];i++)
688 {
689 4748 char* line = file.contents[i];
690
7/8
✓ Branch 0 taken 1326 times.
✓ Branch 1 taken 8180 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 4748 times.
9506 for (int j=1;strqrchr(line, ',') && !strqrchr(line, ',')[1] && file.contents[i+j];j++)
691 {
692 // not using strcat because the source and dest overlap here
693 5 char* otherline = file.contents[i+j];
694 10 char* line_end = line + strlen(line);
695
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 10 times.
138 while(*otherline) *line_end++ = *otherline++;
696 10 *line_end = '\0';
697 static char nullstr[]="";
698 10 file.contents[i+j]=nullstr;
699 }
700 }
701
1/2
✓ Branch 0 taken 228 times.
✗ Branch 1 not taken.
228 filecontents.create(absolutepath) = file;
702 } else { // filecontents.exists(absolutepath)
703
1/2
✓ Branch 0 taken 467 times.
✗ Branch 1 not taken.
934 file = filecontents.find(absolutepath);
704 }
705 581 bool in_macro_def=false;
706 1162 asarverallowed=true;
707
3/4
✓ Branch 0 taken 873548 times.
✓ Branch 1 taken 660 times.
✓ Branch 2 taken 873548 times.
✗ Branch 3 not taken.
874208 for (int i=0;file.contents[i] && i<file.numlines;i++)
708 {
709 try
710 {
711
1/2
✓ Branch 0 taken 436774 times.
✗ Branch 1 not taken.
436774 thisfilename= absolutepath;
712 873548 thisline=i;
713 873548 thisblock= nullptr;
714 873548 istoplevel=toplevel;
715
6/6
✓ Branch 0 taken 156 times.
✓ Branch 1 taken 873392 times.
✓ Branch 2 taken 78 times.
✓ Branch 3 taken 78 times.
✓ Branch 4 taken 78 times.
✓ Branch 5 taken 436696 times.
873548 if (stribegin(file.contents[i], "macro ") && numif==numtrue)
716 {
717 // RPG Hacker: Commented out for Asar 1.81 backwards-compatibility.
718 // (From Asar 2.0 onwards, nested macro definitions will be well-defined).
719
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);
720 78 in_macro_def=true;
721
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);
722 }
723
5/6
✓ Branch 0 taken 436774 times.
✓ Branch 1 taken 436618 times.
✓ Branch 2 taken 156 times.
✓ Branch 3 taken 436618 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 78 times.
873392 else if (!stricmp(file.contents[i], "endmacro") && numif==numtrue)
724 {
725
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);
726 78 in_macro_def=false;
727
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);
728 }
729
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 872852 times.
873236 else if (in_macro_def)
730 {
731
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]);
732 }
733 else
734 {
735 872852 int prevnumif = numif;
736 436426 string connectedline;
737
1/2
✓ Branch 0 taken 436426 times.
✗ Branch 1 not taken.
872852 int skiplines = getconnectedlines<char**>(file.contents, i, connectedline);
738
2/2
✓ Branch 0 taken 872350 times.
✓ Branch 1 taken 502 times.
872852 assembleline(absolutepath, i, connectedline);
739
1/2
✓ Branch 0 taken 436175 times.
✗ Branch 1 not taken.
436175 thisfilename = absolutepath;
740 872350 i += skiplines;
741
17/18
✓ Branch 0 taken 449482 times.
✓ Branch 1 taken 422868 times.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 449422 times.
✓ Branch 4 taken 317452 times.
✓ Branch 5 taken 105476 times.
✓ Branch 6 taken 211756 times.
✓ Branch 7 taken 105696 times.
✓ Branch 8 taken 106204 times.
✓ Branch 9 taken 105480 times.
✓ Branch 10 taken 220 times.
✓ Branch 11 taken 105768 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 330695 times.
1083814 if ((numif != prevnumif || single_line_for_tracker == 3) && (whilestatus[numif].iswhile || whilestatus[numif].is_for) && whilestatus[numif].cond)
742
1/2
✓ Branch 0 taken 105480 times.
✗ Branch 1 not taken.
210960 i = whilestatus[numif].startline - 1;
743 872852 }
744 }
745
2/2
✓ Branch 0 taken 502 times.
✓ Branch 1 taken 2 times.
504 catch (errline&) {}
746 }
747 660 thisline++;
748 660 thisblock= nullptr;
749
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 660 times.
660 if (in_macro_def)
750 {
751 asar_throw_error(0, error_type_null, error_id_unclosed_macro);
752 if (!pass) endmacro(false);
753 }
754
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 660 times.
660 if (repeatnext!=1)
755 {
756 repeatnext=1;
757 asar_throw_error(0, error_type_null, error_id_rep_at_file_end);
758 }
759
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 660 times.
660 if (numif!=startif)
760 {
761 numif=startif;
762 numtrue=startif;
763 asar_throw_error(0, error_type_null, error_id_unclosed_if);
764 }
765 660 incsrcdepth--;
766
3/4
✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 330 times.
✓ Branch 3 taken 21 times.
1706 }
767
768 198 void parse_std_includes(const char* textfile, autoarray<string>& outarray)
769 {
770 198 char* content = readfilenative(textfile);
771
772
1/2
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
198 if (content != nullptr)
773 {
774 99 char* pos = content;
775
776
2/2
✓ Branch 0 taken 396 times.
✓ Branch 1 taken 198 times.
594 while (pos[0] != '\0')
777 {
778 198 string stdinclude;
779
780 do
781 {
782
3/4
✓ Branch 0 taken 9801 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9603 times.
✓ Branch 3 taken 198 times.
9801 if (pos[0] != '\r' && pos[0] != '\n')
783 {
784
1/2
✓ Branch 0 taken 5742 times.
✗ Branch 1 not taken.
9603 stdinclude += pos[0];
785 }
786 9801 pos++;
787
4/4
✓ Branch 0 taken 9603 times.
✓ Branch 1 taken 198 times.
✓ Branch 2 taken 9405 times.
✓ Branch 3 taken 198 times.
9801 } while (pos[0] != '\0' && pos[0] != '\n');
788
789
2/4
✓ Branch 0 taken 396 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 198 times.
✗ Branch 3 not taken.
396 stdinclude = strip_whitespace(stdinclude);
790
791
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 198 times.
396 if (stdinclude != "")
792 {
793
2/4
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 198 times.
198 if (!path_is_absolute(stdinclude))
794 {
795 stdinclude = dir(textfile) + stdinclude;
796 }
797
2/4
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 99 times.
✗ Branch 3 not taken.
198 outarray.append(normalize_path(stdinclude));
798 }
799 396 }
800
801 198 free(content);
802 }
803 198 }
804
805 198 void parse_std_defines(const char* textfile)
806 {
807
808 // RPG Hacker: add built-in defines.
809 // (They're not really standard defines, but I was lazy and this was
810 // one convenient place for doing it).
811 198 builtindefines.create("assembler") = "asar";
812
3/6
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 99 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 99 times.
✗ Branch 5 not taken.
198 builtindefines.create("assembler_ver") = dec(get_version_int());
813
814
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 99 times.
198 if(textfile == nullptr) return;
815
816 198 char* content = readfilenative(textfile);
817
818
1/2
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
198 if (content != nullptr)
819 {
820 99 char* pos = content;
821
2/2
✓ Branch 0 taken 1188 times.
✓ Branch 1 taken 198 times.
1386 while (*pos != 0) {
822 594 string define_name;
823 594 string define_val;
824
825
4/4
✓ Branch 0 taken 11880 times.
✓ Branch 1 taken 792 times.
✓ Branch 2 taken 11484 times.
✓ Branch 3 taken 396 times.
12672 while (*pos != '=' && *pos != '\n') {
826
1/2
✓ Branch 0 taken 5742 times.
✗ Branch 1 not taken.
11484 define_name += *pos;
827 11484 pos++;
828 }
829
4/4
✓ Branch 0 taken 990 times.
✓ Branch 1 taken 198 times.
✓ Branch 2 taken 396 times.
✓ Branch 3 taken 198 times.
1188 if (*pos != 0 && *pos != '\n') pos++; // skip =
830
3/4
✓ Branch 0 taken 5346 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4158 times.
✓ Branch 3 taken 1188 times.
5346 while (*pos != 0 && *pos != '\n') {
831
1/2
✓ Branch 0 taken 2079 times.
✗ Branch 1 not taken.
4158 define_val += *pos;
832 4158 pos++;
833 }
834
1/2
✓ Branch 0 taken 1188 times.
✗ Branch 1 not taken.
1188 if (*pos != 0)
835 1188 pos++; // skip \n
836 // clean define_name
837
2/4
✓ Branch 0 taken 1188 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 594 times.
✗ Branch 3 not taken.
1188 define_name = strip_whitespace(define_name);
838
2/4
✓ Branch 0 taken 1188 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 594 times.
✗ Branch 3 not taken.
1188 define_name = strip_prefix(define_name, '!', false); // remove leading ! if present
839
840
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 990 times.
1188 if (define_name == "")
841 {
842
1/2
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
198 if (define_val == "")
843 {
844 198 continue;
845 }
846
847 asar_throw_error(pass, error_type_null, error_id_stddefines_no_identifier);
848 }
849
850
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 990 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
990 if (!validatedefinename(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_invalid, "stddefines.txt", define_name.data());
851
852 // clean define_val
853 495 const char* defval = define_val.data();
854 495 string cleaned_defval;
855
856
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 792 times.
990 if (*defval == 0) {
857 // no value
858
3/6
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 99 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 99 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
198 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
859
2/4
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 99 times.
✗ Branch 3 not taken.
198 clidefines.create(define_name) = "";
860 198 continue;
861 }
862
863
3/4
✓ Branch 0 taken 396 times.
✓ Branch 1 taken 792 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 792 times.
1188 while (*defval == ' ' || *defval == '\t') defval++; // skip whitespace in beginning
864
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 594 times.
792 if (*defval == '"') {
865 198 defval++; // skip opening quote
866
3/4
✓ Branch 0 taken 2574 times.
✓ Branch 1 taken 198 times.
✓ Branch 2 taken 2574 times.
✗ Branch 3 not taken.
2772 while (*defval != '"' && *defval != 0)
867
1/2
✓ Branch 0 taken 1287 times.
✗ Branch 1 not taken.
2574 cleaned_defval += *defval++;
868
869
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 198 times.
198 if (*defval == 0) {
870 asar_throw_error(pass, error_type_null, error_id_mismatched_quotes);
871 }
872 198 defval++; // skip closing quote
873
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 198 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 198 times.
198 while (*defval == ' ' || *defval == '\t') defval++; // skip whitespace
874
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 198 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
198 if (*defval != 0 && *defval != '\n')
875 asar_throw_error(pass, error_type_null, error_id_stddefine_after_closing_quote);
876
877
3/6
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 99 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 99 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
198 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
878
2/4
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 99 times.
✗ Branch 3 not taken.
198 clidefines.create(define_name) = cleaned_defval;
879 198 continue;
880 }
881 else
882 {
883 // slightly hacky way to remove trailing whitespace
884 594 const char* defval_end = strchr(defval, '\n'); // slightly hacky way to get end of string or newline
885
1/2
✓ Branch 0 taken 594 times.
✗ Branch 1 not taken.
594 if (!defval_end) defval_end = strchr(defval, 0);
886 594 defval_end--;
887
3/4
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 594 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 594 times.
792 while (*defval_end == ' ' || *defval_end == '\t') defval_end--;
888
3/4
✓ Branch 0 taken 297 times.
✓ Branch 1 taken 297 times.
✓ Branch 2 taken 297 times.
✗ Branch 3 not taken.
594 cleaned_defval = string(defval, (int)(defval_end - defval + 1));
889
890
3/6
✓ Branch 0 taken 297 times.
✓ Branch 1 taken 297 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 297 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
594 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
891
2/4
✓ Branch 0 taken 594 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 297 times.
✗ Branch 3 not taken.
594 clidefines.create(define_name) = cleaned_defval;
892 594 continue;
893 594 }
894
895 1188 }
896 198 free(content);
897 }
898 }
899
900 bool checksum_fix_enabled = true;
901 bool force_checksum_fix = false;
902
903 #define cfree(x) free((void*)x)
904 52 static void clearmacro(const string & key, macrodata* & macro)
905 {
906 (void)key;
907 52 macro->lines.~autoarray();
908 52 cfree(macro->fname);
909 52 cfree(macro->arguments[0]);
910 52 cfree(macro->arguments);
911 52 cfree(macro);
912 52 }
913
914 228 static void clearfile(const string & key, sourcefile& filecontent)
915 {
916 (void)key;
917 228 cfree(*filecontent.contents);
918 228 cfree(filecontent.contents);
919 228 }
920
921
1/2
✓ Branch 0 taken 990 times.
✗ Branch 1 not taken.
1980 static void adddefine(const string & key, string & value)
922 {
923
1/2
✓ Branch 0 taken 1980 times.
✗ Branch 1 not taken.
1980 if (!defines.exists(key)) defines.create(key) = value;
924 1980 }
925
926 static string symbolfile;
927
928 static void printsymbol_wla(const string& key, snes_label& label)
929 {
930 string line = hex2((label.pos & 0xFF0000)>>16)+":"+hex4(label.pos & 0xFFFF)+" "+key+"\n";
931 symbolfile += line;
932 }
933
934 static void printsymbol_nocash(const string& key, snes_label& label)
935 {
936 string line = hex8(label.pos & 0xFFFFFF)+" "+key+"\n";
937 symbolfile += line;
938 }
939
940 string create_symbols_file(string format, uint32_t romCrc){
941 format = lower(format);
942 symbolfile = "";
943 if(format == "wla")
944 {
945 symbolfile = "; wla symbolic information file\n";
946 symbolfile += "; generated by asar\n";
947
948 symbolfile += "\n[labels]\n";
949 labels.each(printsymbol_wla);
950
951 symbolfile += "\n[source files]\n";
952 const autoarray<AddressToLineMapping::FileInfo>& addrToLineFileList = addressToLineMapping.getFileList();
953 for (int i = 0; i < addrToLineFileList.count; ++i)
954 {
955 char addrToFileListStr[256];
956 snprintf(addrToFileListStr, 256, "%.4x %.8x %s\n",
957 i,
958 addrToLineFileList[i].fileCrc,
959 addrToLineFileList[i].filename.data()
960 );
961 symbolfile += addrToFileListStr;
962 }
963
964 symbolfile += "\n[rom checksum]\n";
965 {
966 char romCrcStr[32];
967 snprintf(romCrcStr, 32, "%.8x\n",
968 romCrc
969 );
970 symbolfile += romCrcStr;
971 }
972
973 symbolfile += "\n[addr-to-line mapping]\n";
974 const autoarray<AddressToLineMapping::AddrToLineInfo>& addrToLineInfo = addressToLineMapping.getAddrToLineInfo();
975 for (int i = 0; i < addrToLineInfo.count; ++i)
976 {
977 char addrToLineStr[32];
978 snprintf(addrToLineStr, 32, "%.2x:%.4x %.4x:%.8x\n",
979 (addrToLineInfo[i].addr & 0xFF0000) >> 16,
980 addrToLineInfo[i].addr & 0xFFFF,
981 addrToLineInfo[i].fileIdx & 0xFFFF,
982 addrToLineInfo[i].line & 0xFFFFFFFF
983 );
984 symbolfile += addrToLineStr;
985 }
986
987 }
988 else if (format == "nocash")
989 {
990 symbolfile = ";no$sns symbolic information file\n";
991 symbolfile += ";generated by asar\n";
992 symbolfile += "\n";
993 labels.each(printsymbol_nocash);
994 }
995 return symbolfile;
996 }
997
998 198 void reseteverything()
999 {
1000 99 string str;
1001 198 labels.reset();
1002 198 defines.reset();
1003
1/2
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
198 builtindefines.each(adddefine);
1004
1/2
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
198 clidefines.each(adddefine);
1005 198 structs.reset();
1006
1007
1/2
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
198 macros.each(clearmacro);
1008 198 macros.reset();
1009
1010
1/2
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
198 filecontents.each(clearfile);
1011 198 filecontents.reset();
1012
1013 198 writtenblocks.reset();
1014
1015 198 optimizeforbank=-1;
1016 198 optimize_dp = optimize_dp_flag::NONE;
1017 198 dp_base = 0;
1018 198 optimize_address = optimize_address_flag::DEFAULT;
1019
1020
1/2
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
198 closecachedfiles();
1021
1022 198 incsrcdepth=0;
1023 198 errored = false;
1024 198 checksum_fix_enabled = true;
1025 198 force_checksum_fix = false;
1026
1027 198 default_math_pri = false;
1028 198 default_math_round_off = false;
1029 198 suppress_all_warnings = false;
1030
1031 #undef free
1032 297 }
1033