asar coverage - build #230


src/asar/
File: src/asar/main.cpp
Date: 2024-04-08 11:09:14
Lines:
460/561
82.0%
Functions:
19/22
86.4%
Branches:
536/905
59.2%

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