asar coverage - build #262


src/asar/
File: src/asar/main.cpp
Date: 2025-02-27 19:01:43
Lines:
645/680
94.9%
Functions:
37/37
100.0%
Branches:
727/1060
68.6%

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 "asar.h"
5 #include "virtualfile.h"
6 #include "platform/file-helpers.h"
7 #include "assembleblock.h"
8 #include "asar_math.h"
9 #include "macro.h"
10 #include <algorithm>
11 #include <ctime>
12 // randomdude999: remember to also update the .rc files (in res/windows/) when changing this.
13 // Couldn't find a way to automate this without shoving the version somewhere in the CMake files
14 const int asarver_maj=2;
15 const int asarver_min=0;
16 const int asarver_bug=0;
17 const bool asarver_beta=true;
18
19 #ifdef _I_RELEASE
20 extern char blockbetareleases[(!asarver_beta)?1:-1];
21 #endif
22 #ifdef _I_DEBUG
23 extern char blockreleasedebug[(asarver_beta)?1:-1];
24 #endif
25
26 unsigned const char * romdata_r;
27 int romlen_r;
28
29 int pass;
30
31 int optimizeforbank=-1;
32 int optimize_dp = optimize_dp_flag::ALWAYS;
33 int dp_base = 0;
34 int optimize_address = optimize_address_flag::MIRRORS;
35
36 autoarray<callstack_entry> callstack;
37
38 bool errored=false;
39 bool ignoretitleerrors=false;
40
41 int recursioncount=0;
42
43 virtual_filesystem* filesystem = nullptr;
44
45 AddressToLineMapping addressToLineMapping;
46
47 595 int get_version_int()
48 {
49 595 return asarver_maj * 10000 + asarver_min * 100 + asarver_bug;
50 }
51
52 66 bool setmapper()
53 {
54 33 int maxscore=-99999;
55 33 mapper_t bestmap=lorom;
56 66 mapper_t maps[]={lorom, hirom, exlorom, exhirom};
57
2/2
✓ Branch 0 taken 264 times.
✓ Branch 1 taken 66 times.
330 for (size_t mapid=0;mapid<sizeof(maps)/sizeof(maps[0]);mapid++)
58 {
59 264 mapper=maps[mapid];
60 132 int score=0;
61 132 int highbits=0;
62 132 bool foundnull=false;
63
2/2
✓ Branch 0 taken 5544 times.
✓ Branch 1 taken 264 times.
5808 for (int i=0;i<21;i++)
64 {
65 5544 unsigned char c=romdata[snestopc(0x00FFC0+i)];
66
3/4
✓ Branch 0 taken 2000 times.
✓ Branch 1 taken 3544 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2000 times.
5544 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
67
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5544 times.
5544 if (c>=128) highbits++;
68
2/2
✓ Branch 0 taken 960 times.
✓ Branch 1 taken 4584 times.
5544 else if (is_upper(c)) score+=3;
69
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 4200 times.
4584 else if (c==' ') score+=2;
70
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4200 times.
4200 else if (is_digit(c)) score+=1;
71
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4200 times.
4200 else if (is_lower(c)) score+=1;
72
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4200 times.
4200 else if (c=='-') score+=1;
73
2/2
✓ Branch 0 taken 2100 times.
✓ Branch 1 taken 2100 times.
4200 else if (!c) foundnull=true;
74 else score-=3;
75 }
76
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 264 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
264 if (highbits>0 && highbits<=14) score-=21;//high bits set on some, but not all, bytes = unlikely to be a ROM
77
4/4
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 198 times.
✓ Branch 2 taken 99 times.
✓ Branch 3 taken 33 times.
297 if ((romdata[snestopc(0x00FFDE)]^romdata[snestopc(0x00FFDC)])!=0xFF ||
78
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
165 (romdata[snestopc(0x00FFDF)]^romdata[snestopc(0x00FFDD)])!=0xFF) score=-99999;//checksum doesn't match up to 0xFFFF? Not a ROM.
79 //too lazy to check the real checksum
80
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 198 times.
264 if (score>maxscore)
81 {
82 33 maxscore=score;
83 33 bestmap=mapper;
84 }
85 }
86 66 mapper=bestmap;
87
88 //detect oddball mappers
89 66 int mapperbyte=romdata[snestopc(0x00FFD5)];
90 66 int romtypebyte=romdata[snestopc(0x00FFD6)];
91
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
66 if (mapper==lorom)
92 {
93
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 66 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.
66 if (mapperbyte==0x23 && (romtypebyte==0x32 || romtypebyte==0x34 || romtypebyte==0x35)) mapper=sa1rom;
94 }
95 66 return (maxscore>=0);
96 }
97
98
99 bool simple_callstacks = true;
100
101 // Shortens target_path to a relative path, but only if it resides
102 // within base_path or a child directory of it.
103 25849 static string shorten_to_relative_path(const char* base_path, const char* target_path)
104 {
105
2/2
✓ Branch 0 taken 15997 times.
✓ Branch 1 taken 9852 times.
25849 if (stribegin(target_path, base_path)) target_path += strlen(base_path);
106 25849 return target_path;
107 }
108
109 25849 static string get_top_level_directory()
110 {
111 10351 string top_level_file_dir;
112
1/2
✓ Branch 0 taken 25849 times.
✗ Branch 1 not taken.
25849 for (int i = 0; i < callstack.count; ++i)
113 {
114
2/4
✓ Branch 0 taken 25849 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10351 times.
✗ Branch 3 not taken.
25849 if (callstack[i].type == callstack_entry_type::FILE)
115 {
116
2/4
✓ Branch 0 taken 25849 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10351 times.
✗ Branch 3 not taken.
25849 top_level_file_dir = dir(callstack[i].content);
117 25849 break;
118 }
119 }
120 25849 return top_level_file_dir;
121 }
122
123
2/2
✓ Branch 0 taken 15431 times.
✓ Branch 1 taken 25 times.
25765 static string generate_call_details_string(const char* current_block, const char* current_call, int indentation, bool add_lines)
124 {
125 10309 string e;
126
4/4
✓ Branch 0 taken 15527 times.
✓ Branch 1 taken 10238 times.
✓ Branch 2 taken 71 times.
✓ Branch 3 taken 25 times.
25765 if (current_block != nullptr || current_call != nullptr)
127 {
128 10284 string indent;
129
3/4
✓ Branch 0 taken 13715 times.
✓ Branch 1 taken 12000 times.
✓ Branch 2 taken 8332 times.
✗ Branch 3 not taken.
25715 if (add_lines) indent += "|";
130
3/4
✓ Branch 0 taken 102876 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 102876 times.
✓ Branch 3 taken 25715 times.
128591 for (; indentation > 0; --indentation) indent += " ";
131
132
8/14
✓ Branch 0 taken 25581 times.
✓ Branch 1 taken 134 times.
✓ Branch 2 taken 25581 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 25581 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 25581 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 25581 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 25581 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 10213 times.
✗ Branch 13 not taken.
41083 if (current_block != nullptr) e += STR "\n"+indent+"in block: ["+current_block+"]";
133
8/14
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 25581 times.
✓ Branch 2 taken 134 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 134 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 134 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 134 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 134 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 71 times.
✗ Branch 13 not taken.
25778 if (current_call != nullptr) e += STR "\n"+indent+"in macro call: [%"+current_call+"]";
134 25715 }
135 25765 return e;
136 }
137
138 25849 static string get_pretty_filename(const char* current_file)
139 {
140 // RPG Hacker: One could make an argument that we shouldn't shorten paths
141 // here, since some IDEs support jumping to files by double-clicking their
142 // paths. However, AFAIK, no IDE supports this for Asar yet, and if it's
143 // ever desired, we could just make it a command line option. Until then,
144 // I think it's more important to optimize for pretty command line display.
145
2/4
✓ Branch 0 taken 25849 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10351 times.
✗ Branch 3 not taken.
36200 return shorten_to_relative_path(get_top_level_directory(), current_file);
146 }
147
148 9189 static string generate_filename_and_line(const char* current_file, int current_line_no)
149 {
150
1/2
✓ Branch 0 taken 3739 times.
✗ Branch 1 not taken.
12928 return STR current_file
151
13/20
✓ Branch 0 taken 9153 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 9153 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9153 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9171 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5450 times.
✓ Branch 9 taken 18 times.
✓ Branch 10 taken 9171 times.
✓ Branch 11 taken 18 times.
✓ Branch 12 taken 3721 times.
✓ Branch 13 taken 18 times.
✓ Branch 14 taken 3721 times.
✓ Branch 15 taken 18 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
32999 + (current_line_no>=0?STR ":"+dec(current_line_no+1):"");
152 }
153
154 8332 static string format_stack_line(const printable_callstack_entry& entry, int stack_frame_index)
155 {
156
1/2
✓ Branch 0 taken 3308 times.
✗ Branch 1 not taken.
3308 string indent = "\n| ";
157
2/4
✓ Branch 0 taken 8332 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8332 times.
✗ Branch 3 not taken.
8332 indent += dec(stack_frame_index);
158
1/2
✓ Branch 0 taken 8332 times.
✗ Branch 1 not taken.
8332 indent += ": ";
159 // RPG Hacker: We'll probably never have a call stack in the
160 // hundreds even, so this very specific, lazy solution suffices.
161
3/4
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 8080 times.
✓ Branch 2 taken 252 times.
✗ Branch 3 not taken.
8332 if (stack_frame_index < 100) indent += " ";
162
3/4
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 3360 times.
✓ Branch 2 taken 72 times.
✗ Branch 3 not taken.
3432 if (stack_frame_index < 10) indent += " ";
163 return indent
164
2/4
✓ Branch 0 taken 8332 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8332 times.
✗ Branch 3 not taken.
16664 + generate_filename_and_line(entry.prettypath, entry.lineno)
165
1/2
✓ Branch 0 taken 8332 times.
✗ Branch 1 not taken.
19972 + entry.details;
166 8332 }
167
168 40064 static void push_stack_line(autoarray<printable_callstack_entry>* out, const char* current_file, const char* current_block, const char* current_call, int current_line_no, int indentation, bool add_lines)
169 {
170 9920 printable_callstack_entry new_entry;
171
1/2
✓ Branch 0 taken 9920 times.
✗ Branch 1 not taken.
9920 new_entry.fullpath = current_file;
172
1/2
✓ Branch 0 taken 24992 times.
✗ Branch 1 not taken.
24992 new_entry.prettypath = get_pretty_filename(current_file);
173 24992 new_entry.lineno = current_line_no;
174
2/4
✓ Branch 0 taken 24992 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9920 times.
✗ Branch 3 not taken.
40064 new_entry.details = generate_call_details_string(current_block, current_call, indentation, add_lines).raw();
175
1/2
✓ Branch 0 taken 24992 times.
✗ Branch 1 not taken.
24992 out->append(new_entry);
176 24992 }
177
178 774 void get_current_line_details(string* location, string* details, bool exclude_block)
179 {
180 390 const char* current_file = nullptr;
181 390 const char* current_block = nullptr;
182 390 const char* current_call = nullptr;
183 390 int current_line_no = -1;
184
2/2
✓ Branch 0 taken 2636 times.
✓ Branch 1 taken 1 times.
2637 for (int i = callstack.count-1; i >= 0 ; --i)
185 {
186
3/5
✓ Branch 0 taken 773 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 737 times.
✓ Branch 3 taken 1126 times.
✗ Branch 4 not taken.
2636 switch (callstack[i].type)
187 {
188 389 case callstack_entry_type::FILE:
189 389 current_file = callstack[i].content;
190
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 749 times.
773 if (exclude_block) current_block = nullptr;
191
2/4
✓ Branch 0 taken 773 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 389 times.
✗ Branch 3 not taken.
773 *location = generate_filename_and_line(get_pretty_filename(current_file), current_line_no);
192
1/2
✓ Branch 0 taken 389 times.
✗ Branch 1 not taken.
773 *details = generate_call_details_string(current_block, current_call, 4, false);
193 773 return;
194 case callstack_entry_type::MACRO_CALL:
195 if (current_call == nullptr) current_call = callstack[i].content;
196 break;
197 737 case callstack_entry_type::LINE:
198
3/4
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 569 times.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
737 if (current_block == nullptr && current_call == nullptr) current_block = callstack[i].content;
199
1/2
✓ Branch 0 taken 737 times.
✗ Branch 1 not taken.
1103 if (current_line_no == -1) current_line_no = callstack[i].lineno;
200 371 break;
201 1126 case callstack_entry_type::BLOCK:
202
2/2
✓ Branch 0 taken 569 times.
✓ Branch 1 taken 557 times.
1126 if (current_block == nullptr) current_block = callstack[i].content;
203 568 break;
204 }
205 }
206 1 *location = "";
207 1 *details = "";
208 }
209
210 776 void get_full_printable_callstack(autoarray<printable_callstack_entry>* out, int indentation, bool add_lines)
211 {
212 776 out->reset();
213 392 const char* current_file = nullptr;
214 392 const char* current_block = nullptr;
215 392 const char* current_call = nullptr;
216 392 int current_line_no = -1;
217
2/2
✓ Branch 0 taken 102746 times.
✓ Branch 1 taken 776 times.
103522 for (int i = 0; i < callstack.count; ++i)
218 {
219
4/5
✓ Branch 0 taken 25767 times.
✓ Branch 1 taken 134 times.
✓ Branch 2 taken 25731 times.
✓ Branch 3 taken 51114 times.
✗ Branch 4 not taken.
102746 switch (callstack[i].type)
220 {
221 25767 case callstack_entry_type::FILE:
222
2/2
✓ Branch 0 taken 24992 times.
✓ Branch 1 taken 775 times.
25767 if (current_file != nullptr)
223 {
224 24992 push_stack_line(out, current_file, current_block, current_call, current_line_no, indentation, add_lines);
225 }
226 10311 current_file = callstack[i].content;
227 10311 current_block = nullptr;
228 10311 current_call = nullptr;
229 10311 current_line_no = -1;
230 25767 break;
231 134 case callstack_entry_type::MACRO_CALL:
232 71 current_block = nullptr;
233 71 current_call = callstack[i].content;
234 134 break;
235 10293 case callstack_entry_type::LINE:
236 25731 current_line_no = callstack[i].lineno;
237 10293 current_block = callstack[i].content;
238 25731 break;
239 20412 case callstack_entry_type::BLOCK:
240 20412 current_block = callstack[i].content;
241 51114 break;
242 }
243 }
244 776 }
245
246 258 static string get_full_callstack()
247 {
248 130 autoarray<printable_callstack_entry> printable_stack;
249
1/2
✓ Branch 0 taken 258 times.
✗ Branch 1 not taken.
258 get_full_printable_callstack(&printable_stack, 12, true);
250
251 130 string e;
252
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 206 times.
258 if (printable_stack.count > 0)
253 {
254
1/2
✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
52 e += "\nFull call stack:";
255
2/2
✓ Branch 0 taken 8332 times.
✓ Branch 1 taken 52 times.
8384 for (int i = printable_stack.count-1; i >= 0; --i)
256 {
257
3/6
✓ Branch 0 taken 8332 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8332 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3308 times.
✗ Branch 5 not taken.
8332 e += format_stack_line(printable_stack[i], i);
258 }
259 }
260 388 return e;
261 258 }
262
263 // RPG Hacker: This function essetially replicates classic Asar behavior
264 // of only printing a single macro call below the current level.
265 516 static string get_simple_callstack()
266 {
267 int i;
268 260 const char* current_call = nullptr;
269
2/2
✓ Branch 0 taken 68128 times.
✓ Branch 1 taken 432 times.
68560 for (i = callstack.count-1; i >= 0 ; --i)
270 {
271
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 68044 times.
68128 if (callstack[i].type == callstack_entry_type::MACRO_CALL)
272 {
273 42 current_call = callstack[i].content;
274 84 break;
275 }
276 }
277
278 260 const char* current_file = nullptr;
279 260 int current_line_no = -1;
280
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 432 times.
516 if (current_call != nullptr)
281 {
282 42 bool stop = false;
283
1/2
✓ Branch 0 taken 336 times.
✗ Branch 1 not taken.
336 for (int j = i-1; j >= 0 ; --j)
284 {
285
3/5
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✓ Branch 3 taken 168 times.
✗ Branch 4 not taken.
336 switch (callstack[j].type)
286 {
287 84 case callstack_entry_type::FILE:
288
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
84 if (current_file != nullptr)
289 {
290 stop = true;
291 break;
292 }
293 42 current_file = callstack[j].content;
294 84 break;
295 case callstack_entry_type::MACRO_CALL:
296 stop = true;
297 break;
298 84 case callstack_entry_type::LINE:
299
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
126 if (current_line_no == -1) current_line_no = callstack[j].lineno;
300 42 break;
301 84 case callstack_entry_type::BLOCK:
302 84 break;
303 }
304
305
3/4
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
336 if (current_file != nullptr && current_line_no != -1) stop = true;
306
307
2/2
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 126 times.
294 if (stop) break;
308 }
309 }
310
311 260 string e;
312
3/4
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 432 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
516 if (current_call != nullptr && current_file != nullptr)
313 {
314
4/8
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 84 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 42 times.
✗ Branch 7 not taken.
210 e += STR "\n called from: " + generate_filename_and_line(get_pretty_filename(current_file), current_line_no)
315
4/8
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 84 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 84 times.
✗ Branch 7 not taken.
168 + ": [%" + current_call + "]";
316 }
317 516 return e;
318 }
319
320 774 string get_callstack()
321 {
322
2/2
✓ Branch 0 taken 516 times.
✓ Branch 1 taken 258 times.
774 if (simple_callstacks)
323 516 return get_simple_callstack();
324 else
325 258 return get_full_callstack();
326 }
327
328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
99 asar_error_id vfile_error_to_error_id(virtual_file_error vfile_error)
329 {
330
2/5
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
54 switch (vfile_error)
331 {
332 18 case vfe_doesnt_exist:
333 18 return error_id_file_not_found;
334 case vfe_access_denied:
335 return error_id_failed_to_open_file_access_denied;
336 36 case vfe_not_regular_file:
337 36 return error_id_failed_to_open_not_regular_file;
338 case vfe_unknown:
339 case vfe_none:
340 case vfe_num_errors:
341 return error_id_failed_to_open_file;
342 }
343
344 return error_id_failed_to_open_file;
345 }
346
347 99 virtual_file_error asar_get_last_io_error()
348 {
349
1/2
✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
99 if (filesystem != nullptr)
350 {
351 99 return filesystem->get_last_error();
352 }
353
354 return vfe_unknown;
355 }
356
357 1907 int getlenforlabel(snes_label thislabel, bool exists)
358 {
359 1907 unsigned int bank = thislabel.pos>>16;
360 1907 unsigned int word = thislabel.pos&0xFFFF;
361 956 bool lblfreespace = thislabel.freespace_id > 0;
362 unsigned int relaxed_bank;
363
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 1835 times.
1907 if(optimizeforbank >= 0) {
364 72 relaxed_bank = optimizeforbank;
365 } else {
366
2/2
✓ Branch 0 taken 1451 times.
✓ Branch 1 taken 384 times.
1835 if(freespaceid == 0) {
367 1451 relaxed_bank = snespos >> 16;
368 } else {
369 384 int target_bank = freespaces[freespaceid].bank;
370
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 192 times.
384 if(target_bank == -2) relaxed_bank = 0;
371
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 66 times.
132 else if(target_bank == -1) relaxed_bank = 0x40;
372 else relaxed_bank = target_bank;
373 }
374 }
375
2/2
✓ Branch 0 taken 951 times.
✓ Branch 1 taken 956 times.
1907 if (!exists)
376 {
377 return 2;
378 }
379
7/8
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1871 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✓ Branch 7 taken 9 times.
1907 else if((optimize_dp == optimize_dp_flag::RAM) && bank == 0x7E && (word-dp_base < 0x100) && !lblfreespace)
380 {
381 9 return 1;
382 }
383
8/10
✓ Branch 0 taken 1247 times.
✓ Branch 1 taken 642 times.
✓ Branch 2 taken 1247 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1247 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 263 times.
✓ Branch 7 taken 984 times.
✓ Branch 8 taken 134 times.
✓ Branch 9 taken 129 times.
1889 else if(optimize_dp == optimize_dp_flag::ALWAYS && (bank == 0x7E || !(bank & 0x40)) && (word-dp_base < 0x100) && !lblfreespace)
384 {
385 32 return 1;
386 }
387 1830 else if (
388 // if we should optimize ram accesses...
389
4/4
✓ Branch 0 taken 1614 times.
✓ Branch 1 taken 216 times.
✓ Branch 2 taken 699 times.
✓ Branch 3 taken 162 times.
1830 (optimize_address == optimize_address_flag::RAM || optimize_address == optimize_address_flag::MIRRORS)
390 // and we're in a bank with ram mirrors... (optimizeforbank=0x7E is checked later)
391
2/2
✓ Branch 0 taken 1410 times.
✓ Branch 1 taken 96 times.
1506 && !(relaxed_bank & 0x40)
392 // and the label is in low RAM
393
5/6
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 1356 times.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
1410 && bank == 0x7E && word < 0x2000 && !lblfreespace)
394 {
395 27 return 2;
396 }
397
2/2
✓ Branch 0 taken 690 times.
✓ Branch 1 taken 198 times.
1776 else if (
398 // if we should optimize mirrors...
399
2/2
✓ Branch 0 taken 690 times.
✓ Branch 1 taken 198 times.
888 optimize_address == optimize_address_flag::MIRRORS
400 // we're in a bank with ram mirrors...
401
2/2
✓ Branch 0 taken 1302 times.
✓ Branch 1 taken 78 times.
1380 && !(relaxed_bank & 0x40)
402 // and the label is in a mirrored section
403
5/6
✓ Branch 0 taken 1302 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 750 times.
✓ Branch 3 taken 552 times.
✓ Branch 4 taken 36 times.
✓ Branch 5 taken 99 times.
1302 && !(bank & 0x40) && word < 0x8000 && !lblfreespace)
404 {
405 36 return 2;
406 }
407
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 1632 times.
1704 else if (optimizeforbank>=0)
408 {
409 // if optimizing for a specific bank:
410 // if the label is in freespace, never optimize
411
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 36 times.
72 if (thislabel.freespace_id > 0) return 3;
412
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 36 times.
72 else if (bank==(unsigned int)optimizeforbank) return 2;
413 36 else return 3;
414 }
415
4/4
✓ Branch 0 taken 1170 times.
✓ Branch 1 taken 462 times.
✓ Branch 2 taken 162 times.
✓ Branch 3 taken 1008 times.
1632 else if (thislabel.freespace_id > 0 || freespaceid > 0)
416 {
417 // optimize only if the label is in the same freespace
418 // TODO: check whether they're pinned to the same bank
419
2/2
✓ Branch 0 taken 312 times.
✓ Branch 1 taken 312 times.
624 if (thislabel.freespace_id != freespaceid) return 3;
420 96 else return 2;
421 }
422
2/2
✓ Branch 0 taken 504 times.
✓ Branch 1 taken 504 times.
1008 else if ((int)bank != snespos >> 16){ return 3; }
423 954 else { return 2;}
424 }
425
426
427 939 bool is_hex_constant(const char* str){
428
2/2
✓ Branch 0 taken 648 times.
✓ Branch 1 taken 291 times.
939 if (*str=='$')
429 {
430 648 str++;
431
2/2
✓ Branch 0 taken 1800 times.
✓ Branch 1 taken 648 times.
2448 while(is_xdigit(*str)) {
432 1800 str++;
433 }
434
2/2
✓ Branch 0 taken 324 times.
✓ Branch 1 taken 324 times.
648 if(*str=='\0'){
435 324 return true;
436 }
437 }
438 147 return false;
439 }
440
441 struct strcompare {
442 bool operator() (const char * lhs, const char * rhs) const
443 {
444 return strcmp(lhs, rhs)<0;
445 }
446 };
447
448 struct stricompare {
449 bool operator() (const char * lhs, const char * rhs) const
450 {
451 return stricmp(lhs, rhs)<0;
452 }
453 };
454
455 struct sourcefile {
456 char *data;
457 char** contents;
458 int numlines;
459 };
460
461 static assocarr<sourcefile> filecontents;
462 assocarr<string> defines;
463 // needs to be separate because defines is reset between parsing arguments and patching
464 assocarr<string> clidefines;
465 assocarr<string> builtindefines;
466
467 5419 bool validatedefinename(const char * name)
468 {
469
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5419 times.
5419 if (!name[0]) return false;
470
2/2
✓ Branch 0 taken 56558 times.
✓ Branch 1 taken 5419 times.
61977 for (int i = 0;name[i];i++)
471 {
472
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56558 times.
56558 if (!is_ualnum(name[i])) return false;
473 }
474
475 2718 return true;
476 }
477
478 193192 void resolvedefines(string& out, const char * start)
479 {
480
2/2
✓ Branch 0 taken 94187 times.
✓ Branch 1 taken 3 times.
94190 recurseblock rec;
481 94187 const char * here=start;
482
2/2
✓ Branch 0 taken 161822 times.
✓ Branch 1 taken 31364 times.
193186 if (!strchr(here, '!'))
483 {
484
1/2
✓ Branch 0 taken 161822 times.
✗ Branch 1 not taken.
161822 out += here;
485 78481 return;
486 }
487
2/2
✓ Branch 0 taken 215003 times.
✓ Branch 1 taken 31273 times.
246276 while (*here)
488 {
489
4/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 214859 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 126 times.
215003 if (here[0] == '\\' && here[1] == '\\')
490 {
491 // allow using \\ as escape sequence
492
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
18 if (in_macro_def > 0) out += "\\";
493
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 out += "\\";
494 18 here += 2;
495 }
496
3/4
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 214859 times.
✓ Branch 2 taken 126 times.
✗ Branch 3 not taken.
214985 else if (here[0] == '\\' && here[1] == '!')
497 {
498 // allow using \! to escape !
499
3/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
126 if (in_macro_def > 0) out += "\\";
500
1/2
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
126 out+="!";
501 126 here += 2;
502 }
503
2/2
✓ Branch 0 taken 33662 times.
✓ Branch 1 taken 181197 times.
214859 else if (*here=='!')
504 {
505
10/10
✓ Branch 0 taken 16365 times.
✓ Branch 1 taken 17297 times.
✓ Branch 2 taken 10119 times.
✓ Branch 3 taken 6246 times.
✓ Branch 4 taken 7746 times.
✓ Branch 5 taken 2373 times.
✓ Branch 6 taken 360 times.
✓ Branch 7 taken 7386 times.
✓ Branch 8 taken 36 times.
✓ Branch 9 taken 324 times.
33662 bool first=(here==start || (here>=start+4 && here[-1]==' ' && here[-2]==':' && here[-3]==' '));//check if it's the start of a block
506 16861 string defname;
507 33662 here++;
508
509 16861 int depth = 0;
510
2/2
✓ Branch 0 taken 342 times.
✓ Branch 1 taken 33662 times.
34004 for (const char* depth_str = here; *depth_str=='^'; depth_str++)
511 {
512 342 depth++;
513 }
514 33662 here += depth;
515
516
2/2
✓ Branch 0 taken 3963 times.
✓ Branch 1 taken 29699 times.
33662 if (depth != in_macro_def)
517 {
518
1/2
✓ Branch 0 taken 3963 times.
✗ Branch 1 not taken.
3963 out += '!';
519
3/4
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 198 times.
✓ Branch 3 taken 3963 times.
4161 for (int i=0; i < depth; ++i) out += '^';
520
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 3909 times.
3963 if (depth > in_macro_def) asar_throw_error(0, error_type_line, error_id_invalid_depth_resolve, "define", "define", depth, in_macro_def);
521 1956 continue;
522 3909 }
523
524
2/2
✓ Branch 0 taken 324 times.
✓ Branch 1 taken 29375 times.
29699 if (*here=='{')
525 {
526 324 here++;
527 162 string unprocessedname;
528 162 int braces=1;
529 while (true)
530 {
531
2/2
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 3240 times.
3456 if (*here=='{') braces++;
532
2/2
✓ Branch 0 taken 540 times.
✓ Branch 1 taken 2916 times.
3456 if (*here=='}') braces--;
533
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3456 times.
3456 if (!*here) asar_throw_error(0, error_type_line, error_id_mismatched_braces);
534
2/2
✓ Branch 0 taken 1728 times.
✓ Branch 1 taken 1728 times.
3456 if (!braces) break;
535
1/2
✓ Branch 0 taken 3132 times.
✗ Branch 1 not taken.
3132 unprocessedname+=*here++;
536 }
537
1/2
✓ Branch 0 taken 162 times.
✗ Branch 1 not taken.
324 here++;
538
1/2
✓ Branch 0 taken 324 times.
✗ Branch 1 not taken.
324 resolvedefines(defname, unprocessedname);
539
3/4
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 108 times.
324 if (!validatedefinename(defname)) asar_throw_error(0, error_type_line, error_id_invalid_define_name);
540 324 }
541 else
542 {
543
3/4
✓ Branch 0 taken 149945 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 149945 times.
✓ Branch 3 taken 29375 times.
179320 while (is_ualnum(*here)) defname+=*here++;
544 }
545
546
2/2
✓ Branch 0 taken 15803 times.
✓ Branch 1 taken 13896 times.
29699 if (first)
547 {
548 enum {
549 null,
550 append,
551 expand,
552 domath,
553 setifnotset,
554 } mode;
555 if(0);
556
2/2
✓ Branch 0 taken 1560 times.
✓ Branch 1 taken 14243 times.
15803 else if (stribegin(here, " = ")) { here+=3; mode=null; }
557
2/2
✓ Branch 0 taken 306 times.
✓ Branch 1 taken 13937 times.
14243 else if (stribegin(here, " += ")) { here+=4; mode=append; }
558
2/2
✓ Branch 0 taken 165 times.
✓ Branch 1 taken 13772 times.
13937 else if (stribegin(here, " := ")) { here+=4; mode=expand; }
559
2/2
✓ Branch 0 taken 5778 times.
✓ Branch 1 taken 7994 times.
13772 else if (stribegin(here, " #= ")) { here+=4; mode=domath; }
560
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 7982 times.
7994 else if (stribegin(here, " ?= ")) { here+=4; mode=setifnotset; }
561 7982 else goto notdefineset;
562 3918 string val;
563
2/2
✓ Branch 0 taken 561 times.
✓ Branch 1 taken 7260 times.
7821 if (*here=='"')
564 {
565 561 here++;
566 while (true)
567 {
568
2/2
✓ Branch 0 taken 579 times.
✓ Branch 1 taken 2484 times.
3063 if (*here=='"')
569 {
570
3/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 561 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
579 if (!here[1] || here[1]==' ') break;
571
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 else if (here[1]=='"') here++;
572 else asar_throw_error(0, error_type_line, error_id_broken_define_declaration);
573 }
574
1/2
✓ Branch 0 taken 2502 times.
✗ Branch 1 not taken.
2502 val+=*here++;
575 }
576 561 here++;
577 }
578 else
579 {
580
4/6
✓ Branch 0 taken 49917 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 49917 times.
✓ Branch 3 taken 7260 times.
✓ Branch 4 taken 49917 times.
✗ Branch 5 not taken.
57177 while (*here && *here!=' ') val+=*here++;
581 }
582 //if (strqchr(val.data(), ';')) *strqchr(val.data(), ';')=0;
583
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 7821 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3918 times.
7821 if (*here && !stribegin(here, " : ")) asar_throw_error(0, error_type_line, error_id_broken_define_declaration);
584 // RPG Hacker: Is it really a good idea to normalize
585 // the content of defines? That kinda violates their
586 // functionality as a string replacement mechanism.
587 //val.qnormalize();
588
589 // RPG Hacker: throw an error if we're trying to overwrite built-in defines.
590
3/4
✓ Branch 0 taken 7821 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 7803 times.
7821 if (builtindefines.exists(defname))
591 {
592 18 asar_throw_error(0, error_type_line, error_id_overriding_builtin_define, defname.data());
593 }
594
595
5/6
✓ Branch 0 taken 1542 times.
✓ Branch 1 taken 306 times.
✓ Branch 2 taken 165 times.
✓ Branch 3 taken 5778 times.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
7803 switch (mode)
596 {
597 777 case null:
598 {
599
2/4
✓ Branch 0 taken 1542 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 777 times.
✗ Branch 3 not taken.
1542 defines.create(defname) = val;
600 777 break;
601 }
602 153 case append:
603 {
604
2/4
✓ Branch 0 taken 306 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 306 times.
306 if (!defines.exists(defname)) asar_throw_error(0, error_type_line, error_id_define_not_found, defname.data());
605
2/4
✓ Branch 0 taken 306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 153 times.
✗ Branch 3 not taken.
306 string oldval = defines.find(defname);
606
2/4
✓ Branch 0 taken 306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 153 times.
✗ Branch 3 not taken.
306 val=oldval+val;
607
2/4
✓ Branch 0 taken 306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 153 times.
✗ Branch 3 not taken.
306 defines.create(defname) = val;
608 153 break;
609 306 }
610 84 case expand:
611 {
612 84 string newval;
613
1/2
✓ Branch 0 taken 165 times.
✗ Branch 1 not taken.
165 resolvedefines(newval, val);
614
2/4
✓ Branch 0 taken 165 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
165 defines.create(defname) = newval;
615 84 break;
616 165 }
617 2889 case domath:
618 {
619 2889 string newval;
620
1/2
✓ Branch 0 taken 5778 times.
✗ Branch 1 not taken.
5778 resolvedefines(newval, val);
621
1/2
✓ Branch 0 taken 5778 times.
✗ Branch 1 not taken.
5778 double num= getnumdouble(newval);
622
4/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 5742 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 18 times.
5778 if (foundlabel && !foundlabel_static) asar_throw_error(0, error_type_line, error_id_define_label_math);
623
2/4
✓ Branch 0 taken 5760 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5760 times.
✗ Branch 3 not taken.
5760 defines.create(defname) = ftostr(num);
624 2880 break;
625 5778 }
626 6 case setifnotset:
627 {
628
4/8
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
12 if (!defines.exists(defname)) defines.create(defname) = val;
629 6 break;
630 }
631 }
632 7821 }
633 else
634 {
635
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 10828 times.
17884 notdefineset:
636
3/4
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 21689 times.
✓ Branch 2 taken 189 times.
✗ Branch 3 not taken.
21878 if (!defname) out+="!";
637 else
638 {
639
3/4
✓ Branch 0 taken 21689 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 21688 times.
21689 if (!defines.exists(defname)) asar_throw_error(0, error_type_line, error_id_define_not_found, defname.data());
640 else {
641
2/4
✓ Branch 0 taken 21688 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10860 times.
✗ Branch 3 not taken.
21688 string thisone = defines.find(defname);
642
1/2
✓ Branch 0 taken 21688 times.
✗ Branch 1 not taken.
21688 resolvedefines(out, thisone);
643 21688 }
644 }
645 }
646
2/2
✓ Branch 0 taken 14859 times.
✓ Branch 1 taken 1956 times.
33662 }
647
1/2
✓ Branch 0 taken 181197 times.
✗ Branch 1 not taken.
181197 else out+=*here++;
648 }
649
5/8
✓ Branch 0 taken 31273 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 31255 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
31273 if (!confirmquotes(out)) { asar_throw_error(0, error_type_null, error_id_mismatched_quotes); out = ""; }
650
2/2
✓ Branch 0 taken 15660 times.
✓ Branch 1 taken 78481 times.
193186 }
651
652 bool moreonline;
653 bool asarverallowed = false;
654
655 160785 void assembleline(const char * fname, int linenum, const char * line, int& single_line_for_tracker)
656 {
657
1/2
✓ Branch 0 taken 77952 times.
✗ Branch 1 not taken.
77952 recurseblock rec;
658
1/2
✓ Branch 0 taken 82833 times.
✗ Branch 1 not taken.
160785 bool moreonlinetmp=moreonline;
659 // randomdude999: redundant, assemblefile already converted the path to absolute
660 //string absolutepath = filesystem->create_absolute_path("", fname);
661
1/2
✓ Branch 0 taken 77952 times.
✗ Branch 1 not taken.
77952 string absolutepath = fname;
662
1/2
✓ Branch 0 taken 82833 times.
✗ Branch 1 not taken.
160785 single_line_for_tracker = 1;
663 try
664 {
665
1/2
✓ Branch 0 taken 77952 times.
✗ Branch 1 not taken.
77952 string out=line;
666
1/2
✓ Branch 0 taken 160785 times.
✗ Branch 1 not taken.
160785 autoptr<char**> blocks=qsplitstr(out.temp_raw(), " : ");
667 160785 moreonline=true;
668
2/2
✓ Branch 0 taken 166254 times.
✓ Branch 1 taken 135927 times.
302181 for (int block=0;moreonline;block++)
669 {
670 166254 moreonline=(blocks[block+1] != nullptr);
671 try
672 {
673 // it's possible that our input looks something like:
674 // nop : : nop
675 // nop : : : : : nop
676 // also, it's possible that there were empty blocks at the start or end of the line:
677 // : nop :
678 // after qsplit, we still need to deal with possibly a single ": " from a preceding empty block,
679 // and if it's the last block, possibly a following " :".
680
1/2
✓ Branch 0 taken 80721 times.
✗ Branch 1 not taken.
166254 string stripped_block = strip_whitespace(blocks[block]);
681 80721 int i = 0;
682 // if the block starts with ": "
683
6/6
✓ Branch 0 taken 162 times.
✓ Branch 1 taken 166092 times.
✓ Branch 2 taken 72 times.
✓ Branch 3 taken 90 times.
✓ Branch 4 taken 36 times.
✓ Branch 5 taken 80685 times.
166254 if(stripped_block[i] == ':' && stripped_block[i+1] == ' ') {
684 36 i++;
685
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 72 times.
144 while(stripped_block[i] == ' ') i++;
686 }
687 // if the block is a single :, skip that too.
688
5/6
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 166164 times.
✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 45 times.
✓ Branch 5 taken 80676 times.
166254 if(stripped_block[i] == ':' && stripped_block[i+1] == 0) i++;
689
690 // last block - strip trailing " :" if present.
691
10/10
✓ Branch 0 taken 160785 times.
✓ Branch 1 taken 5469 times.
✓ Branch 2 taken 110469 times.
✓ Branch 3 taken 50316 times.
✓ Branch 4 taken 9342 times.
✓ Branch 5 taken 101127 times.
✓ Branch 6 taken 36 times.
✓ Branch 7 taken 9306 times.
✓ Branch 8 taken 18 times.
✓ Branch 9 taken 80703 times.
166254 if(!moreonline && stripped_block.length() >= 2 && stripped_block[stripped_block.length()-2] == ' ' && stripped_block[stripped_block.length()-1] == ':') {
692
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 stripped_block.truncate(stripped_block.length()-2);
693 }
694
695
1/2
✓ Branch 0 taken 166254 times.
✗ Branch 1 not taken.
166254 callstack_push cs_push(callstack_entry_type::BLOCK, stripped_block.data() + i);
696
697
2/2
✓ Branch 0 taken 140406 times.
✓ Branch 1 taken 25848 times.
166254 assembleblock(stripped_block.data() + i, single_line_for_tracker);
698
2/2
✓ Branch 0 taken 140394 times.
✓ Branch 1 taken 12 times.
140406 checkbankcross();
699 192114 }
700
2/2
✓ Branch 0 taken 24858 times.
✓ Branch 1 taken 1002 times.
25860 catch (errblock&) {}
701
2/2
✓ Branch 0 taken 91626 times.
✓ Branch 1 taken 49770 times.
141396 if (blocks[block][0]!='\0') asarverallowed=false;
702
2/2
✓ Branch 0 taken 134937 times.
✓ Branch 1 taken 6459 times.
141396 if(single_line_for_tracker == 1) single_line_for_tracker = 0;
703 }
704 185643 }
705
1/2
✓ Branch 0 taken 24858 times.
✗ Branch 1 not taken.
24858 catch (errline&) {}
706 135927 moreonline=moreonlinetmp;
707 185643 }
708
709 int incsrcdepth=0;
710
711 // Returns true if a file is protected via
712 // an "includeonce".
713 27708 bool file_included_once(const char* file)
714 {
715
2/2
✓ Branch 0 taken 720 times.
✓ Branch 1 taken 27582 times.
28302 for (int i = 0; i < includeonce.count; ++i)
716 {
717
2/2
✓ Branch 0 taken 360 times.
✓ Branch 1 taken 360 times.
720 if (includeonce[i] == file)
718 {
719 63 return true;
720 }
721 }
722
723 11268 return false;
724 }
725
726 autoarray<string> macro_defs;
727 int in_macro_def=0;
728
729 27618 void assemblefile(const char * filename)
730 {
731 27618 incsrcdepth++;
732
2/4
✓ Branch 0 taken 11286 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11286 times.
✗ Branch 3 not taken.
27618 string absolutepath = filesystem->create_absolute_path(get_current_file_name(), filename);
733
734
4/4
✓ Branch 0 taken 27555 times.
✓ Branch 1 taken 63 times.
✓ Branch 2 taken 63 times.
✓ Branch 3 taken 11223 times.
27618 if (file_included_once(absolutepath))
735 {
736 63 return;
737 }
738
739
1/2
✓ Branch 0 taken 11223 times.
✗ Branch 1 not taken.
11223 callstack_push cs_push(callstack_entry_type::FILE, absolutepath);
740
741 sourcefile file;
742 27492 file.contents = nullptr;
743 27492 file.numlines = 0;
744
1/2
✓ Branch 0 taken 16269 times.
✗ Branch 1 not taken.
27492 int startif=numif;
745
3/4
✓ Branch 0 taken 27492 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 928 times.
✓ Branch 3 taken 26564 times.
27492 if (!filecontents.exists(absolutepath))
746 {
747
2/2
✓ Branch 0 taken 922 times.
✓ Branch 1 taken 6 times.
928 char * temp = readfile(absolutepath, "");
748
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 904 times.
922 if (!temp)
749 {
750
6/12
✓ Branch 0 taken 15 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 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
18 asar_throw_error(0, error_type_null, vfile_error_to_error_id(asar_get_last_io_error()), filename);
751
752 9 return;
753 }
754
1/2
✓ Branch 0 taken 904 times.
✗ Branch 1 not taken.
904 sourcefile& newfile = filecontents.create(absolutepath);
755
1/2
✓ Branch 0 taken 904 times.
✗ Branch 1 not taken.
904 newfile.contents =split(temp, '\n');
756 904 newfile.data = temp;
757
2/2
✓ Branch 0 taken 35365 times.
✓ Branch 1 taken 904 times.
36269 for (int i=0;newfile.contents[i];i++)
758 {
759 35365 newfile.numlines++;
760 17730 char * line = newfile.contents[i];
761 17730 int i_temp = i;
762 char * comment;
763
2/2
✓ Branch 0 taken 9378 times.
✓ Branch 1 taken 35359 times.
44737 while((comment = strqchr(line, ';'))) {
764
3/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 9342 times.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
9378 if(comment[1] == '[' && comment[2] == '[') {
765 // block comment - find where it ends
766 36 char* theline = comment + 3;
767 36 char* comment_end = strstr(theline, "]]");
768
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 30 times.
90 while(comment_end == nullptr) {
769 60 i_temp++;
770 60 char* new_line = newfile.contents[i_temp];
771
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 54 times.
60 if(new_line == nullptr) {
772
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 callstack_push cs_push(callstack_entry_type::LINE, line, i);
773
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 asar_throw_error(0, error_type_null, error_id_unclosed_block_comment);
774 // make sure this line is still parsed correctly
775 6 *comment = 0;
776 // but don't go looking at any other lines
777 6 goto break_outer;
778 6 }
779 54 comment_end = strstr(new_line, "]]");
780 // this line is itself part of the comment, so ignore it
781 //new_line[0] = 0;
782 // except not like that^, because that will break the
783 // memmove below
784 static char junk[]="";
785 // using a static here should be fine, since if the line
786 // doesn't contain ',' or '\' we won't go mutating it
787 54 newfile.contents[i_temp] = junk;
788 }
789 // comment_end+2 is a valid pointer, since comment_end is
790 // guaranteed to start with ]]
791 30 comment_end += 2;
792 // stitch together the part of the line before the comment,
793 // and the part of the line after it
794 30 memmove(comment, comment_end, strlen(comment_end) + 1);
795 // and then recheck for ; in the line again...
796 30 } else {
797 9342 *comment = 0;
798 }
799 }
800 35359 break_outer:
801
3/4
✓ Branch 0 taken 35365 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 35353 times.
35365 if (!confirmquotes(line)) {
802
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 callstack_push cs_push(callstack_entry_type::LINE, line, i);
803
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 asar_throw_error(0, error_type_null, error_id_mismatched_quotes);
804 12 line[0] = '\0';
805 12 }
806 35365 newfile.contents[i] = strip_whitespace(line);
807 }
808
2/2
✓ Branch 0 taken 35365 times.
✓ Branch 1 taken 904 times.
36269 for(int i=0;newfile.contents[i];i++)
809 {
810 17730 char* line = newfile.contents[i];
811
2/2
✓ Branch 0 taken 13400 times.
✓ Branch 1 taken 21965 times.
35365 if(!*line) continue;
812
3/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 21965 times.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
21995 for (int j=1;line[strlen(line) - 1] == ',' && newfile.contents[i+j];j++)
813 {
814 // not using strcat because the source and dest overlap here
815 15 char* otherline = newfile.contents[i+j];
816 30 char* line_end = line + strlen(line);
817
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 30 times.
414 while(*otherline) *line_end++ = *otherline++;
818 30 *line_end = '\0';
819 static char nullstr[]="";
820 30 newfile.contents[i+j]=nullstr;
821 }
822 }
823 904 file = newfile;
824 } else { // filecontents.exists(absolutepath)
825
1/2
✓ Branch 0 taken 26564 times.
✗ Branch 1 not taken.
26564 file = filecontents.find(absolutepath);
826 }
827 27468 asarverallowed=true;
828
3/4
✓ Branch 0 taken 150021 times.
✓ Branch 1 taken 2604 times.
✓ Branch 2 taken 150021 times.
✗ Branch 3 not taken.
152625 for (int i=0;file.contents[i] && i<file.numlines;i++)
829 {
830 72573 string connectedline;
831
1/2
✓ Branch 0 taken 150021 times.
✗ Branch 1 not taken.
150021 int skiplines = getconnectedlines<char**>(file.contents, i, connectedline);
832
833
2/2
✓ Branch 0 taken 125157 times.
✓ Branch 1 taken 24864 times.
150021 bool was_loop_end = do_line_logic(connectedline, absolutepath, i);
834 125157 i += skiplines;
835
836 // if a loop ended on this line, should it run again?
837
8/8
✓ Branch 0 taken 6318 times.
✓ Branch 1 taken 118839 times.
✓ Branch 2 taken 4320 times.
✓ Branch 3 taken 1998 times.
✓ Branch 4 taken 1998 times.
✓ Branch 5 taken 1161 times.
✓ Branch 6 taken 1998 times.
✓ Branch 7 taken 60723 times.
125157 if (was_loop_end && whilestatus[numif].cond)
838
1/2
✓ Branch 0 taken 1998 times.
✗ Branch 1 not taken.
3996 i = whilestatus[numif].startline - 1;
839 150021 }
840
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 2604 times.
2640 while (in_macro_def > 0)
841 {
842
2/4
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
36 asar_throw_error(0, error_type_null, error_id_unclosed_macro, macro_defs[in_macro_def-1].data());
843
5/6
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
36 if (!pass && in_macro_def == 1) endmacro(false);
844 36 in_macro_def--;
845 36 macro_defs.remove(in_macro_def);
846 }
847
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2604 times.
2604 if (numif!=startif)
848 {
849 numif=startif;
850 numtrue=startif;
851 asar_throw_error(0, error_type_null, error_id_unclosed_if);
852 }
853 2604 incsrcdepth--;
854
4/4
✓ Branch 0 taken 1359 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 1359 times.
✓ Branch 3 taken 72 times.
52497 }
855
856 // RPG Hacker: At some point, this should probably be merged
857 // into assembleline(), since the two names just cause
858 // confusion otherwise.
859 // return value is "did a loop end on this line"
860 171105 bool do_line_logic(const char* line, const char* filename, int lineno)
861 {
862 171105 int prevnumif = numif;
863
2/2
✓ Branch 0 taken 5049 times.
✓ Branch 1 taken 82935 times.
171105 int single_line_for_tracker = 1;
864 try
865 {
866 83121 string current_line;
867
8/8
✓ Branch 0 taken 10098 times.
✓ Branch 1 taken 161007 times.
✓ Branch 2 taken 8640 times.
✓ Branch 3 taken 1458 times.
✓ Branch 4 taken 504 times.
✓ Branch 5 taken 8136 times.
✓ Branch 6 taken 78324 times.
✓ Branch 7 taken 4797 times.
171105 if (numif==numtrue || (numtrue+1==numif && stribegin(line, "elseif ")))
868 {
869
1/2
✓ Branch 0 taken 78324 times.
✗ Branch 1 not taken.
78324 callstack_push cs_push(callstack_entry_type::LINE, line, lineno);
870
2/2
✓ Branch 0 taken 161205 times.
✓ Branch 1 taken 306 times.
161511 string tmp=replace_macro_args(line);
871
1/2
✓ Branch 0 taken 161205 times.
✗ Branch 1 not taken.
161205 tmp.qnormalize();
872
2/2
✓ Branch 0 taken 161109 times.
✓ Branch 1 taken 96 times.
161205 resolvedefines(current_line, tmp);
873
2/4
✓ Branch 0 taken 161109 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 161109 times.
161109 if (!confirmquotes(current_line)) asar_throw_error(0, error_type_line, error_id_mismatched_quotes);
874 161607 }
875
1/2
✓ Branch 0 taken 4797 times.
✗ Branch 1 not taken.
4797 else current_line=line;
876
877
1/2
✓ Branch 0 taken 82920 times.
✗ Branch 1 not taken.
82920 callstack_push cs_push(callstack_entry_type::LINE, current_line, lineno);
878
879
6/6
✓ Branch 0 taken 1662 times.
✓ Branch 1 taken 169041 times.
✓ Branch 2 taken 834 times.
✓ Branch 3 taken 828 times.
✓ Branch 4 taken 780 times.
✓ Branch 5 taken 82140 times.
170703 if (stribegin(current_line, "macro ") && numif==numtrue)
880 {
881 // RPG Hacker: Slight redundancy here with code that is
882 // also in startmacro(). Could improve this for Asar 2.0.
883
1/2
✓ Branch 0 taken 1554 times.
✗ Branch 1 not taken.
1554 string macro_name = current_line.data()+6;
884 1554 char * startpar=strqchr(macro_name.data(), '(');
885
1/2
✓ Branch 0 taken 1554 times.
✗ Branch 1 not taken.
1554 if (startpar) *startpar=0;
886
1/2
✓ Branch 0 taken 1554 times.
✗ Branch 1 not taken.
1554 macro_defs.append(macro_name);
887
888 // RPG Hacker: I think it would make more logical sense
889 // to have this ++ after the if, but hat breaks compatibility
890 // with at least one test, and it generally leads to more
891 // errors being output after a broken macro declaration.
892 1554 in_macro_def++;
893
2/2
✓ Branch 0 taken 518 times.
✓ Branch 1 taken 1036 times.
1554 if (!pass)
894 {
895
4/4
✓ Branch 0 taken 422 times.
✓ Branch 1 taken 96 times.
✓ Branch 2 taken 416 times.
✓ Branch 3 taken 6 times.
518 if (in_macro_def == 1) startmacro(current_line.data()+6);
896
1/2
✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
96 else tomacro(current_line);
897 }
898 1554 }
899
6/6
✓ Branch 0 taken 87825 times.
✓ Branch 1 taken 81324 times.
✓ Branch 2 taken 1572 times.
✓ Branch 3 taken 86253 times.
✓ Branch 4 taken 816 times.
✓ Branch 5 taken 82134 times.
169149 else if (!stricmp(current_line, "endmacro") && numif==numtrue)
900 {
901
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1518 times.
1518 if (in_macro_def == 0) asar_throw_error(0, error_type_line, error_id_misplaced_endmacro);
902 else
903 {
904 1518 in_macro_def--;
905 1518 macro_defs.remove(in_macro_def);
906
2/2
✓ Branch 0 taken 506 times.
✓ Branch 1 taken 1012 times.
1518 if (!pass)
907 {
908
3/4
✓ Branch 0 taken 416 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 416 times.
✗ Branch 3 not taken.
506 if (in_macro_def == 0) endmacro(true);
909
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 else tomacro(current_line);
910 }
911 }
912 }
913
2/2
✓ Branch 0 taken 6846 times.
✓ Branch 1 taken 160785 times.
167631 else if (in_macro_def > 0)
914 {
915
3/4
✓ Branch 0 taken 2282 times.
✓ Branch 1 taken 4564 times.
✓ Branch 2 taken 2282 times.
✗ Branch 3 not taken.
6846 if (!pass) tomacro(current_line);
916 }
917 else
918 {
919
2/2
✓ Branch 0 taken 135927 times.
✓ Branch 1 taken 24858 times.
160785 assembleline(filename, lineno, current_line, single_line_for_tracker);
920 }
921 195969 }
922
2/2
✓ Branch 0 taken 24864 times.
✓ Branch 1 taken 402 times.
25266 catch (errline&) {}
923
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 129453 times.
129633 return (numif != prevnumif || single_line_for_tracker == 3)
924
9/10
✓ Branch 0 taken 129633 times.
✓ Branch 1 taken 16608 times.
✓ Branch 2 taken 12975 times.
✓ Branch 3 taken 3813 times.
✓ Branch 4 taken 8035 times.
✓ Branch 5 taken 4940 times.
✓ Branch 6 taken 4581 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1127 times.
✓ Branch 9 taken 3454 times.
292572 && (whilestatus[numif].iswhile || whilestatus[numif].is_for);
925 }
926
927
928 511 void parse_std_includes(const char* textfile, autoarray<string>& outarray)
929 {
930 511 char* content = readfilenative(textfile);
931
932
1/2
✓ Branch 0 taken 511 times.
✗ Branch 1 not taken.
511 if (content != nullptr)
933 {
934 257 char* pos = content;
935
936
2/2
✓ Branch 0 taken 1024 times.
✓ Branch 1 taken 511 times.
1535 while (pos[0] != '\0')
937 {
938 516 string stdinclude;
939
940 do
941 {
942
3/4
✓ Branch 0 taken 25294 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24781 times.
✓ Branch 3 taken 513 times.
25294 if (pos[0] != '\r' && pos[0] != '\n')
943 {
944
1/2
✓ Branch 0 taken 24781 times.
✗ Branch 1 not taken.
24781 stdinclude += pos[0];
945 }
946 25294 pos++;
947
4/4
✓ Branch 0 taken 24783 times.
✓ Branch 1 taken 511 times.
✓ Branch 2 taken 24270 times.
✓ Branch 3 taken 513 times.
25294 } while (pos[0] != '\0' && pos[0] != '\n');
948
949
1/2
✓ Branch 0 taken 1024 times.
✗ Branch 1 not taken.
1024 strip_whitespace(stdinclude);
950
951
2/2
✓ Branch 0 taken 513 times.
✓ Branch 1 taken 511 times.
1024 if (stdinclude != "")
952 {
953
3/4
✓ Branch 0 taken 513 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 512 times.
513 if (!path_is_absolute(stdinclude))
954 {
955
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 stdinclude = dir(textfile) + stdinclude;
956 }
957
2/4
✓ Branch 0 taken 513 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 513 times.
✗ Branch 3 not taken.
513 outarray.append(normalize_path(stdinclude));
958 }
959 1024 }
960
961 511 free(content);
962 }
963 511 }
964
965 787 void parse_std_defines(const char* textfile)
966 {
967
968 // RPG Hacker: add built-in defines.
969 // (They're not really standard defines, but I was lazy and this was
970 // one convenient place for doing it).
971 787 builtindefines.create("assembler") = "asar";
972
5/8
✓ Branch 0 taken 658 times.
✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 280 times.
✓ Branch 4 taken 129 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 280 times.
✗ Branch 7 not taken.
787 builtindefines.create("assembler_ver") = dec(get_version_int());
973
2/4
✓ Branch 0 taken 787 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 409 times.
✗ Branch 3 not taken.
787 builtindefines.create("assembler_time") = dec(time(nullptr));
974
975
2/2
✓ Branch 0 taken 406 times.
✓ Branch 1 taken 381 times.
787 if(textfile == nullptr) return;
976
977 511 char* content = readfilenative(textfile);
978
979
1/2
✓ Branch 0 taken 511 times.
✗ Branch 1 not taken.
511 if (content != nullptr)
980 {
981 257 char* pos = content;
982
2/2
✓ Branch 0 taken 3065 times.
✓ Branch 1 taken 511 times.
3576 while (*pos != 0) {
983 1541 string define_name;
984 1541 string define_val;
985
986
4/4
✓ Branch 0 taken 30627 times.
✓ Branch 1 taken 2042 times.
✓ Branch 2 taken 29604 times.
✓ Branch 3 taken 1023 times.
32669 while (*pos != '=' && *pos != '\n') {
987
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29604 times.
29604 if(*pos == '\r') { pos++; continue; }
988
1/2
✓ Branch 0 taken 29604 times.
✗ Branch 1 not taken.
29604 define_name += *pos;
989 29604 pos++;
990 }
991
5/6
✓ Branch 0 taken 2557 times.
✓ Branch 1 taken 508 times.
✓ Branch 2 taken 1541 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1026 times.
✓ Branch 5 taken 515 times.
3065 if (*pos != 0 && *pos != '\r' && *pos != '\n') pos++; // skip =
992
3/4
✓ Branch 0 taken 13788 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10723 times.
✓ Branch 3 taken 3065 times.
13788 while (*pos != 0 && *pos != '\n') {
993
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10723 times.
10723 if(*pos == '\r') { pos++; continue; }
994
1/2
✓ Branch 0 taken 10723 times.
✗ Branch 1 not taken.
10723 define_val += *pos;
995 10723 pos++;
996 }
997
1/2
✓ Branch 0 taken 3065 times.
✗ Branch 1 not taken.
3065 if (*pos != 0)
998 3065 pos++; // skip \n
999 // clean define_name
1000
1/2
✓ Branch 0 taken 3065 times.
✗ Branch 1 not taken.
3065 strip_whitespace(define_name);
1001
1/2
✓ Branch 0 taken 3065 times.
✗ Branch 1 not taken.
3065 define_name.strip_prefix('!'); // remove leading ! if present
1002
1003
2/2
✓ Branch 0 taken 511 times.
✓ Branch 1 taken 2554 times.
3065 if (define_name == "")
1004 {
1005
1/2
✓ Branch 0 taken 511 times.
✗ Branch 1 not taken.
511 if (define_val == "")
1006 {
1007 511 continue;
1008 }
1009
1010 asar_throw_error(pass, error_type_null, error_id_stddefines_no_identifier);
1011 }
1012
1013
3/8
✓ Branch 0 taken 639 times.
✓ Branch 1 taken 1915 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 639 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2554 if (!validatedefinename(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_invalid, "stddefines.txt", define_name.data());
1014
1015 // clean define_val
1016 1284 const char* defval = define_val.data();
1017 1284 string cleaned_defval;
1018
1019
2/2
✓ Branch 0 taken 512 times.
✓ Branch 1 taken 2042 times.
2554 if (*defval == 0) {
1020 // no value
1021
2/6
✓ Branch 0 taken 512 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 512 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
512 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
1022
2/4
✓ Branch 0 taken 512 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 258 times.
✗ Branch 3 not taken.
512 clidefines.create(define_name) = "";
1023 512 continue;
1024 }
1025
1026
3/4
✓ Branch 0 taken 1022 times.
✓ Branch 1 taken 2042 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2042 times.
3064 while (*defval == ' ' || *defval == '\t') defval++; // skip whitespace in beginning
1027
2/2
✓ Branch 0 taken 511 times.
✓ Branch 1 taken 1531 times.
2042 if (*defval == '"') {
1028 511 defval++; // skip opening quote
1029
3/4
✓ Branch 0 taken 6635 times.
✓ Branch 1 taken 511 times.
✓ Branch 2 taken 6635 times.
✗ Branch 3 not taken.
7146 while (*defval != '"' && *defval != 0)
1030
1/2
✓ Branch 0 taken 6635 times.
✗ Branch 1 not taken.
6635 cleaned_defval += *defval++;
1031
1032
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 511 times.
511 if (*defval == 0) {
1033 asar_throw_error(pass, error_type_null, error_id_mismatched_quotes);
1034 }
1035 511 defval++; // skip closing quote
1036
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 511 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 511 times.
511 while (*defval == ' ' || *defval == '\t') defval++; // skip whitespace
1037
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 511 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
511 if (*defval != 0 && *defval != '\n')
1038 asar_throw_error(pass, error_type_null, error_id_stddefine_after_closing_quote);
1039
1040
2/6
✓ Branch 0 taken 511 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 511 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
511 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
1041
2/4
✓ Branch 0 taken 511 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 257 times.
✗ Branch 3 not taken.
511 clidefines.create(define_name) = cleaned_defval;
1042 511 continue;
1043 }
1044 else
1045 {
1046 // slightly hacky way to remove trailing whitespace
1047 1531 const char* defval_end = strchr(defval, '\n'); // slightly hacky way to get end of string or newline
1048
1/2
✓ Branch 0 taken 1531 times.
✗ Branch 1 not taken.
1531 if (!defval_end) defval_end = strchr(defval, 0);
1049 1531 defval_end--;
1050
3/4
✓ Branch 0 taken 513 times.
✓ Branch 1 taken 1531 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1531 times.
2044 while (*defval_end == ' ' || *defval_end == '\t') defval_end--;
1051
2/4
✓ Branch 0 taken 1531 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 762 times.
✗ Branch 3 not taken.
1531 cleaned_defval = string(defval, (int)(defval_end - defval + 1));
1052
1053
2/6
✓ Branch 0 taken 1531 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1531 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1531 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
1054
2/4
✓ Branch 0 taken 1531 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 769 times.
✗ Branch 3 not taken.
1531 clidefines.create(define_name) = cleaned_defval;
1055 1531 continue;
1056 1531 }
1057
1058 3065 }
1059 511 free(content);
1060 }
1061 }
1062
1063 bool checksum_fix_enabled = true;
1064 bool force_checksum_fix = false;
1065
1066 #define cfree(x) free((void*)x)
1067 414 static void clearmacro(const string & key, macrodata* & macro)
1068 {
1069 (void)key;
1070 414 freemacro(macro);
1071 414 }
1072
1073 903 static void clearfile(const string & key, sourcefile& filecontent)
1074 {
1075 (void)key;
1076 903 cfree(filecontent.data);
1077 903 cfree(filecontent.contents);
1078 903 }
1079 #undef cfree
1080
1081 4908 static void adddefine(const string & key, string & value)
1082 {
1083
1/2
✓ Branch 0 taken 4908 times.
✗ Branch 1 not taken.
4908 if (!defines.exists(key)) defines.create(key) = value;
1084 4908 }
1085
1086
1/2
✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
186 string create_symbols_file(string format, uint32_t romCrc){
1087 94 string symbolfile;
1088
1089 94 std::vector<std::pair<unsigned int, const char*>> all_labels;
1090
1/2
✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
372 labels.each([&all_labels](const string& key, snes_label& label) {
1091
2/4
✓ Branch 0 taken 190 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 190 times.
✗ Branch 3 not taken.
376 all_labels.push_back(std::make_pair(label.pos, key.data()));
1092 376 });
1093
1/2
✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
186 std::sort(all_labels.begin(), all_labels.end(),
1094 882 [](auto& l, auto& r) {
1095
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 796 times.
882 if (l.first == r.first)
1096 86 return strcmp(l.second, r.second) < 0;
1097 796 return l.first < r.first;
1098 });
1099
1100
1/2
✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
186 format = lower(format);
1101
1/2
✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
186 if(format == "wla")
1102 {
1103
1/2
✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
94 symbolfile = "; wla symbolic information file\n";
1104
1/2
✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
186 symbolfile += "; generated by asar\n";
1105
1106
1/2
✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
186 symbolfile += "\n[labels]\n";
1107
2/2
✓ Branch 0 taken 376 times.
✓ Branch 1 taken 186 times.
562 for (auto& p : all_labels) {
1108 char buffer[10];
1109
1/2
✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
376 std::snprintf(buffer, sizeof(buffer), "%02X:%04X ", (p.first >> 16) & 0xFF, p.first & 0xFFFF);
1110
1111
1/2
✓ Branch 0 taken 376 times.
✗ Branch 1 not taken.
376 symbolfile += buffer;
1112
1/2
✓ Branch 0 taken 376 times.
✗ Branch 1 not taken.
376 symbolfile += p.second;
1113
1/2
✓ Branch 0 taken 376 times.
✗ Branch 1 not taken.
376 symbolfile += "\n";
1114 }
1115
1116
1/2
✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
186 symbolfile += "\n[source files]\n";
1117 94 const autoarray<AddressToLineMapping::FileInfo>& addrToLineFileList = addressToLineMapping.getFileList();
1118
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 186 times.
378 for (int i = 0; i < addrToLineFileList.count; ++i)
1119 {
1120 char addrToFileListStr[256];
1121 289 snprintf(addrToFileListStr, 256, "%.4x %.8x %s\n",
1122 i,
1123
1/2
✓ Branch 0 taken 192 times.
✗ Branch 1 not taken.
192 addrToLineFileList[i].fileCrc,
1124
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 addrToLineFileList[i].filename.data()
1125 );
1126
1/2
✓ Branch 0 taken 192 times.
✗ Branch 1 not taken.
192 symbolfile += addrToFileListStr;
1127 }
1128
1129
1/2
✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
186 symbolfile += "\n[rom checksum]\n";
1130 {
1131 char romCrcStr[32];
1132
1/2
✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
186 snprintf(romCrcStr, 32, "%.8x\n",
1133 romCrc
1134 );
1135
1/2
✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
186 symbolfile += romCrcStr;
1136 }
1137
1138
1/2
✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
186 symbolfile += "\n[addr-to-line mapping]\n";
1139 94 const autoarray<AddressToLineMapping::AddrToLineInfo>& addrToLineInfo = addressToLineMapping.getAddrToLineInfo();
1140
2/2
✓ Branch 0 taken 5468 times.
✓ Branch 1 taken 186 times.
5654 for (int i = 0; i < addrToLineInfo.count; ++i)
1141 {
1142 char addrToLineStr[32];
1143 13679 snprintf(addrToLineStr, 32, "%.2x:%.4x %.4x:%.8x\n",
1144 8205 (addrToLineInfo[i].addr & 0xFF0000) >> 16,
1145
1/2
✓ Branch 0 taken 2737 times.
✗ Branch 1 not taken.
5468 addrToLineInfo[i].addr & 0xFFFF,
1146
1/2
✓ Branch 0 taken 2737 times.
✗ Branch 1 not taken.
5468 addrToLineInfo[i].fileIdx & 0xFFFF,
1147
2/4
✓ Branch 0 taken 5468 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2737 times.
✗ Branch 3 not taken.
5468 addrToLineInfo[i].line & 0xFFFFFFFF
1148 );
1149
1/2
✓ Branch 0 taken 5468 times.
✗ Branch 1 not taken.
5468 symbolfile += addrToLineStr;
1150 }
1151
1152 }
1153 else if (format == "nocash")
1154 {
1155 symbolfile = ";no$sns symbolic information file\n";
1156 symbolfile += ";generated by asar\n";
1157 symbolfile += "\n";
1158 for (auto& p : all_labels) {
1159 char buffer[10];
1160 std::snprintf(buffer, sizeof(buffer), "%08X ", p.first & 0xFFFFFF);
1161
1162 symbolfile += buffer;
1163 symbolfile += p.second;
1164 symbolfile += "\n";
1165 }
1166 }
1167 280 return symbolfile;
1168 94 }
1169
1170
1171 6 bool in_top_level_file()
1172 {
1173 3 int num_files = 0;
1174
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 6 times.
30 for (int i = callstack.count-1; i >= 0; --i)
1175 {
1176
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 18 times.
24 if (callstack[i].type == callstack_entry_type::FILE)
1177 {
1178 6 num_files++;
1179
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (num_files > 1) break;
1180 }
1181 }
1182 6 return (num_files <= 1);
1183 }
1184
1185 45470 const char* get_current_file_name()
1186 {
1187
2/2
✓ Branch 0 taken 171524 times.
✓ Branch 1 taken 2302 times.
173826 for (int i = callstack.count-1; i >= 0; --i)
1188 {
1189
2/2
✓ Branch 0 taken 43168 times.
✓ Branch 1 taken 128356 times.
171524 if (callstack[i].type == callstack_entry_type::FILE)
1190 43168 return callstack[i].content.raw();
1191 }
1192 1198 return nullptr;
1193 }
1194
1195 26906 int get_current_line()
1196 {
1197
2/2
✓ Branch 0 taken 79603 times.
✓ Branch 1 taken 21 times.
79624 for (int i = callstack.count-1; i >= 0; --i)
1198 {
1199
2/2
✓ Branch 0 taken 26885 times.
✓ Branch 1 taken 52718 times.
93026 if (callstack[i].type == callstack_entry_type::LINE) return callstack[i].lineno;
1200 }
1201 11 return -1;
1202 }
1203
1204 774 const char* get_current_block()
1205 {
1206
2/2
✓ Branch 0 taken 779 times.
✓ Branch 1 taken 31 times.
810 for (int i = callstack.count-1; i >= 0; --i)
1207 {
1208
6/6
✓ Branch 0 taken 611 times.
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 575 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 374 times.
✓ Branch 5 taken 18 times.
1451 if (callstack[i].type == callstack_entry_type::LINE || callstack[i].type == callstack_entry_type::BLOCK) return callstack[i].content.raw();
1209 }
1210 16 return nullptr;
1211 }
1212
1213
1214 792 void reseteverything()
1215 {
1216 412 string str;
1217 412 labels.reset();
1218 412 defines.reset();
1219
1/2
✓ Branch 0 taken 792 times.
✗ Branch 1 not taken.
792 builtindefines.each(adddefine);
1220
1/2
✓ Branch 0 taken 792 times.
✗ Branch 1 not taken.
792 clidefines.each(adddefine);
1221 412 structs.reset();
1222
1223
1/2
✓ Branch 0 taken 792 times.
✗ Branch 1 not taken.
792 macros.each(clearmacro);
1224 412 macros.reset();
1225
1226
1/2
✓ Branch 0 taken 792 times.
✗ Branch 1 not taken.
792 filecontents.each(clearfile);
1227 412 filecontents.reset();
1228
1229 792 writtenblocks.reset();
1230
1231 792 optimizeforbank=-1;
1232 792 optimize_dp = optimize_dp_flag::ALWAYS;
1233 792 dp_base = 0;
1234 792 optimize_address = optimize_address_flag::MIRRORS;
1235
1236
1/2
✓ Branch 0 taken 792 times.
✗ Branch 1 not taken.
792 closecachedfiles();
1237
1238 792 incsrcdepth=0;
1239 792 label_counter = 0;
1240 792 errored = false;
1241 792 checksum_fix_enabled = true;
1242 792 force_checksum_fix = false;
1243
1244 792 in_macro_def = 0;
1245
1246 #ifndef ASAR_SHARED
1247 256 free(const_cast<unsigned char*>(romdata_r));
1248 #endif
1249
1250 792 callstack.reset();
1251 792 simple_callstacks = true;
1252 #undef free
1253 792 }
1254