asar coverage - build #97


src/asar/
File: src/asar/main.cpp
Date: 2024-01-19 19:01:19
Lines:
658/699
94.1%
Functions:
37/38
97.4%
Branches:
711/1089
65.3%

Line Branch Exec Source
1 // "because satanism is best defeated by summoning a bigger satan"
2 // ~Alcaro, 2019 (discussing Asar)
3 #include "addr2line.h"
4 #include "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 <ctime>
11 // randomdude999: remember to also update the .rc files (in res/windows/) when changing this.
12 // Couldn't find a way to automate this without shoving the version somewhere in the CMake files
13 const int asarver_maj=2;
14 const int asarver_min=0;
15 const int asarver_bug=0;
16 const bool asarver_beta=true;
17
18 #ifdef _I_RELEASE
19 extern char blockbetareleases[(!asarver_beta)?1:-1];
20 #endif
21 #ifdef _I_DEBUG
22 extern char blockreleasedebug[(asarver_beta)?1:-1];
23 #endif
24
25 unsigned const char * romdata_r;
26 int romlen_r;
27
28 int pass;
29
30 int optimizeforbank=-1;
31 int optimize_dp = optimize_dp_flag::NONE;
32 int dp_base = 0;
33 int optimize_address = optimize_address_flag::DEFAULT;
34
35 autoarray<callstack_entry> callstack;
36
37 bool errored=false;
38 bool ignoretitleerrors=false;
39
40 volatile int recursioncount=0;
41
42 virtual_filesystem* filesystem = nullptr;
43
44 AddressToLineMapping addressToLineMapping;
45
46 889 int get_version_int()
47 {
48 889 return asarver_maj * 10000 + asarver_min * 100 + asarver_bug;
49 }
50
51 56 bool setmapper()
52 {
53 56 int maxscore=-99999;
54 56 mapper_t bestmap=lorom;
55 56 mapper_t maps[]={lorom, hirom, exlorom, exhirom};
56
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++)
57 {
58 224 mapper=maps[mapid];
59 224 int score=0;
60 224 int highbits=0;
61 224 bool foundnull=false;
62
2/2
✓ Branch 0 taken 4704 times.
✓ Branch 1 taken 224 times.
4928 for (int i=0;i<21;i++)
63 {
64 4704 unsigned char c=romdata[snestopc(0x00FFC0+i)];
65
3/4
✓ Branch 0 taken 3400 times.
✓ Branch 1 taken 1304 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3400 times.
4704 if (foundnull && c) score-=4;//according to some documents, NUL terminated names are possible - but they shouldn't appear in the middle of the name
66
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4704 times.
4704 if (c>=128) highbits++;
67
2/2
✓ Branch 0 taken 810 times.
✓ Branch 1 taken 3894 times.
4704 else if (is_upper(c)) score+=3;
68
2/2
✓ Branch 0 taken 324 times.
✓ Branch 1 taken 3570 times.
3894 else if (c==' ') score+=2;
69
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3570 times.
3570 else if (is_digit(c)) score+=1;
70
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3570 times.
3570 else if (is_lower(c)) score+=1;
71
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3570 times.
3570 else if (c=='-') score+=1;
72
1/2
✓ Branch 0 taken 3570 times.
✗ Branch 1 not taken.
3570 else if (!c) foundnull=true;
73 else score-=3;
74 }
75
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
76
4/4
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 168 times.
✓ Branch 3 taken 56 times.
280 if ((romdata[snestopc(0x00FFDE)]^romdata[snestopc(0x00FFDC)])!=0xFF ||
77
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
224 (romdata[snestopc(0x00FFDF)]^romdata[snestopc(0x00FFDD)])!=0xFF) score=-99999;//checksum doesn't match up to 0xFFFF? Not a ROM.
78 //too lazy to check the real checksum
79
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 168 times.
224 if (score>maxscore)
80 {
81 56 maxscore=score;
82 56 bestmap=mapper;
83 }
84 }
85 56 mapper=bestmap;
86
87 //detect oddball mappers
88 56 int mapperbyte=romdata[snestopc(0x00FFD5)];
89 56 int romtypebyte=romdata[snestopc(0x00FFD6)];
90
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 if (mapper==lorom)
91 {
92
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;
93 }
94 56 return (maxscore>=0);
95 }
96
97
98 bool simple_callstacks = true;
99
100 // Shortens target_path to a relative path, but only if it resides
101 // within base_path or a child directory of it.
102 17799 string shorten_to_relative_path(const char* base_path, const char* target_path)
103 {
104
2/2
✓ Branch 0 taken 17793 times.
✓ Branch 1 taken 6 times.
17799 if (stribegin(target_path, base_path)) target_path += strlen(base_path);
105 17799 return target_path;
106 }
107
108 17799 string get_top_level_directory()
109 {
110 17799 string top_level_file_dir;
111
1/2
✓ Branch 0 taken 17799 times.
✗ Branch 1 not taken.
17799 for (int i = 0; i < callstack.count; ++i)
112 {
113
2/4
✓ Branch 0 taken 17799 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17799 times.
✗ Branch 3 not taken.
17799 if (callstack[i].type == callstack_entry_type::FILE)
114 {
115
3/6
✓ Branch 0 taken 17799 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17799 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17799 times.
✗ Branch 5 not taken.
17799 top_level_file_dir = dir(callstack[i].content);
116 17799 break;
117 }
118 }
119 17799 return top_level_file_dir;
120 }
121
122 17715 string generate_call_details_string(const char* current_block, const char* current_call, int indentation, bool add_lines)
123 {
124 17715 string e;
125
4/4
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 17541 times.
✓ Branch 2 taken 126 times.
✓ Branch 3 taken 48 times.
17715 if (current_block != nullptr || current_call != nullptr)
126 {
127 17667 string indent;
128
3/4
✓ Branch 0 taken 5674 times.
✓ Branch 1 taken 11993 times.
✓ Branch 2 taken 5674 times.
✗ Branch 3 not taken.
17667 if (add_lines) indent += "|";
129
3/4
✓ Branch 0 taken 70668 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 70668 times.
✓ Branch 3 taken 17667 times.
88335 for (; indentation > 0; --indentation) indent += " ";
130
131
8/14
✓ Branch 0 taken 17541 times.
✓ Branch 1 taken 126 times.
✓ Branch 2 taken 17541 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17541 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 17541 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 17541 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 17541 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 17541 times.
✗ Branch 13 not taken.
17667 if (current_block != nullptr) e += STR "\n"+indent+"in block: ["+current_block+"]";
132
8/14
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 17541 times.
✓ Branch 2 taken 126 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 126 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 126 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 126 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 126 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 126 times.
✗ Branch 13 not taken.
17667 if (current_call != nullptr) e += STR "\n"+indent+"in macro call: [%"+current_call+"]";
133 17667 }
134 17715 return e;
135 }
136
137 17799 string get_pretty_filename(const char* current_file)
138 {
139 // RPG Hacker: One could make an argument that we shouldn't shorten paths
140 // here, since some IDEs support jumping to files by double-clicking their
141 // paths. However, AFAIK, no IDE supports this for Asar yet, and if it's
142 // ever desired, we could just make it a command line option. Until then,
143 // I think it's more important to optimize for pretty command line display.
144
2/4
✓ Branch 0 taken 17799 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17799 times.
✗ Branch 3 not taken.
35598 return shorten_to_relative_path(get_top_level_directory(), current_file);
145 }
146
147 6451 string generate_filename_and_line(const char* current_file, int current_line_no)
148 {
149
1/2
✓ Branch 0 taken 6451 times.
✗ Branch 1 not taken.
12902 return STR current_file
150
11/20
✓ Branch 0 taken 6415 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 6415 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6415 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6415 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 36 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6451 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 6415 times.
✓ Branch 13 taken 36 times.
✓ Branch 14 taken 6415 times.
✓ Branch 15 taken 36 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
19353 + (current_line_no>=0?STR ":"+dec(current_line_no+1):"");
151 }
152
153 5674 string format_stack_line(const printable_callstack_entry& entry, int stack_frame_index)
154 {
155
1/2
✓ Branch 0 taken 5674 times.
✗ Branch 1 not taken.
5674 string indent = "\n| ";
156
2/4
✓ Branch 0 taken 5674 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5674 times.
✗ Branch 3 not taken.
5674 indent += dec(stack_frame_index);
157
1/2
✓ Branch 0 taken 5674 times.
✗ Branch 1 not taken.
5674 indent += ": ";
158 // RPG Hacker: We'll probably never have a call stack in the
159 // hundreds even, so this very specific, lazy solution suffices.
160
3/4
✓ Branch 0 taken 248 times.
✓ Branch 1 taken 5426 times.
✓ Branch 2 taken 248 times.
✗ Branch 3 not taken.
5674 if (stack_frame_index < 100) indent += " ";
161
3/4
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 5606 times.
✓ Branch 2 taken 68 times.
✗ Branch 3 not taken.
5674 if (stack_frame_index < 10) indent += " ";
162 return indent
163
2/4
✓ Branch 0 taken 5674 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5674 times.
✗ Branch 3 not taken.
11348 + generate_filename_and_line(entry.prettypath, entry.lineno)
164
1/2
✓ Branch 0 taken 5674 times.
✗ Branch 1 not taken.
17022 + entry.details;
165 5674 }
166
167 17022 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)
168 {
169 17022 printable_callstack_entry new_entry;
170
1/2
✓ Branch 0 taken 17022 times.
✗ Branch 1 not taken.
17022 new_entry.fullpath = current_file;
171
2/4
✓ Branch 0 taken 17022 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17022 times.
✗ Branch 3 not taken.
17022 new_entry.prettypath = get_pretty_filename(current_file);
172 17022 new_entry.lineno = current_line_no;
173
2/4
✓ Branch 0 taken 17022 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17022 times.
✗ Branch 3 not taken.
17022 new_entry.details = generate_call_details_string(current_block, current_call, indentation, add_lines).raw();
174
1/2
✓ Branch 0 taken 17022 times.
✗ Branch 1 not taken.
17022 out->append(new_entry);
175 17022 }
176
177 694 void get_current_line_details(string* location, string* details, bool exclude_block)
178 {
179 694 const char* current_file = nullptr;
180 694 const char* current_block = nullptr;
181 694 const char* current_call = nullptr;
182 694 int current_line_no = -1;
183
2/2
✓ Branch 0 taken 2316 times.
✓ Branch 1 taken 1 times.
2317 for (int i = callstack.count-1; i >= 0 ; --i)
184 {
185
3/5
✓ Branch 0 taken 693 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 657 times.
✓ Branch 3 taken 966 times.
✗ Branch 4 not taken.
2316 switch (callstack[i].type)
186 {
187 693 case callstack_entry_type::FILE:
188 693 current_file = callstack[i].content;
189
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 671 times.
693 if (exclude_block) current_block = nullptr;
190
3/6
✓ Branch 0 taken 693 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 693 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 693 times.
✗ Branch 5 not taken.
693 *location = generate_filename_and_line(get_pretty_filename(current_file), current_line_no);
191
2/4
✓ Branch 0 taken 693 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 693 times.
✗ Branch 3 not taken.
693 *details = generate_call_details_string(current_block, current_call, 4, false);
192 693 return;
193 case callstack_entry_type::MACRO_CALL:
194 if (current_call == nullptr) current_call = callstack[i].content;
195 break;
196 657 case callstack_entry_type::LINE:
197
3/4
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 489 times.
✓ Branch 2 taken 168 times.
✗ Branch 3 not taken.
657 if (current_block == nullptr && current_call == nullptr) current_block = callstack[i].content;
198
1/2
✓ Branch 0 taken 657 times.
✗ Branch 1 not taken.
657 if (current_line_no == -1) current_line_no = callstack[i].lineno;
199 657 break;
200 966 case callstack_entry_type::BLOCK:
201
2/2
✓ Branch 0 taken 489 times.
✓ Branch 1 taken 477 times.
966 if (current_block == nullptr) current_block = callstack[i].content;
202 966 break;
203 }
204 }
205 1 *location = "";
206 1 *details = "";
207 }
208
209 694 void get_full_printable_callstack(autoarray<printable_callstack_entry>* out, int indentation, bool add_lines)
210 {
211 694 out->reset();
212 694 const char* current_file = nullptr;
213 694 const char* current_block = nullptr;
214 694 const char* current_call = nullptr;
215 694 int current_line_no = -1;
216
2/2
✓ Branch 0 taken 70530 times.
✓ Branch 1 taken 694 times.
71224 for (int i = 0; i < callstack.count; ++i)
217 {
218
4/5
✓ Branch 0 taken 17715 times.
✓ Branch 1 taken 126 times.
✓ Branch 2 taken 17679 times.
✓ Branch 3 taken 35010 times.
✗ Branch 4 not taken.
70530 switch (callstack[i].type)
219 {
220 17715 case callstack_entry_type::FILE:
221
2/2
✓ Branch 0 taken 17022 times.
✓ Branch 1 taken 693 times.
17715 if (current_file != nullptr)
222 {
223 17022 push_stack_line(out, current_file, current_block, current_call, current_line_no, indentation, add_lines);
224 }
225 17715 current_file = callstack[i].content;
226 17715 current_block = nullptr;
227 17715 current_call = nullptr;
228 17715 current_line_no = -1;
229 17715 break;
230 126 case callstack_entry_type::MACRO_CALL:
231 126 current_block = nullptr;
232 126 current_call = callstack[i].content;
233 126 break;
234 17679 case callstack_entry_type::LINE:
235 17679 current_line_no = callstack[i].lineno;
236 17679 current_block = callstack[i].content;
237 17679 break;
238 35010 case callstack_entry_type::BLOCK:
239 35010 current_block = callstack[i].content;
240 35010 break;
241 }
242 }
243 694 }
244
245 230 string get_full_callstack()
246 {
247 230 autoarray<printable_callstack_entry> printable_stack;
248
1/2
✓ Branch 0 taken 230 times.
✗ Branch 1 not taken.
230 get_full_printable_callstack(&printable_stack, 12, true);
249
250 230 string e;
251
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 180 times.
230 if (printable_stack.count > 0)
252 {
253
1/2
✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
50 e += "\nFull call stack:";
254
2/2
✓ Branch 0 taken 5674 times.
✓ Branch 1 taken 50 times.
5724 for (int i = printable_stack.count-1; i >= 0; --i)
255 {
256
3/6
✓ Branch 0 taken 5674 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5674 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5674 times.
✗ Branch 5 not taken.
5674 e += format_stack_line(printable_stack[i], i);
257 }
258 }
259 460 return e;
260 230 }
261
262 // RPG Hacker: This function essetially replicates classic Asar behavior
263 // of only printing a single macro call below the current level.
264 464 string get_simple_callstack()
265 {
266 int i;
267 464 const char* current_call = nullptr;
268
2/2
✓ Branch 0 taken 46688 times.
✓ Branch 1 taken 380 times.
47068 for (i = callstack.count-1; i >= 0 ; --i)
269 {
270
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 46604 times.
46688 if (callstack[i].type == callstack_entry_type::MACRO_CALL)
271 {
272 84 current_call = callstack[i].content;
273 84 break;
274 }
275 }
276
277 464 const char* current_file = nullptr;
278 464 int current_line_no = -1;
279
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 380 times.
464 if (current_call != nullptr)
280 {
281 84 bool stop = false;
282
1/2
✓ Branch 0 taken 336 times.
✗ Branch 1 not taken.
336 for (int j = i-1; j >= 0 ; --j)
283 {
284
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)
285 {
286 84 case callstack_entry_type::FILE:
287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
84 if (current_file != nullptr)
288 {
289 stop = true;
290 break;
291 }
292 84 current_file = callstack[j].content;
293 84 break;
294 case callstack_entry_type::MACRO_CALL:
295 stop = true;
296 break;
297 84 case callstack_entry_type::LINE:
298
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
84 if (current_line_no == -1) current_line_no = callstack[j].lineno;
299 84 break;
300 168 case callstack_entry_type::BLOCK:
301 168 break;
302 }
303
304
3/4
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 252 times.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
336 if (current_file != nullptr && current_line_no != -1) stop = true;
305
306
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 252 times.
336 if (stop) break;
307 }
308 }
309
310 464 string e;
311
3/4
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 380 times.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
464 if (current_call != nullptr && current_file != nullptr)
312 {
313
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 e += STR "\n called from: " + generate_filename_and_line(get_pretty_filename(current_file), current_line_no)
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 84 times.
✗ Branch 7 not taken.
168 + ": [%" + current_call + "]";
315 }
316 464 return e;
317 }
318
319 694 string get_callstack()
320 {
321
2/2
✓ Branch 0 taken 464 times.
✓ Branch 1 taken 230 times.
694 if (simple_callstacks)
322 464 return get_simple_callstack();
323 else
324 230 return get_full_callstack();
325 }
326
327 54 asar_error_id vfile_error_to_error_id(virtual_file_error vfile_error)
328 {
329
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)
330 {
331 18 case vfe_doesnt_exist:
332 18 return error_id_file_not_found;
333 case vfe_access_denied:
334 return error_id_failed_to_open_file_access_denied;
335 36 case vfe_not_regular_file:
336 36 return error_id_failed_to_open_not_regular_file;
337 case vfe_unknown:
338 case vfe_none:
339 case vfe_num_errors:
340 return error_id_failed_to_open_file;
341 }
342
343 return error_id_failed_to_open_file;
344 }
345
346 54 virtual_file_error asar_get_last_io_error()
347 {
348
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 if (filesystem != nullptr)
349 {
350 54 return filesystem->get_last_error();
351 }
352
353 return vfe_unknown;
354 }
355
356 static bool freespaced;
357 1660 static int getlenforlabel(snes_label thislabel, bool exists)
358 {
359 1660 unsigned int bank = thislabel.pos>>16;
360 1660 unsigned int word = thislabel.pos&0xFFFF;
361 1660 unsigned int relaxed_bank = optimizeforbank < 0 ? 0 : optimizeforbank;
362
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 1384 times.
1660 if (!exists)
363 {
364 276 return 2;
365 }
366
5/6
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1348 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
1384 else if((optimize_dp == optimize_dp_flag::RAM) && bank == 0x7E && (word-dp_base < 0x100))
367 {
368 18 return 1;
369 }
370
6/8
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 1288 times.
✓ Branch 2 taken 78 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 78 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 54 times.
✓ Branch 7 taken 24 times.
1366 else if(optimize_dp == optimize_dp_flag::ALWAYS && (bank == 0x7E || !(bank & 0x40)) && (word-dp_base < 0x100))
371 {
372 54 return 1;
373 }
374
5/6
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1276 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
1312 else if (optimize_address == optimize_address_flag::RAM && bank == 0x7E && word < 0x2000)
375 {
376 18 return 2;
377 }
378
8/10
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 1222 times.
✓ Branch 2 taken 54 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 54 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 54 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 18 times.
✓ Branch 9 taken 54 times.
1294 else if (optimize_address == optimize_address_flag::MIRRORS && (bank == relaxed_bank || (!(bank & 0x40) && !(relaxed_bank & 0x40))) && word < 0x2000)
379 {
380 18 return 2;
381 }
382
5/8
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 1222 times.
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 54 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 54 times.
1276 else if (optimize_address == optimize_address_flag::MIRRORS && !(bank & 0x40) && !(relaxed_bank & 0x40) && word < 0x8000)
383 {
384 return 2;
385 }
386
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1240 times.
1276 else if (optimizeforbank>=0)
387 {
388
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 if (thislabel.freespace_id > 0) return 3;
389
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 else if (bank==(unsigned int)optimizeforbank) return 2;
390 36 else return 3;
391 }
392
3/4
✓ Branch 0 taken 1144 times.
✓ Branch 1 taken 96 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1144 times.
1240 else if (thislabel.freespace_id > 0 || freespaceid > 0)
393 {
394 // TODO: check whether they're pinned to the same bank
395
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 60 times.
96 if (thislabel.freespace_id != freespaceid) return 3;
396 60 else return 2;
397 }
398
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 1084 times.
1144 else if ((int)bank != snespos >> 16){ return 3; }
399 1084 else { return 2;}
400 }
401
402
403 9777 bool is_hex_constant(const char* str){
404
2/2
✓ Branch 0 taken 8319 times.
✓ Branch 1 taken 1458 times.
9777 if (*str=='$')
405 {
406 8319 str++;
407
2/2
✓ Branch 0 taken 29430 times.
✓ Branch 1 taken 8319 times.
37749 while(is_xdigit(*str)) {
408 29430 str++;
409 }
410
1/2
✓ Branch 0 taken 8319 times.
✗ Branch 1 not taken.
8319 if(*str=='\0'){
411 8319 return true;
412 }
413 }
414 1458 return false;
415 }
416
417 8985 int getlen(const char * orgstr, bool optimizebankextraction)
418 {
419 8985 const char * str=orgstr;
420 8985 freespaced=false;
421
422 8985 const char* posneglabel = str;
423
1/2
✓ Branch 0 taken 8985 times.
✗ Branch 1 not taken.
8985 string posnegname = posneglabelname(&posneglabel, false);
424
425
3/4
✓ Branch 0 taken 8985 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 186 times.
✓ Branch 3 taken 8799 times.
8985 if (posnegname.length() > 0)
426 {
427
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 186 times.
186 if (*posneglabel != '\0') goto notposneglabel;
428
429
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 124 times.
310 if (!pass) return 2;
430 124 snes_label label_data;
431 // RPG Hacker: Umm... what kind of magic constant is this?
432 124 label_data.pos = 31415926;
433
2/4
✓ Branch 0 taken 124 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 124 times.
✗ Branch 3 not taken.
124 bool found = labelval(posnegname, &label_data);
434 124 return getlenforlabel(label_data, found);
435 }
436 8799 notposneglabel:
437 8799 int len=0;
438
2/2
✓ Branch 0 taken 9219 times.
✓ Branch 1 taken 8799 times.
18018 while (*str)
439 {
440 9219 int thislen=0;
441 9219 bool maybebankextraction=(str==orgstr);
442
2/2
✓ Branch 0 taken 7077 times.
✓ Branch 1 taken 2142 times.
9219 if (*str=='$')
443 {
444 7077 str++;
445 int i;
446
2/2
✓ Branch 0 taken 27954 times.
✓ Branch 1 taken 7077 times.
35031 for (i=0;is_xdigit(str[i]);i++);
447 //if (i&1) warn(S dec(i)+"-digit hex value");//blocked in getnum instead
448 7077 thislen=(i+1)/2;
449 7077 str+=i;
450 }
451
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2142 times.
2142 else if (*str=='%')
452 {
453 str++;
454 int i;
455 for (i=0;str[i]=='0' || str[i]=='1';i++);
456 //if (i&7) warn(S dec(i)+"-digit binary value");
457 thislen=(i+7)/8;
458 str+=i;
459 }
460
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2142 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2142 else if (str[0]=='\'' && str[2]=='\'')
461 {
462 thislen=1;
463 str+=3;
464 }
465
2/2
✓ Branch 0 taken 306 times.
✓ Branch 1 taken 1836 times.
2142 else if (is_digit(*str))
466 {
467 306 int val=strtol(str, const_cast<char**>(&str), 10);
468
1/2
✓ Branch 0 taken 306 times.
✗ Branch 1 not taken.
306 if (val>=0) thislen=1;
469
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 252 times.
306 if (val>=256) thislen=2;
470
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 306 times.
306 if (val>=65536) thislen=3;
471 }
472
6/8
✓ Branch 0 taken 300 times.
✓ Branch 1 taken 1536 times.
✓ Branch 2 taken 300 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 300 times.
✓ Branch 6 taken 1536 times.
✓ Branch 7 taken 300 times.
1836 else if (is_ualpha(*str) || *str=='.' || *str=='?')
473 {
474 1536 snes_label thislabel;
475
1/2
✓ Branch 0 taken 1536 times.
✗ Branch 1 not taken.
1536 bool exists=labelval(&str, &thislabel);
476 1536 thislen=getlenforlabel(thislabel, exists);
477 }
478 300 else str++;
479
4/4
✓ Branch 0 taken 1353 times.
✓ Branch 1 taken 7866 times.
✓ Branch 2 taken 933 times.
✓ Branch 3 taken 420 times.
9219 if (optimizebankextraction && maybebankextraction &&
480
3/6
✓ Branch 0 taken 933 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 933 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 933 times.
933 (!strcmp(str, ">>16") || !strcmp(str, "/65536") || !strcmp(str, "/$10000")))
481 return 1;
482
2/2
✓ Branch 0 taken 8847 times.
✓ Branch 1 taken 372 times.
9219 if (thislen>len) len=thislen;
483 }
484 8799 return len;
485 8985 }
486
487 struct strcompare {
488 bool operator() (const char * lhs, const char * rhs) const
489 {
490 return strcmp(lhs, rhs)<0;
491 }
492 };
493
494 struct stricompare {
495 bool operator() (const char * lhs, const char * rhs) const
496 {
497 return stricmp(lhs, rhs)<0;
498 }
499 };
500
501 struct sourcefile {
502 char *data;
503 char** contents;
504 int numlines;
505 };
506
507 static assocarr<sourcefile> filecontents;
508 assocarr<string> defines;
509 // needs to be separate because defines is reset between parsing arguments and patching
510 assocarr<string> clidefines;
511 assocarr<string> builtindefines;
512
513 5066 bool validatedefinename(const char * name)
514 {
515
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5066 times.
5066 if (!name[0]) return false;
516
2/2
✓ Branch 0 taken 52624 times.
✓ Branch 1 taken 5066 times.
57690 for (int i = 0;name[i];i++)
517 {
518
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52624 times.
52624 if (!is_ualnum(name[i])) return false;
519 }
520
521 5066 return true;
522 }
523
524 177922 void resolvedefines(string& out, const char * start)
525 {
526
2/2
✓ Branch 0 taken 177916 times.
✓ Branch 1 taken 6 times.
177922 recurseblock rec;
527 177916 const char * here=start;
528
2/2
✓ Branch 0 taken 146756 times.
✓ Branch 1 taken 31160 times.
177916 if (!strchr(here, '!'))
529 {
530
1/2
✓ Branch 0 taken 146756 times.
✗ Branch 1 not taken.
146756 out += here;
531 146756 return;
532 }
533
2/2
✓ Branch 0 taken 212600 times.
✓ Branch 1 taken 31070 times.
243670 while (*here)
534 {
535
4/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 212456 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 126 times.
212600 if (here[0] == '\\' && here[1] == '\\')
536 {
537 // allow using \\ as escape sequence
538
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 += "\\";
539
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 out += "\\";
540 18 here += 2;
541 }
542
3/4
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 212456 times.
✓ Branch 2 taken 126 times.
✗ Branch 3 not taken.
212582 else if (here[0] == '\\' && here[1] == '!')
543 {
544 // allow using \! to escape !
545
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 += "\\";
546
1/2
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
126 out+="!";
547 126 here += 2;
548 }
549
2/2
✓ Branch 0 taken 33422 times.
✓ Branch 1 taken 179034 times.
212456 else if (*here=='!')
550 {
551
9/10
✓ Branch 0 taken 16227 times.
✓ Branch 1 taken 17195 times.
✓ Branch 2 taken 9981 times.
✓ Branch 3 taken 6246 times.
✓ Branch 4 taken 7581 times.
✓ Branch 5 taken 2400 times.
✓ Branch 6 taken 324 times.
✓ Branch 7 taken 7257 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 324 times.
33422 bool first=(here==start || (here>=start+4 && here[-1]==' ' && here[-2]==':' && here[-3]==' '));//check if it's the start of a block
552 33422 string defname;
553 33422 here++;
554
555 33422 int depth = 0;
556
2/2
✓ Branch 0 taken 342 times.
✓ Branch 1 taken 33422 times.
33764 for (const char* depth_str = here; *depth_str=='^'; depth_str++)
557 {
558 342 depth++;
559 }
560 33422 here += depth;
561
562
2/2
✓ Branch 0 taken 3960 times.
✓ Branch 1 taken 29462 times.
33422 if (depth != in_macro_def)
563 {
564
1/2
✓ Branch 0 taken 3960 times.
✗ Branch 1 not taken.
3960 out += '!';
565
3/4
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 198 times.
✓ Branch 3 taken 3960 times.
4158 for (int i=0; i < depth; ++i) out += '^';
566
3/4
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 3906 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
3960 if (depth > in_macro_def) asar_throw_error(0, error_type_line, error_id_invalid_depth_resolve, "define", "define", depth, in_macro_def);
567 3906 continue;
568 3906 }
569
570
2/2
✓ Branch 0 taken 324 times.
✓ Branch 1 taken 29138 times.
29462 if (*here=='{')
571 {
572 324 here++;
573 324 string unprocessedname;
574 324 int braces=1;
575 while (true)
576 {
577
2/2
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 3240 times.
3456 if (*here=='{') braces++;
578
2/2
✓ Branch 0 taken 540 times.
✓ Branch 1 taken 2916 times.
3456 if (*here=='}') braces--;
579
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3456 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3456 if (!*here) asar_throw_error(0, error_type_line, error_id_mismatched_braces);
580
2/2
✓ Branch 0 taken 324 times.
✓ Branch 1 taken 3132 times.
3456 if (!braces) break;
581
1/2
✓ Branch 0 taken 3132 times.
✗ Branch 1 not taken.
3132 unprocessedname+=*here++;
582 }
583 324 here++;
584
1/2
✓ Branch 0 taken 324 times.
✗ Branch 1 not taken.
324 resolvedefines(defname, unprocessedname);
585
3/7
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 108 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
324 if (!validatedefinename(defname)) asar_throw_error(0, error_type_line, error_id_invalid_define_name);
586 324 }
587 else
588 {
589
3/4
✓ Branch 0 taken 149773 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 149773 times.
✓ Branch 3 taken 29138 times.
178911 while (is_ualnum(*here)) defname+=*here++;
590 }
591
592
2/2
✓ Branch 0 taken 15665 times.
✓ Branch 1 taken 13797 times.
29462 if (first)
593 {
594 enum {
595 null,
596 append,
597 expand,
598 domath,
599 setifnotset,
600 } mode;
601 if(0);
602
2/2
✓ Branch 0 taken 1500 times.
✓ Branch 1 taken 14165 times.
15665 else if (stribegin(here, " = ")) { here+=3; mode=null; }
603
2/2
✓ Branch 0 taken 306 times.
✓ Branch 1 taken 13859 times.
14165 else if (stribegin(here, " += ")) { here+=4; mode=append; }
604
2/2
✓ Branch 0 taken 162 times.
✓ Branch 1 taken 13697 times.
13859 else if (stribegin(here, " := ")) { here+=4; mode=expand; }
605
2/2
✓ Branch 0 taken 5778 times.
✓ Branch 1 taken 7919 times.
13697 else if (stribegin(here, " #= ")) { here+=4; mode=domath; }
606
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 7907 times.
7919 else if (stribegin(here, " ?= ")) { here+=4; mode=setifnotset; }
607 7907 else goto notdefineset;
608 7758 string val;
609
2/2
✓ Branch 0 taken 507 times.
✓ Branch 1 taken 7251 times.
7758 if (*here=='"')
610 {
611 507 here++;
612 while (true)
613 {
614
2/2
✓ Branch 0 taken 525 times.
✓ Branch 1 taken 2052 times.
2577 if (*here=='"')
615 {
616
3/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 507 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
525 if (!here[1] || here[1]==' ') break;
617
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 else if (here[1]=='"') here++;
618 else asar_throw_error(0, error_type_line, error_id_broken_define_declaration);
619 }
620
1/2
✓ Branch 0 taken 2070 times.
✗ Branch 1 not taken.
2070 val+=*here++;
621 }
622 507 here++;
623 }
624 else
625 {
626
4/6
✓ Branch 0 taken 49863 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 49863 times.
✓ Branch 3 taken 7251 times.
✓ Branch 4 taken 49863 times.
✗ Branch 5 not taken.
57114 while (*here && *here!=' ') val+=*here++;
627 }
628 //if (strqchr(val.data(), ';')) *strqchr(val.data(), ';')=0;
629
2/8
✗ Branch 0 not taken.
✓ Branch 1 taken 7758 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 7758 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
7758 if (*here && !stribegin(here, " : ")) asar_throw_error(0, error_type_line, error_id_broken_define_declaration);
630 // RPG Hacker: Is it really a good idea to normalize
631 // the content of defines? That kinda violates their
632 // functionality as a string replacement mechanism.
633
1/2
✓ Branch 0 taken 7758 times.
✗ Branch 1 not taken.
7758 val.qnormalize();
634
635 // RPG Hacker: throw an error if we're trying to overwrite built-in defines.
636
3/4
✓ Branch 0 taken 7758 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 7740 times.
7758 if (builtindefines.exists(defname))
637 {
638
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 asar_throw_error(0, error_type_line, error_id_overriding_builtin_define, defname.data());
639 }
640
641
5/6
✓ Branch 0 taken 1482 times.
✓ Branch 1 taken 306 times.
✓ Branch 2 taken 162 times.
✓ Branch 3 taken 5778 times.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
7740 switch (mode)
642 {
643 1482 case null:
644 {
645
2/4
✓ Branch 0 taken 1482 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1482 times.
✗ Branch 3 not taken.
1482 defines.create(defname) = val;
646 1482 break;
647 }
648 306 case append:
649 {
650
2/6
✓ Branch 0 taken 306 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 306 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
306 if (!defines.exists(defname)) asar_throw_error(0, error_type_line, error_id_define_not_found, defname.data());
651
2/4
✓ Branch 0 taken 306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 306 times.
✗ Branch 3 not taken.
306 string oldval = defines.find(defname);
652
2/4
✓ Branch 0 taken 306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 306 times.
✗ Branch 3 not taken.
306 val=oldval+val;
653
2/4
✓ Branch 0 taken 306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 306 times.
✗ Branch 3 not taken.
306 defines.create(defname) = val;
654 306 break;
655 306 }
656 162 case expand:
657 {
658 162 string newval;
659
1/2
✓ Branch 0 taken 162 times.
✗ Branch 1 not taken.
162 resolvedefines(newval, val);
660
2/4
✓ Branch 0 taken 162 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 162 times.
✗ Branch 3 not taken.
162 defines.create(defname) = newval;
661 162 break;
662 162 }
663 5778 case domath:
664 {
665 5778 string newval;
666
1/2
✓ Branch 0 taken 5778 times.
✗ Branch 1 not taken.
5778 resolvedefines(newval, val);
667
1/2
✓ Branch 0 taken 5778 times.
✗ Branch 1 not taken.
5778 double num= getnumdouble(newval);
668
5/6
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 5742 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 18 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 18 times.
5778 if (foundlabel && !foundlabel_static) asar_throw_error(0, error_type_line, error_id_define_label_math);
669
3/6
✓ Branch 0 taken 5760 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5760 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5760 times.
✗ Branch 5 not taken.
5760 defines.create(defname) = ftostr(num);
670 5760 break;
671 5778 }
672 12 case setifnotset:
673 {
674
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 12 times.
✗ Branch 7 not taken.
12 if (!defines.exists(defname)) defines.create(defname) = val;
675 12 break;
676 }
677 }
678 7758 }
679 else
680 {
681 13797 notdefineset:
682
4/6
✓ Branch 0 taken 21704 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 93 times.
✓ Branch 3 taken 21611 times.
✓ Branch 4 taken 93 times.
✗ Branch 5 not taken.
21704 if (!defname) out+="!";
683 else
684 {
685
2/6
✓ Branch 0 taken 21611 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 21611 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
21611 if (!defines.exists(defname)) asar_throw_error(0, error_type_line, error_id_define_not_found, defname.data());
686 else {
687
2/4
✓ Branch 0 taken 21611 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21611 times.
✗ Branch 3 not taken.
21611 string thisone = defines.find(defname);
688
1/2
✓ Branch 0 taken 21611 times.
✗ Branch 1 not taken.
21611 resolvedefines(out, thisone);
689 21611 }
690 }
691 }
692
2/2
✓ Branch 0 taken 29426 times.
✓ Branch 1 taken 3906 times.
33422 }
693
1/2
✓ Branch 0 taken 179034 times.
✗ Branch 1 not taken.
179034 else out+=*here++;
694 }
695
5/8
✓ Branch 0 taken 31070 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 31052 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
31070 if (!confirmquotes(out)) { asar_throw_error(0, error_type_null, error_id_mismatched_quotes); out = ""; }
696
2/2
✓ Branch 0 taken 31070 times.
✓ Branch 1 taken 146756 times.
177916 }
697
698 bool moreonline;
699 bool asarverallowed = false;
700
701 145089 void assembleline(const char * fname, int linenum, const char * line, int& single_line_for_tracker)
702 {
703
1/2
✓ Branch 0 taken 145089 times.
✗ Branch 1 not taken.
145089 recurseblock rec;
704 145089 bool moreonlinetmp=moreonline;
705 // randomdude999: redundant, assemblefile already converted the path to absolute
706 //string absolutepath = filesystem->create_absolute_path("", fname);
707
1/2
✓ Branch 0 taken 145089 times.
✗ Branch 1 not taken.
145089 string absolutepath = fname;
708 145089 single_line_for_tracker = 1;
709 try
710 {
711
1/2
✓ Branch 0 taken 145089 times.
✗ Branch 1 not taken.
145089 string out=line;
712
1/2
✓ Branch 0 taken 145089 times.
✗ Branch 1 not taken.
145089 out.qreplace(": :", ": :");
713
1/2
✓ Branch 0 taken 145089 times.
✗ Branch 1 not taken.
145089 autoptr<char**> blocks=qsplitstr(out.temp_raw(), " : ");
714 145089 moreonline=true;
715
2/2
✓ Branch 0 taken 150318 times.
✓ Branch 1 taken 128193 times.
278511 for (int block=0;moreonline;block++)
716 {
717 150318 moreonline=(blocks[block+1] != nullptr);
718 try
719 {
720
1/2
✓ Branch 0 taken 150318 times.
✗ Branch 1 not taken.
150318 string stripped_block = strip_whitespace(blocks[block]);
721
722
1/2
✓ Branch 0 taken 150318 times.
✗ Branch 1 not taken.
150318 callstack_push cs_push(callstack_entry_type::BLOCK, stripped_block);
723
724
2/2
✓ Branch 0 taken 132534 times.
✓ Branch 1 taken 17784 times.
150318 assembleblock(stripped_block, single_line_for_tracker);
725
2/2
✓ Branch 0 taken 132522 times.
✓ Branch 1 taken 12 times.
132534 checkbankcross();
726 168114 }
727
2/2
✓ Branch 0 taken 16896 times.
✓ Branch 1 taken 900 times.
17796 catch (errblock&) {}
728
2/2
✓ Branch 0 taken 87531 times.
✓ Branch 1 taken 45891 times.
133422 if (blocks[block][0]!='\0') asarverallowed=false;
729
2/2
✓ Branch 0 taken 127203 times.
✓ Branch 1 taken 6219 times.
133422 if(single_line_for_tracker == 1) single_line_for_tracker = 0;
730 }
731 161985 }
732
1/2
✓ Branch 0 taken 16896 times.
✗ Branch 1 not taken.
16896 catch (errline&) {}
733 128193 moreonline=moreonlinetmp;
734 161985 }
735
736 int incsrcdepth=0;
737
738 // Returns true if a file is protected via
739 // an "includeonce".
740 19548 bool file_included_once(const char* file)
741 {
742
2/2
✓ Branch 0 taken 720 times.
✓ Branch 1 taken 19422 times.
20142 for (int i = 0; i < includeonce.count; ++i)
743 {
744
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 594 times.
720 if (includeonce[i] == file)
745 {
746 126 return true;
747 }
748 }
749
750 19422 return false;
751 }
752
753 autoarray<string> macro_defs;
754 int in_macro_def=0;
755
756 19458 void assemblefile(const char * filename)
757 {
758 19458 incsrcdepth++;
759
2/4
✓ Branch 0 taken 19458 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19458 times.
✗ Branch 3 not taken.
19458 string absolutepath = filesystem->create_absolute_path(get_current_file_name(), filename);
760
761
3/4
✓ Branch 0 taken 19458 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 126 times.
✓ Branch 3 taken 19332 times.
19458 if (file_included_once(absolutepath))
762 {
763 126 return;
764 }
765
766
1/2
✓ Branch 0 taken 19332 times.
✗ Branch 1 not taken.
19332 callstack_push cs_push(callstack_entry_type::FILE, absolutepath);
767
768 sourcefile file;
769 19332 file.contents = nullptr;
770 19332 file.numlines = 0;
771 19332 int startif=numif;
772
3/4
✓ Branch 0 taken 19332 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 862 times.
✓ Branch 3 taken 18470 times.
19332 if (!filecontents.exists(absolutepath))
773 {
774
2/2
✓ Branch 0 taken 856 times.
✓ Branch 1 taken 6 times.
862 char * temp = readfile(absolutepath, "");
775
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 838 times.
856 if (!temp)
776 {
777
4/7
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
18 asar_throw_error(0, error_type_null, vfile_error_to_error_id(asar_get_last_io_error()), filename);
778
779 18 return;
780 }
781
1/2
✓ Branch 0 taken 838 times.
✗ Branch 1 not taken.
838 sourcefile& newfile = filecontents.create(absolutepath);
782
1/2
✓ Branch 0 taken 838 times.
✗ Branch 1 not taken.
838 newfile.contents =split(temp, '\n');
783 838 newfile.data = temp;
784 838 bool in_block_comment = false;
785 838 int block_comment_start = -1;
786 838 string block_comment_start_line;
787
2/2
✓ Branch 0 taken 32785 times.
✓ Branch 1 taken 838 times.
33623 for (int i=0;newfile.contents[i];i++)
788 {
789 32785 newfile.numlines++;
790 32785 char * line= newfile.contents[i];
791
2/2
✓ Branch 0 taken 32743 times.
✓ Branch 1 taken 42 times.
32785 if(in_block_comment) {
792 42 char * end = strstr(line, "]]");
793
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 6 times.
42 if(!end) {
794 36 *line = 0;
795 36 continue;
796 }
797 6 line = end+2;
798 6 in_block_comment = false;
799 }
800 32749 redo_line:
801 32761 char * comment = strqchr(line, ';');
802
2/2
✓ Branch 0 taken 8634 times.
✓ Branch 1 taken 24127 times.
32761 if(comment) {
803
3/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8610 times.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
8634 if(comment[1] == '[' && comment[2] == '[') {
804 24 in_block_comment = true;
805 24 block_comment_start = i;
806
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 block_comment_start_line = line;
807 // this is a little messy because a multiline comment could
808 // end right on the line where it started. so if we find
809 // the end, cut the comment out of the line and recheck for
810 // more comments.
811 24 char * end = strstr(line, "]]");
812
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if(end) {
813 12 memmove(comment, end+2, strlen(end+2)+1);
814 12 in_block_comment = false;
815 12 goto redo_line;
816 }
817 }
818 8622 *comment = 0;
819 }
820
5/8
✓ Branch 0 taken 32749 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 32737 times.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
32749 if (!confirmquotes(line)) { callstack_push cs_push(callstack_entry_type::LINE, line, i); asar_throw_error(0, error_type_null, error_id_mismatched_quotes); line[0] = '\0'; }
821 32749 newfile.contents[i] = strip_whitespace(line);
822 }
823
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 832 times.
838 if(in_block_comment) {
824
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 callstack_push cs_push(callstack_entry_type::LINE, block_comment_start_line, block_comment_start);
825
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 asar_throw_error(0, error_type_null, error_id_unclosed_block_comment);
826 6 }
827
2/2
✓ Branch 0 taken 32785 times.
✓ Branch 1 taken 838 times.
33623 for(int i=0;newfile.contents[i];i++)
828 {
829 32785 char* line = newfile.contents[i];
830
2/2
✓ Branch 0 taken 12140 times.
✓ Branch 1 taken 20645 times.
32785 if(!*line) continue;
831
3/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 20645 times.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
20675 for (int j=1;line[strlen(line) - 1] == ',' && newfile.contents[i+j];j++)
832 {
833 // not using strcat because the source and dest overlap here
834 30 char* otherline = newfile.contents[i+j];
835 30 char* line_end = line + strlen(line);
836
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 30 times.
414 while(*otherline) *line_end++ = *otherline++;
837 30 *line_end = '\0';
838 static char nullstr[]="";
839 30 newfile.contents[i+j]=nullstr;
840 }
841 }
842 838 file = newfile;
843 838 } else { // filecontents.exists(absolutepath)
844
1/2
✓ Branch 0 taken 18470 times.
✗ Branch 1 not taken.
18470 file = filecontents.find(absolutepath);
845 }
846 19308 asarverallowed=true;
847
3/4
✓ Branch 0 taken 134319 times.
✓ Branch 1 taken 2406 times.
✓ Branch 2 taken 134319 times.
✗ Branch 3 not taken.
136725 for (int i=0;file.contents[i] && i<file.numlines;i++)
848 {
849 134319 string connectedline;
850
1/2
✓ Branch 0 taken 134319 times.
✗ Branch 1 not taken.
134319 int skiplines = getconnectedlines<char**>(file.contents, i, connectedline);
851
852
2/2
✓ Branch 0 taken 117417 times.
✓ Branch 1 taken 16902 times.
134319 bool was_loop_end = do_line_logic(connectedline, absolutepath, i);
853 117417 i += skiplines;
854
855 // if a loop ended on this line, should it run again?
856
7/8
✓ Branch 0 taken 6306 times.
✓ Branch 1 taken 111111 times.
✓ Branch 2 taken 6306 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3996 times.
✓ Branch 5 taken 2310 times.
✓ Branch 6 taken 3996 times.
✓ Branch 7 taken 113421 times.
117417 if (was_loop_end && whilestatus[numif].cond)
857
1/2
✓ Branch 0 taken 3996 times.
✗ Branch 1 not taken.
3996 i = whilestatus[numif].startline - 1;
858 134319 }
859
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 2406 times.
2442 while (in_macro_def > 0)
860 {
861
2/4
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
36 asar_throw_error(0, error_type_null, error_id_unclosed_macro, macro_defs[in_macro_def-1].data());
862
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);
863 36 in_macro_def--;
864
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 macro_defs.remove(in_macro_def);
865 }
866
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2406 times.
2406 if (numif!=startif)
867 {
868 numif=startif;
869 numtrue=startif;
870 asar_throw_error(0, error_type_null, error_id_unclosed_if);
871 }
872 2406 incsrcdepth--;
873
4/4
✓ Branch 0 taken 2406 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 2406 times.
✓ Branch 3 taken 144 times.
36384 }
874
875 // RPG Hacker: At some point, this should probably be merged
876 // into assembleline(), since the two names just cause
877 // confusion otherwise.
878 // return value is "did a loop end on this line"
879 155391 bool do_line_logic(const char* line, const char* filename, int lineno)
880 {
881 155391 int prevnumif = numif;
882 155391 int single_line_for_tracker = 1;
883 try
884 {
885 155391 string current_line;
886
8/8
✓ Branch 0 taken 9558 times.
✓ Branch 1 taken 145833 times.
✓ Branch 2 taken 8100 times.
✓ Branch 3 taken 1458 times.
✓ Branch 4 taken 504 times.
✓ Branch 5 taken 7596 times.
✓ Branch 6 taken 146337 times.
✓ Branch 7 taken 9054 times.
155391 if (numif==numtrue || (numtrue+1==numif && stribegin(line, "elseif ")))
887 {
888
1/2
✓ Branch 0 taken 146337 times.
✗ Branch 1 not taken.
146337 callstack_push cs_push(callstack_entry_type::LINE, line, lineno);
889
2/2
✓ Branch 0 taken 146031 times.
✓ Branch 1 taken 306 times.
146337 string tmp=replace_macro_args(line);
890
1/2
✓ Branch 0 taken 146031 times.
✗ Branch 1 not taken.
146031 tmp.qnormalize();
891
2/2
✓ Branch 0 taken 145935 times.
✓ Branch 1 taken 96 times.
146031 resolvedefines(current_line, tmp);
892 146433 }
893
1/2
✓ Branch 0 taken 9054 times.
✗ Branch 1 not taken.
9054 else current_line=line;
894
895
1/2
✓ Branch 0 taken 154989 times.
✗ Branch 1 not taken.
154989 callstack_push cs_push(callstack_entry_type::LINE, current_line, lineno);
896
897
6/6
✓ Branch 0 taken 1656 times.
✓ Branch 1 taken 153333 times.
✓ Branch 2 taken 1548 times.
✓ Branch 3 taken 108 times.
✓ Branch 4 taken 1548 times.
✓ Branch 5 taken 153441 times.
154989 if (stribegin(current_line, "macro ") && numif==numtrue)
898 {
899 // RPG Hacker: Slight redundancy here with code that is
900 // also in startmacro(). Could improve this for Asar 2.0.
901
1/2
✓ Branch 0 taken 1548 times.
✗ Branch 1 not taken.
1548 string macro_name = current_line.data()+6;
902 1548 char * startpar=strqchr(macro_name.data(), '(');
903
1/2
✓ Branch 0 taken 1548 times.
✗ Branch 1 not taken.
1548 if (startpar) *startpar=0;
904
1/2
✓ Branch 0 taken 1548 times.
✗ Branch 1 not taken.
1548 macro_defs.append(macro_name);
905
906 // RPG Hacker: I think it would make more logical sense
907 // to have this ++ after the if, but hat breaks compatibility
908 // with at least one test, and it generally leads to more
909 // errors being output after a broken macro declaration.
910 1548 in_macro_def++;
911
2/2
✓ Branch 0 taken 516 times.
✓ Branch 1 taken 1032 times.
1548 if (!pass)
912 {
913
4/4
✓ Branch 0 taken 420 times.
✓ Branch 1 taken 96 times.
✓ Branch 2 taken 414 times.
✓ Branch 3 taken 6 times.
516 if (in_macro_def == 1) startmacro(current_line.data()+6);
914
1/2
✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
96 else tomacro(current_line);
915 }
916 1548 }
917
8/8
✓ Branch 0 taken 77406 times.
✓ Branch 1 taken 76035 times.
✓ Branch 2 taken 1566 times.
✓ Branch 3 taken 75840 times.
✓ Branch 4 taken 1512 times.
✓ Branch 5 taken 76143 times.
✓ Branch 6 taken 756 times.
✓ Branch 7 taken 75840 times.
153441 else if (!stricmp(current_line, "endmacro") && numif==numtrue)
918 {
919
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1512 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1512 if (in_macro_def == 0) asar_throw_error(0, error_type_line, error_id_misplaced_endmacro);
920 else
921 {
922 1512 in_macro_def--;
923
1/2
✓ Branch 0 taken 1512 times.
✗ Branch 1 not taken.
1512 macro_defs.remove(in_macro_def);
924
2/2
✓ Branch 0 taken 504 times.
✓ Branch 1 taken 1008 times.
1512 if (!pass)
925 {
926
3/4
✓ Branch 0 taken 414 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 414 times.
✗ Branch 3 not taken.
504 if (in_macro_def == 0) endmacro(true);
927
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 else tomacro(current_line);
928 }
929 }
930 }
931
2/2
✓ Branch 0 taken 6840 times.
✓ Branch 1 taken 145089 times.
151929 else if (in_macro_def > 0)
932 {
933
3/4
✓ Branch 0 taken 2280 times.
✓ Branch 1 taken 4560 times.
✓ Branch 2 taken 2280 times.
✗ Branch 3 not taken.
6840 if (!pass) tomacro(current_line);
934 }
935 else
936 {
937
2/2
✓ Branch 0 taken 128193 times.
✓ Branch 1 taken 16896 times.
145089 assembleline(filename, lineno, current_line, single_line_for_tracker);
938 }
939 172293 }
940
2/2
✓ Branch 0 taken 16902 times.
✓ Branch 1 taken 402 times.
17304 catch (errline&) {}
941
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 121809 times.
121989 return (numif != prevnumif || single_line_for_tracker == 3)
942
8/10
✓ Branch 0 taken 121989 times.
✓ Branch 1 taken 16500 times.
✓ Branch 2 taken 16680 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9054 times.
✓ Branch 5 taken 7626 times.
✓ Branch 6 taken 9054 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2242 times.
✓ Branch 9 taken 6812 times.
260478 && (whilestatus[numif].iswhile || whilestatus[numif].is_for);
943 }
944
945
946 473 void parse_std_includes(const char* textfile, autoarray<string>& outarray)
947 {
948 473 char* content = readfilenative(textfile);
949
950
1/2
✓ Branch 0 taken 473 times.
✗ Branch 1 not taken.
473 if (content != nullptr)
951 {
952 473 char* pos = content;
953
954
2/2
✓ Branch 0 taken 948 times.
✓ Branch 1 taken 473 times.
1421 while (pos[0] != '\0')
955 {
956 948 string stdinclude;
957
958 do
959 {
960
3/4
✓ Branch 0 taken 18438 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17963 times.
✓ Branch 3 taken 475 times.
18438 if (pos[0] != '\r' && pos[0] != '\n')
961 {
962
1/2
✓ Branch 0 taken 17963 times.
✗ Branch 1 not taken.
17963 stdinclude += pos[0];
963 }
964 18438 pos++;
965
4/4
✓ Branch 0 taken 17965 times.
✓ Branch 1 taken 473 times.
✓ Branch 2 taken 17490 times.
✓ Branch 3 taken 475 times.
18438 } while (pos[0] != '\0' && pos[0] != '\n');
966
967
1/2
✓ Branch 0 taken 948 times.
✗ Branch 1 not taken.
948 strip_whitespace(stdinclude);
968
969
2/2
✓ Branch 0 taken 475 times.
✓ Branch 1 taken 473 times.
948 if (stdinclude != "")
970 {
971
3/4
✓ Branch 0 taken 475 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 474 times.
475 if (!path_is_absolute(stdinclude))
972 {
973
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 stdinclude = dir(textfile) + stdinclude;
974 }
975
2/4
✓ Branch 0 taken 475 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 475 times.
✗ Branch 3 not taken.
475 outarray.append(normalize_path(stdinclude));
976 }
977 948 }
978
979 473 free(content);
980 }
981 473 }
982
983 722 void parse_std_defines(const char* textfile)
984 {
985
986 // RPG Hacker: add built-in defines.
987 // (They're not really standard defines, but I was lazy and this was
988 // one convenient place for doing it).
989 722 builtindefines.create("assembler") = "asar";
990
8/11
✓ Branch 0 taken 604 times.
✓ Branch 1 taken 118 times.
✓ Branch 2 taken 351 times.
✓ Branch 3 taken 253 times.
✓ Branch 4 taken 469 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 253 times.
✓ Branch 7 taken 118 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 253 times.
✗ Branch 10 not taken.
722 builtindefines.create("assembler_ver") = dec(get_version_int());
991
4/8
✓ Branch 0 taken 722 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 722 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 722 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 351 times.
✗ Branch 7 not taken.
722 builtindefines.create("assembler_time") = dec(time(nullptr));
992
993
2/2
✓ Branch 0 taken 249 times.
✓ Branch 1 taken 473 times.
722 if(textfile == nullptr) return;
994
995 473 char* content = readfilenative(textfile);
996
997
1/2
✓ Branch 0 taken 473 times.
✗ Branch 1 not taken.
473 if (content != nullptr)
998 {
999 473 char* pos = content;
1000
2/2
✓ Branch 0 taken 2837 times.
✓ Branch 1 taken 473 times.
3310 while (*pos != 0) {
1001 2837 string define_name;
1002 2837 string define_val;
1003
1004
4/4
✓ Branch 0 taken 28347 times.
✓ Branch 1 taken 1890 times.
✓ Branch 2 taken 27400 times.
✓ Branch 3 taken 947 times.
30237 while (*pos != '=' && *pos != '\n') {
1005
1/2
✓ Branch 0 taken 27400 times.
✗ Branch 1 not taken.
27400 define_name += *pos;
1006 27400 pos++;
1007 }
1008
3/4
✓ Branch 0 taken 2837 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1890 times.
✓ Branch 3 taken 947 times.
2837 if (*pos != 0 && *pos != '\n') pos++; // skip =
1009
3/4
✓ Branch 0 taken 12762 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9925 times.
✓ Branch 3 taken 2837 times.
12762 while (*pos != 0 && *pos != '\n') {
1010
1/2
✓ Branch 0 taken 9925 times.
✗ Branch 1 not taken.
9925 define_val += *pos;
1011 9925 pos++;
1012 }
1013
1/2
✓ Branch 0 taken 2837 times.
✗ Branch 1 not taken.
2837 if (*pos != 0)
1014 2837 pos++; // skip \n
1015 // clean define_name
1016
1/2
✓ Branch 0 taken 2837 times.
✗ Branch 1 not taken.
2837 strip_whitespace(define_name);
1017
1/2
✓ Branch 0 taken 2837 times.
✗ Branch 1 not taken.
2837 define_name.strip_prefix('!'); // remove leading ! if present
1018
1019
2/2
✓ Branch 0 taken 473 times.
✓ Branch 1 taken 2364 times.
2837 if (define_name == "")
1020 {
1021
1/2
✓ Branch 0 taken 473 times.
✗ Branch 1 not taken.
473 if (define_val == "")
1022 {
1023 473 continue;
1024 }
1025
1026 asar_throw_error(pass, error_type_null, error_id_stddefines_no_identifier);
1027 }
1028
1029
3/8
✓ Branch 0 taken 594 times.
✓ Branch 1 taken 1770 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 594 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2364 if (!validatedefinename(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_invalid, "stddefines.txt", define_name.data());
1030
1031 // clean define_val
1032 2364 const char* defval = define_val.data();
1033 2364 string cleaned_defval;
1034
1035
2/2
✓ Branch 0 taken 474 times.
✓ Branch 1 taken 1890 times.
2364 if (*defval == 0) {
1036 // no value
1037
2/6
✓ Branch 0 taken 474 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 474 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
474 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
1038
2/4
✓ Branch 0 taken 474 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 474 times.
✗ Branch 3 not taken.
474 clidefines.create(define_name) = "";
1039 474 continue;
1040 }
1041
1042
3/4
✓ Branch 0 taken 946 times.
✓ Branch 1 taken 1890 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1890 times.
2836 while (*defval == ' ' || *defval == '\t') defval++; // skip whitespace in beginning
1043
2/2
✓ Branch 0 taken 473 times.
✓ Branch 1 taken 1417 times.
1890 if (*defval == '"') {
1044 473 defval++; // skip opening quote
1045
3/4
✓ Branch 0 taken 6141 times.
✓ Branch 1 taken 473 times.
✓ Branch 2 taken 6141 times.
✗ Branch 3 not taken.
6614 while (*defval != '"' && *defval != 0)
1046
1/2
✓ Branch 0 taken 6141 times.
✗ Branch 1 not taken.
6141 cleaned_defval += *defval++;
1047
1048
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 473 times.
473 if (*defval == 0) {
1049 asar_throw_error(pass, error_type_null, error_id_mismatched_quotes);
1050 }
1051 473 defval++; // skip closing quote
1052
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 473 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 473 times.
473 while (*defval == ' ' || *defval == '\t') defval++; // skip whitespace
1053
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 473 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
473 if (*defval != 0 && *defval != '\n')
1054 asar_throw_error(pass, error_type_null, error_id_stddefine_after_closing_quote);
1055
1056
2/6
✓ Branch 0 taken 473 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 473 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
473 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
1057
2/4
✓ Branch 0 taken 473 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 473 times.
✗ Branch 3 not taken.
473 clidefines.create(define_name) = cleaned_defval;
1058 473 continue;
1059 }
1060 else
1061 {
1062 // slightly hacky way to remove trailing whitespace
1063 1417 const char* defval_end = strchr(defval, '\n'); // slightly hacky way to get end of string or newline
1064
1/2
✓ Branch 0 taken 1417 times.
✗ Branch 1 not taken.
1417 if (!defval_end) defval_end = strchr(defval, 0);
1065 1417 defval_end--;
1066
3/4
✓ Branch 0 taken 475 times.
✓ Branch 1 taken 1417 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1417 times.
1892 while (*defval_end == ' ' || *defval_end == '\t') defval_end--;
1067
2/4
✓ Branch 0 taken 1417 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1417 times.
✗ Branch 3 not taken.
1417 cleaned_defval = string(defval, (int)(defval_end - defval + 1));
1068
1069
2/6
✓ Branch 0 taken 1417 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1417 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1417 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
1070
2/4
✓ Branch 0 taken 1417 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1417 times.
✗ Branch 3 not taken.
1417 clidefines.create(define_name) = cleaned_defval;
1071 1417 continue;
1072 1417 }
1073
1074 2837 }
1075 473 free(content);
1076 }
1077 }
1078
1079 bool checksum_fix_enabled = true;
1080 bool force_checksum_fix = false;
1081
1082 #define cfree(x) free((void*)x)
1083 414 static void clearmacro(const string & key, macrodata* & macro)
1084 {
1085 (void)key;
1086 414 freemacro(macro);
1087 414 }
1088
1089 838 static void clearfile(const string & key, sourcefile& filecontent)
1090 {
1091 (void)key;
1092 838 cfree(filecontent.data);
1093 838 cfree(filecontent.contents);
1094 838 }
1095 #undef cfree
1096
1097 4526 static void adddefine(const string & key, string & value)
1098 {
1099
1/2
✓ Branch 0 taken 4526 times.
✗ Branch 1 not taken.
4526 if (!defines.exists(key)) defines.create(key) = value;
1100 4526 }
1101
1102 static string symbolfile;
1103
1104 318 static void printsymbol_wla(const string& key, snes_label& label)
1105 {
1106
7/14
✓ Branch 0 taken 318 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 318 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 318 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 318 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 318 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 318 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 318 times.
✗ Branch 13 not taken.
318 string line = hex((label.pos & 0xFF0000)>>16, 2)+":"+hex(label.pos & 0xFFFF, 4)+" "+key+"\n";
1107
1/2
✓ Branch 0 taken 318 times.
✗ Branch 1 not taken.
318 symbolfile += line;
1108 318 }
1109
1110 static void printsymbol_nocash(const string& key, snes_label& label)
1111 {
1112 string line = hex(label.pos & 0xFFFFFF, 8)+" "+key+"\n";
1113 symbolfile += line;
1114 }
1115
1116 166 string create_symbols_file(string format, uint32_t romCrc){
1117 166 format = lower(format);
1118 166 symbolfile = "";
1119
1/2
✓ Branch 0 taken 166 times.
✗ Branch 1 not taken.
166 if(format == "wla")
1120 {
1121 166 symbolfile = "; wla symbolic information file\n";
1122 166 symbolfile += "; generated by asar\n";
1123
1124 166 symbolfile += "\n[labels]\n";
1125 166 labels.each(printsymbol_wla);
1126
1127 166 symbolfile += "\n[source files]\n";
1128 166 const autoarray<AddressToLineMapping::FileInfo>& addrToLineFileList = addressToLineMapping.getFileList();
1129
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 166 times.
342 for (int i = 0; i < addrToLineFileList.count; ++i)
1130 {
1131 char addrToFileListStr[256];
1132 352 snprintf(addrToFileListStr, 256, "%.4x %.8x %s\n",
1133 i,
1134
2/4
✓ Branch 0 taken 176 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
176 addrToLineFileList[i].fileCrc,
1135
1/2
✓ Branch 0 taken 176 times.
✗ Branch 1 not taken.
176 addrToLineFileList[i].filename.data()
1136 );
1137
1/2
✓ Branch 0 taken 176 times.
✗ Branch 1 not taken.
176 symbolfile += addrToFileListStr;
1138 }
1139
1140 166 symbolfile += "\n[rom checksum]\n";
1141 {
1142 char romCrcStr[32];
1143
1/2
✓ Branch 0 taken 83 times.
✗ Branch 1 not taken.
166 snprintf(romCrcStr, 32, "%.8x\n",
1144 romCrc
1145 );
1146
1/2
✓ Branch 0 taken 166 times.
✗ Branch 1 not taken.
166 symbolfile += romCrcStr;
1147 }
1148
1149 166 symbolfile += "\n[addr-to-line mapping]\n";
1150 166 const autoarray<AddressToLineMapping::AddrToLineInfo>& addrToLineInfo = addressToLineMapping.getAddrToLineInfo();
1151
2/2
✓ Branch 0 taken 5234 times.
✓ Branch 1 taken 166 times.
5400 for (int i = 0; i < addrToLineInfo.count; ++i)
1152 {
1153 char addrToLineStr[32];
1154 20936 snprintf(addrToLineStr, 32, "%.2x:%.4x %.4x:%.8x\n",
1155
1/2
✓ Branch 0 taken 2617 times.
✗ Branch 1 not taken.
7851 (addrToLineInfo[i].addr & 0xFF0000) >> 16,
1156
1/2
✓ Branch 0 taken 5234 times.
✗ Branch 1 not taken.
5234 addrToLineInfo[i].addr & 0xFFFF,
1157
1/2
✓ Branch 0 taken 5234 times.
✗ Branch 1 not taken.
5234 addrToLineInfo[i].fileIdx & 0xFFFF,
1158
2/4
✓ Branch 0 taken 5234 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5234 times.
✗ Branch 3 not taken.
5234 addrToLineInfo[i].line & 0xFFFFFFFF
1159 );
1160
1/2
✓ Branch 0 taken 5234 times.
✗ Branch 1 not taken.
5234 symbolfile += addrToLineStr;
1161 }
1162
1163 }
1164 else if (format == "nocash")
1165 {
1166 symbolfile = ";no$sns symbolic information file\n";
1167 symbolfile += ";generated by asar\n";
1168 symbolfile += "\n";
1169 labels.each(printsymbol_nocash);
1170 }
1171 166 return symbolfile;
1172 }
1173
1174
1175 6 bool in_top_level_file()
1176 {
1177 6 int num_files = 0;
1178
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 6 times.
30 for (int i = callstack.count-1; i >= 0; --i)
1179 {
1180
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 18 times.
24 if (callstack[i].type == callstack_entry_type::FILE)
1181 {
1182 6 num_files++;
1183
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (num_files > 1) break;
1184 }
1185 }
1186 6 return (num_files <= 1);
1187 }
1188
1189 36537 const char* get_current_file_name()
1190 {
1191
2/2
✓ Branch 0 taken 136576 times.
✓ Branch 1 taken 2107 times.
138683 for (int i = callstack.count-1; i >= 0; --i)
1192 {
1193
2/2
✓ Branch 0 taken 34430 times.
✓ Branch 1 taken 102146 times.
136576 if (callstack[i].type == callstack_entry_type::FILE)
1194 34430 return callstack[i].content.raw();
1195 }
1196 2107 return nullptr;
1197 }
1198
1199 26205 int get_current_line()
1200 {
1201
2/2
✓ Branch 0 taken 77504 times.
✓ Branch 1 taken 21 times.
77525 for (int i = callstack.count-1; i >= 0; --i)
1202 {
1203
2/2
✓ Branch 0 taken 26184 times.
✓ Branch 1 taken 51320 times.
77504 if (callstack[i].type == callstack_entry_type::LINE) return callstack[i].lineno;
1204 }
1205 21 return -1;
1206 }
1207
1208 694 const char* get_current_block()
1209 {
1210
2/2
✓ Branch 0 taken 699 times.
✓ Branch 1 taken 31 times.
730 for (int i = callstack.count-1; i >= 0; --i)
1211 {
1212
6/6
✓ Branch 0 taken 531 times.
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 495 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 663 times.
✓ Branch 5 taken 36 times.
699 if (callstack[i].type == callstack_entry_type::LINE || callstack[i].type == callstack_entry_type::BLOCK) return callstack[i].content.raw();
1213 }
1214 31 return nullptr;
1215 }
1216
1217
1218 727 void reseteverything()
1219 {
1220 727 string str;
1221 727 labels.reset();
1222 727 defines.reset();
1223
1/2
✓ Branch 0 taken 727 times.
✗ Branch 1 not taken.
727 builtindefines.each(adddefine);
1224
1/2
✓ Branch 0 taken 727 times.
✗ Branch 1 not taken.
727 clidefines.each(adddefine);
1225 727 structs.reset();
1226
1227
1/2
✓ Branch 0 taken 727 times.
✗ Branch 1 not taken.
727 macros.each(clearmacro);
1228 727 macros.reset();
1229
1230
1/2
✓ Branch 0 taken 727 times.
✗ Branch 1 not taken.
727 filecontents.each(clearfile);
1231 727 filecontents.reset();
1232
1233 727 writtenblocks.reset();
1234
1235 727 optimizeforbank=-1;
1236 727 optimize_dp = optimize_dp_flag::NONE;
1237 727 dp_base = 0;
1238 727 optimize_address = optimize_address_flag::DEFAULT;
1239
1240
1/2
✓ Branch 0 taken 727 times.
✗ Branch 1 not taken.
727 closecachedfiles();
1241
1242 727 incsrcdepth=0;
1243 727 label_counter = 0;
1244 727 errored = false;
1245 727 checksum_fix_enabled = true;
1246 727 force_checksum_fix = false;
1247
1248 727 in_macro_def = 0;
1249
1250 #ifndef ASAR_SHARED
1251 236 free(const_cast<unsigned char*>(romdata_r));
1252 #endif
1253
1254
1/2
✓ Branch 0 taken 727 times.
✗ Branch 1 not taken.
727 callstack.reset();
1255 727 simple_callstacks = true;
1256 #undef free
1257 727 }
1258