asar coverage - build #259


src/asar/
File: src/asar/main.cpp
Date: 2025-02-26 19:38:12
Lines:
688/729
94.4%
Functions:
39/39
100.0%
Branches:
769/1124
68.4%

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 582 int get_version_int()
48 {
49 582 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 25777 static string shorten_to_relative_path(const char* base_path, const char* target_path)
104 {
105
2/2
✓ Branch 0 taken 15925 times.
✓ Branch 1 taken 9852 times.
25777 if (stribegin(target_path, base_path)) target_path += strlen(base_path);
106 25777 return target_path;
107 }
108
109 25777 static string get_top_level_directory()
110 {
111 10315 string top_level_file_dir;
112
1/2
✓ Branch 0 taken 25777 times.
✗ Branch 1 not taken.
25777 for (int i = 0; i < callstack.count; ++i)
113 {
114
2/4
✓ Branch 0 taken 25777 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10315 times.
✗ Branch 3 not taken.
25777 if (callstack[i].type == callstack_entry_type::FILE)
115 {
116
2/4
✓ Branch 0 taken 25777 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10315 times.
✗ Branch 3 not taken.
25777 top_level_file_dir = dir(callstack[i].content);
117 25777 break;
118 }
119 }
120 25777 return top_level_file_dir;
121 }
122
123
2/2
✓ Branch 0 taken 15395 times.
✓ Branch 1 taken 25 times.
25693 static string generate_call_details_string(const char* current_block, const char* current_call, int indentation, bool add_lines)
124 {
125 10273 string e;
126
4/4
✓ Branch 0 taken 15491 times.
✓ Branch 1 taken 10202 times.
✓ Branch 2 taken 71 times.
✓ Branch 3 taken 25 times.
25693 if (current_block != nullptr || current_call != nullptr)
127 {
128 10248 string indent;
129
3/4
✓ Branch 0 taken 13679 times.
✓ Branch 1 taken 11964 times.
✓ Branch 2 taken 8332 times.
✗ Branch 3 not taken.
25643 if (add_lines) indent += "|";
130
3/4
✓ Branch 0 taken 102588 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 102588 times.
✓ Branch 3 taken 25643 times.
128231 for (; indentation > 0; --indentation) indent += " ";
131
132
8/14
✓ Branch 0 taken 25509 times.
✓ Branch 1 taken 134 times.
✓ Branch 2 taken 25509 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 25509 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 25509 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 25509 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 25509 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 10177 times.
✗ Branch 13 not taken.
40975 if (current_block != nullptr) e += STR "\n"+indent+"in block: ["+current_block+"]";
133
8/14
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 25509 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.
25706 if (current_call != nullptr) e += STR "\n"+indent+"in macro call: [%"+current_call+"]";
134 25643 }
135 25693 return e;
136 }
137
138 25777 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 25777 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10315 times.
✗ Branch 3 not taken.
36092 return shorten_to_relative_path(get_top_level_directory(), current_file);
146 }
147
148 9117 static string generate_filename_and_line(const char* current_file, int current_line_no)
149 {
150
1/2
✓ Branch 0 taken 3703 times.
✗ Branch 1 not taken.
12820 return STR current_file
151
13/20
✓ Branch 0 taken 9081 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 9081 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9081 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9099 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5414 times.
✓ Branch 9 taken 18 times.
✓ Branch 10 taken 9099 times.
✓ Branch 11 taken 18 times.
✓ Branch 12 taken 3685 times.
✓ Branch 13 taken 18 times.
✓ Branch 14 taken 3685 times.
✓ Branch 15 taken 18 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
32747 + (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 24992 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 702 void get_current_line_details(string* location, string* details, bool exclude_block)
179 {
180 354 const char* current_file = nullptr;
181 354 const char* current_block = nullptr;
182 354 const char* current_call = nullptr;
183 354 int current_line_no = -1;
184
2/2
✓ Branch 0 taken 2348 times.
✓ Branch 1 taken 1 times.
2349 for (int i = callstack.count-1; i >= 0 ; --i)
185 {
186
3/5
✓ Branch 0 taken 701 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 665 times.
✓ Branch 3 taken 982 times.
✗ Branch 4 not taken.
2348 switch (callstack[i].type)
187 {
188 353 case callstack_entry_type::FILE:
189 353 current_file = callstack[i].content;
190
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 677 times.
701 if (exclude_block) current_block = nullptr;
191
2/4
✓ Branch 0 taken 701 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 353 times.
✗ Branch 3 not taken.
701 *location = generate_filename_and_line(get_pretty_filename(current_file), current_line_no);
192
1/2
✓ Branch 0 taken 353 times.
✗ Branch 1 not taken.
701 *details = generate_call_details_string(current_block, current_call, 4, false);
193 701 return;
194 case callstack_entry_type::MACRO_CALL:
195 if (current_call == nullptr) current_call = callstack[i].content;
196 break;
197 665 case callstack_entry_type::LINE:
198
3/4
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 497 times.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
665 if (current_block == nullptr && current_call == nullptr) current_block = callstack[i].content;
199
1/2
✓ Branch 0 taken 665 times.
✗ Branch 1 not taken.
995 if (current_line_no == -1) current_line_no = callstack[i].lineno;
200 335 break;
201 982 case callstack_entry_type::BLOCK:
202
2/2
✓ Branch 0 taken 497 times.
✓ Branch 1 taken 485 times.
982 if (current_block == nullptr) current_block = callstack[i].content;
203 496 break;
204 }
205 }
206 1 *location = "";
207 1 *details = "";
208 }
209
210 704 void get_full_printable_callstack(autoarray<printable_callstack_entry>* out, int indentation, bool add_lines)
211 {
212 704 out->reset();
213 356 const char* current_file = nullptr;
214 356 const char* current_block = nullptr;
215 356 const char* current_call = nullptr;
216 356 int current_line_no = -1;
217
2/2
✓ Branch 0 taken 102458 times.
✓ Branch 1 taken 704 times.
103162 for (int i = 0; i < callstack.count; ++i)
218 {
219
4/5
✓ Branch 0 taken 25695 times.
✓ Branch 1 taken 134 times.
✓ Branch 2 taken 25659 times.
✓ Branch 3 taken 50970 times.
✗ Branch 4 not taken.
102458 switch (callstack[i].type)
220 {
221 25695 case callstack_entry_type::FILE:
222
2/2
✓ Branch 0 taken 24992 times.
✓ Branch 1 taken 703 times.
25695 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 10275 current_file = callstack[i].content;
227 10275 current_block = nullptr;
228 10275 current_call = nullptr;
229 10275 current_line_no = -1;
230 25695 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 10257 case callstack_entry_type::LINE:
236 25659 current_line_no = callstack[i].lineno;
237 10257 current_block = callstack[i].content;
238 25659 break;
239 20340 case callstack_entry_type::BLOCK:
240 20340 current_block = callstack[i].content;
241 50970 break;
242 }
243 }
244 704 }
245
246 234 static string get_full_callstack()
247 {
248 118 autoarray<printable_callstack_entry> printable_stack;
249
1/2
✓ Branch 0 taken 234 times.
✗ Branch 1 not taken.
234 get_full_printable_callstack(&printable_stack, 12, true);
250
251 118 string e;
252
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 182 times.
234 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 352 return e;
261 234 }
262
263 // RPG Hacker: This function essetially replicates classic Asar behavior
264 // of only printing a single macro call below the current level.
265 468 static string get_simple_callstack()
266 {
267 int i;
268 236 const char* current_call = nullptr;
269
2/2
✓ Branch 0 taken 67936 times.
✓ Branch 1 taken 384 times.
68320 for (i = callstack.count-1; i >= 0 ; --i)
270 {
271
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 67852 times.
67936 if (callstack[i].type == callstack_entry_type::MACRO_CALL)
272 {
273 42 current_call = callstack[i].content;
274 84 break;
275 }
276 }
277
278 236 const char* current_file = nullptr;
279 236 int current_line_no = -1;
280
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 384 times.
468 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 236 string e;
312
3/4
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 384 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
468 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 468 return e;
318 }
319
320 702 string get_callstack()
321 {
322
2/2
✓ Branch 0 taken 468 times.
✓ Branch 1 taken 234 times.
702 if (simple_callstacks)
323 468 return get_simple_callstack();
324 else
325 234 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 static bool freespaced;
358 2290 static int getlenforlabel(snes_label thislabel, bool exists)
359 {
360 2290 unsigned int bank = thislabel.pos>>16;
361 2290 unsigned int word = thislabel.pos&0xFFFF;
362 1147 bool lblfreespace = thislabel.freespace_id > 0;
363 unsigned int relaxed_bank;
364
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 2236 times.
2290 if(optimizeforbank >= 0) {
365 54 relaxed_bank = optimizeforbank;
366 } else {
367
2/2
✓ Branch 0 taken 1804 times.
✓ Branch 1 taken 432 times.
2236 if(freespaceid == 0) {
368 1804 relaxed_bank = snespos >> 16;
369 } else {
370 432 int target_bank = freespaces[freespaceid].bank;
371
2/2
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 216 times.
432 if(target_bank == -2) relaxed_bank = 0;
372
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 72 times.
144 else if(target_bank == -1) relaxed_bank = 0x40;
373 else relaxed_bank = target_bank;
374 }
375 }
376
2/2
✓ Branch 0 taken 1143 times.
✓ Branch 1 taken 1147 times.
2290 if (!exists)
377 {
378 216 return 2;
379 }
380
7/8
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1822 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.
1858 else if((optimize_dp == optimize_dp_flag::RAM) && bank == 0x7E && (word-dp_base < 0x100) && !lblfreespace)
381 {
382 9 return 1;
383 }
384
8/10
✓ Branch 0 taken 1252 times.
✓ Branch 1 taken 588 times.
✓ Branch 2 taken 1252 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1252 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 262 times.
✓ Branch 7 taken 990 times.
✓ Branch 8 taken 133 times.
✓ Branch 9 taken 129 times.
1840 else if(optimize_dp == optimize_dp_flag::ALWAYS && (bank == 0x7E || !(bank & 0x40)) && (word-dp_base < 0x100) && !lblfreespace)
385 {
386 31 return 1;
387 }
388 1782 else if (
389 // if we should optimize ram accesses...
390
4/4
✓ Branch 0 taken 1593 times.
✓ Branch 1 taken 189 times.
✓ Branch 2 taken 702 times.
✓ Branch 3 taken 135 times.
1782 (optimize_address == optimize_address_flag::RAM || optimize_address == optimize_address_flag::MIRRORS)
391 // and we're in a bank with ram mirrors... (optimizeforbank=0x7E is checked later)
392
2/2
✓ Branch 0 taken 1416 times.
✓ Branch 1 taken 96 times.
1512 && !(relaxed_bank & 0x40)
393 // and the label is in low RAM
394
5/6
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 1362 times.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
1416 && bank == 0x7E && word < 0x2000 && !lblfreespace)
395 {
396 27 return 2;
397 }
398
2/2
✓ Branch 0 taken 693 times.
✓ Branch 1 taken 171 times.
1728 else if (
399 // if we should optimize mirrors...
400
2/2
✓ Branch 0 taken 693 times.
✓ Branch 1 taken 171 times.
864 optimize_address == optimize_address_flag::MIRRORS
401 // we're in a bank with ram mirrors...
402
2/2
✓ Branch 0 taken 1308 times.
✓ Branch 1 taken 78 times.
1386 && !(relaxed_bank & 0x40)
403 // and the label is in a mirrored section
404
5/6
✓ Branch 0 taken 1308 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 753 times.
✓ Branch 3 taken 555 times.
✓ Branch 4 taken 36 times.
✓ Branch 5 taken 99 times.
1308 && !(bank & 0x40) && word < 0x8000 && !lblfreespace)
405 {
406 36 return 2;
407 }
408
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 1602 times.
1656 else if (optimizeforbank>=0)
409 {
410 // if optimizing for a specific bank:
411 // if the label is in freespace, never optimize
412
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 27 times.
54 if (thislabel.freespace_id > 0) return 3;
413
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 27 times.
54 else if (bank==(unsigned int)optimizeforbank) return 2;
414 36 else return 3;
415 }
416
4/4
✓ Branch 0 taken 1140 times.
✓ Branch 1 taken 462 times.
✓ Branch 2 taken 162 times.
✓ Branch 3 taken 978 times.
1602 else if (thislabel.freespace_id > 0 || freespaceid > 0)
417 {
418 // optimize only if the label is in the same freespace
419 // TODO: check whether they're pinned to the same bank
420
2/2
✓ Branch 0 taken 312 times.
✓ Branch 1 taken 312 times.
624 if (thislabel.freespace_id != freespaceid) return 3;
421 96 else return 2;
422 }
423
2/2
✓ Branch 0 taken 489 times.
✓ Branch 1 taken 489 times.
978 else if ((int)bank != snespos >> 16){ return 3; }
424 900 else { return 2;}
425 }
426
427
428 669 bool is_hex_constant(const char* str){
429
2/2
✓ Branch 0 taken 576 times.
✓ Branch 1 taken 93 times.
669 if (*str=='$')
430 {
431 576 str++;
432
2/2
✓ Branch 0 taken 1620 times.
✓ Branch 1 taken 576 times.
2196 while(is_xdigit(*str)) {
433 1620 str++;
434 }
435
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 288 times.
576 if(*str=='\0'){
436 288 return true;
437 }
438 }
439 48 return false;
440 }
441
442 bool in_getlen;
443 9264 int getlen(const char * orgstr, bool optimizebankextraction)
444 {
445 9264 const char * str=orgstr;
446 9264 freespaced=false;
447
448 9264 const char* posneglabel = str;
449
1/2
✓ Branch 0 taken 4638 times.
✗ Branch 1 not taken.
9264 string posnegname = posneglabelname(&posneglabel, false);
450
451
2/2
✓ Branch 0 taken 4632 times.
✓ Branch 1 taken 4632 times.
9264 if (posnegname.length() > 0)
452 {
453
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (*posneglabel != '\0') goto notposneglabel;
454
455
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
10 if (!pass) return 2;
456 4 snes_label label_data;
457 // RPG Hacker: Umm... what kind of magic constant is this?
458
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
4 label_data.pos = 31415926;
459
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 bool found = labelval(posnegname, &label_data);
460
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 return getlenforlabel(label_data, found);
461 }
462 9258 notposneglabel:
463 4632 int len=0;
464
2/2
✓ Branch 0 taken 9690 times.
✓ Branch 1 taken 9258 times.
18948 while (*str)
465 {
466 4848 int thislen=0;
467 9690 bool maybebankextraction=(str==orgstr);
468
2/2
✓ Branch 0 taken 7059 times.
✓ Branch 1 taken 2631 times.
9690 if (*str=='$')
469 {
470 7059 str++;
471 int i;
472
2/2
✓ Branch 0 taken 19128 times.
✓ Branch 1 taken 7059 times.
26187 for (i=0;is_xdigit(str[i]);i++);
473 //if (i&1) warn(S dec(i)+"-digit hex value");//blocked in getnum instead
474 7059 thislen=(i+1)/2;
475 7059 str+=i;
476 }
477
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2631 times.
2631 else if (*str=='%')
478 {
479 str++;
480 int i;
481 for (i=0;str[i]=='0' || str[i]=='1';i++);
482 //if (i&7) warn(S dec(i)+"-digit binary value");
483 thislen=(i+7)/8;
484 str+=i;
485 }
486
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2631 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2631 else if (str[0]=='\'' && str[2]=='\'')
487 {
488 thislen=1;
489 str+=3;
490 }
491
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 2592 times.
2631 else if (is_digit(*str))
492 {
493 39 int val=strtol(str, const_cast<char**>(&str), 10);
494
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 if (val>=0) thislen=1;
495
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 21 times.
39 if (val>=256) thislen=2;
496
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if (val>=65536) thislen=3;
497 }
498
7/8
✓ Branch 0 taken 306 times.
✓ Branch 1 taken 2286 times.
✓ Branch 2 taken 306 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 153 times.
✓ Branch 5 taken 153 times.
✓ Branch 6 taken 1143 times.
✓ Branch 7 taken 153 times.
2592 else if (is_ualpha(*str) || *str=='.' || *str=='?')
499 {
500 1143 snes_label thislabel;
501 2286 in_getlen = true;
502 struct guard {
503 2286 ~guard() { in_getlen = false; }
504 } _g;
505
1/2
✓ Branch 0 taken 2286 times.
✗ Branch 1 not taken.
2286 bool exists=labelval(&str, &thislabel);
506
1/2
✓ Branch 0 taken 1143 times.
✗ Branch 1 not taken.
2286 thislen=getlenforlabel(thislabel, exists);
507 1143 }
508 306 else str++;
509
4/4
✓ Branch 0 taken 1425 times.
✓ Branch 1 taken 8265 times.
✓ Branch 2 taken 606 times.
✓ Branch 3 taken 216 times.
9690 if (optimizebankextraction && maybebankextraction &&
510
4/6
✓ Branch 0 taken 1209 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1209 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 603 times.
✓ Branch 5 taken 606 times.
1209 (!strcmp(str, ">>16") || !strcmp(str, "/65536") || !strcmp(str, "/$10000")))
511 return 1;
512
2/2
✓ Branch 0 taken 4659 times.
✓ Branch 1 taken 189 times.
4848 if (thislen>len) len=thislen;
513 }
514 4632 return len;
515 9264 }
516
517 struct strcompare {
518 bool operator() (const char * lhs, const char * rhs) const
519 {
520 return strcmp(lhs, rhs)<0;
521 }
522 };
523
524 struct stricompare {
525 bool operator() (const char * lhs, const char * rhs) const
526 {
527 return stricmp(lhs, rhs)<0;
528 }
529 };
530
531 struct sourcefile {
532 char *data;
533 char** contents;
534 int numlines;
535 };
536
537 static assocarr<sourcefile> filecontents;
538 assocarr<string> defines;
539 // needs to be separate because defines is reset between parsing arguments and patching
540 assocarr<string> clidefines;
541 assocarr<string> builtindefines;
542
543 5305 bool validatedefinename(const char * name)
544 {
545
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5305 times.
5305 if (!name[0]) return false;
546
2/2
✓ Branch 0 taken 55286 times.
✓ Branch 1 taken 5305 times.
60591 for (int i = 0;name[i];i++)
547 {
548
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55286 times.
55286 if (!is_ualnum(name[i])) return false;
549 }
550
551 2661 return true;
552 }
553
554 191464 void resolvedefines(string& out, const char * start)
555 {
556
2/2
✓ Branch 0 taken 93323 times.
✓ Branch 1 taken 3 times.
93326 recurseblock rec;
557 93323 const char * here=start;
558
2/2
✓ Branch 0 taken 160148 times.
✓ Branch 1 taken 31310 times.
191458 if (!strchr(here, '!'))
559 {
560
1/2
✓ Branch 0 taken 160148 times.
✗ Branch 1 not taken.
160148 out += here;
561 77644 return;
562 }
563
2/2
✓ Branch 0 taken 214031 times.
✓ Branch 1 taken 31219 times.
245250 while (*here)
564 {
565
4/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 213887 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 126 times.
214031 if (here[0] == '\\' && here[1] == '\\')
566 {
567 // allow using \\ as escape sequence
568
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 += "\\";
569
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 out += "\\";
570 18 here += 2;
571 }
572
3/4
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 213887 times.
✓ Branch 2 taken 126 times.
✗ Branch 3 not taken.
214013 else if (here[0] == '\\' && here[1] == '!')
573 {
574 // allow using \! to escape !
575
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 += "\\";
576
1/2
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
126 out+="!";
577 126 here += 2;
578 }
579
2/2
✓ Branch 0 taken 33608 times.
✓ Branch 1 taken 180279 times.
213887 else if (*here=='!')
580 {
581
10/10
✓ Branch 0 taken 16311 times.
✓ Branch 1 taken 17297 times.
✓ Branch 2 taken 10065 times.
✓ Branch 3 taken 6246 times.
✓ Branch 4 taken 7692 times.
✓ Branch 5 taken 2373 times.
✓ Branch 6 taken 360 times.
✓ Branch 7 taken 7332 times.
✓ Branch 8 taken 36 times.
✓ Branch 9 taken 324 times.
33608 bool first=(here==start || (here>=start+4 && here[-1]==' ' && here[-2]==':' && here[-3]==' '));//check if it's the start of a block
582 16834 string defname;
583 33608 here++;
584
585 16834 int depth = 0;
586
2/2
✓ Branch 0 taken 342 times.
✓ Branch 1 taken 33608 times.
33950 for (const char* depth_str = here; *depth_str=='^'; depth_str++)
587 {
588 342 depth++;
589 }
590 33608 here += depth;
591
592
2/2
✓ Branch 0 taken 3963 times.
✓ Branch 1 taken 29645 times.
33608 if (depth != in_macro_def)
593 {
594
1/2
✓ Branch 0 taken 3963 times.
✗ Branch 1 not taken.
3963 out += '!';
595
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 += '^';
596
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);
597 1956 continue;
598 3909 }
599
600
2/2
✓ Branch 0 taken 324 times.
✓ Branch 1 taken 29321 times.
29645 if (*here=='{')
601 {
602 324 here++;
603 162 string unprocessedname;
604 162 int braces=1;
605 while (true)
606 {
607
2/2
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 3240 times.
3456 if (*here=='{') braces++;
608
2/2
✓ Branch 0 taken 540 times.
✓ Branch 1 taken 2916 times.
3456 if (*here=='}') braces--;
609
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);
610
2/2
✓ Branch 0 taken 1728 times.
✓ Branch 1 taken 1728 times.
3456 if (!braces) break;
611
1/2
✓ Branch 0 taken 3132 times.
✗ Branch 1 not taken.
3132 unprocessedname+=*here++;
612 }
613
1/2
✓ Branch 0 taken 162 times.
✗ Branch 1 not taken.
324 here++;
614
1/2
✓ Branch 0 taken 324 times.
✗ Branch 1 not taken.
324 resolvedefines(defname, unprocessedname);
615
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);
616 324 }
617 else
618 {
619
3/4
✓ Branch 0 taken 149945 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 149945 times.
✓ Branch 3 taken 29321 times.
179266 while (is_ualnum(*here)) defname+=*here++;
620 }
621
622
2/2
✓ Branch 0 taken 15803 times.
✓ Branch 1 taken 13842 times.
29645 if (first)
623 {
624 enum {
625 null,
626 append,
627 expand,
628 domath,
629 setifnotset,
630 } mode;
631 if(0);
632
2/2
✓ Branch 0 taken 1560 times.
✓ Branch 1 taken 14243 times.
15803 else if (stribegin(here, " = ")) { here+=3; mode=null; }
633
2/2
✓ Branch 0 taken 306 times.
✓ Branch 1 taken 13937 times.
14243 else if (stribegin(here, " += ")) { here+=4; mode=append; }
634
2/2
✓ Branch 0 taken 165 times.
✓ Branch 1 taken 13772 times.
13937 else if (stribegin(here, " := ")) { here+=4; mode=expand; }
635
2/2
✓ Branch 0 taken 5778 times.
✓ Branch 1 taken 7994 times.
13772 else if (stribegin(here, " #= ")) { here+=4; mode=domath; }
636
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 7982 times.
7994 else if (stribegin(here, " ?= ")) { here+=4; mode=setifnotset; }
637 7982 else goto notdefineset;
638 3918 string val;
639
2/2
✓ Branch 0 taken 561 times.
✓ Branch 1 taken 7260 times.
7821 if (*here=='"')
640 {
641 561 here++;
642 while (true)
643 {
644
2/2
✓ Branch 0 taken 579 times.
✓ Branch 1 taken 2484 times.
3063 if (*here=='"')
645 {
646
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;
647
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 else if (here[1]=='"') here++;
648 else asar_throw_error(0, error_type_line, error_id_broken_define_declaration);
649 }
650
1/2
✓ Branch 0 taken 2502 times.
✗ Branch 1 not taken.
2502 val+=*here++;
651 }
652 561 here++;
653 }
654 else
655 {
656
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++;
657 }
658 //if (strqchr(val.data(), ';')) *strqchr(val.data(), ';')=0;
659
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);
660 // RPG Hacker: Is it really a good idea to normalize
661 // the content of defines? That kinda violates their
662 // functionality as a string replacement mechanism.
663 //val.qnormalize();
664
665 // RPG Hacker: throw an error if we're trying to overwrite built-in defines.
666
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))
667 {
668 18 asar_throw_error(0, error_type_line, error_id_overriding_builtin_define, defname.data());
669 }
670
671
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)
672 {
673 777 case null:
674 {
675
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;
676 777 break;
677 }
678 153 case append:
679 {
680
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());
681
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);
682
2/4
✓ Branch 0 taken 306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 153 times.
✗ Branch 3 not taken.
306 val=oldval+val;
683
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;
684 153 break;
685 306 }
686 84 case expand:
687 {
688 84 string newval;
689
1/2
✓ Branch 0 taken 165 times.
✗ Branch 1 not taken.
165 resolvedefines(newval, val);
690
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;
691 84 break;
692 165 }
693 2889 case domath:
694 {
695 2889 string newval;
696
1/2
✓ Branch 0 taken 5778 times.
✗ Branch 1 not taken.
5778 resolvedefines(newval, val);
697
1/2
✓ Branch 0 taken 5778 times.
✗ Branch 1 not taken.
5778 double num= getnumdouble(newval);
698
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);
699
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);
700 2880 break;
701 5778 }
702 6 case setifnotset:
703 {
704
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;
705 6 break;
706 }
707 }
708 7821 }
709 else
710 {
711
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 10828 times.
17830 notdefineset:
712
3/4
✓ Branch 0 taken 135 times.
✓ Branch 1 taken 21689 times.
✓ Branch 2 taken 135 times.
✗ Branch 3 not taken.
21824 if (!defname) out+="!";
713 else
714 {
715
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());
716 else {
717
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);
718
1/2
✓ Branch 0 taken 21688 times.
✗ Branch 1 not taken.
21688 resolvedefines(out, thisone);
719 21688 }
720 }
721 }
722
2/2
✓ Branch 0 taken 14832 times.
✓ Branch 1 taken 1956 times.
33608 }
723
1/2
✓ Branch 0 taken 180279 times.
✗ Branch 1 not taken.
180279 else out+=*here++;
724 }
725
5/8
✓ Branch 0 taken 31219 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 31201 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
31219 if (!confirmquotes(out)) { asar_throw_error(0, error_type_null, error_id_mismatched_quotes); out = ""; }
726
2/2
✓ Branch 0 taken 15633 times.
✓ Branch 1 taken 77644 times.
191458 }
727
728 bool moreonline;
729 bool asarverallowed = false;
730
731 159057 void assembleline(const char * fname, int linenum, const char * line, int& single_line_for_tracker)
732 {
733
1/2
✓ Branch 0 taken 77088 times.
✗ Branch 1 not taken.
77088 recurseblock rec;
734
1/2
✓ Branch 0 taken 81969 times.
✗ Branch 1 not taken.
159057 bool moreonlinetmp=moreonline;
735 // randomdude999: redundant, assemblefile already converted the path to absolute
736 //string absolutepath = filesystem->create_absolute_path("", fname);
737
1/2
✓ Branch 0 taken 77088 times.
✗ Branch 1 not taken.
77088 string absolutepath = fname;
738
1/2
✓ Branch 0 taken 81969 times.
✗ Branch 1 not taken.
159057 single_line_for_tracker = 1;
739 try
740 {
741
1/2
✓ Branch 0 taken 77088 times.
✗ Branch 1 not taken.
77088 string out=line;
742
1/2
✓ Branch 0 taken 159057 times.
✗ Branch 1 not taken.
159057 autoptr<char**> blocks=qsplitstr(out.temp_raw(), " : ");
743 159057 moreonline=true;
744
2/2
✓ Branch 0 taken 164526 times.
✓ Branch 1 taken 134199 times.
298725 for (int block=0;moreonline;block++)
745 {
746 164526 moreonline=(blocks[block+1] != nullptr);
747 try
748 {
749 // it's possible that our input looks something like:
750 // nop : : nop
751 // nop : : : : : nop
752 // also, it's possible that there were empty blocks at the start or end of the line:
753 // : nop :
754 // after qsplit, we still need to deal with possibly a single ": " from a preceding empty block,
755 // and if it's the last block, possibly a following " :".
756
1/2
✓ Branch 0 taken 79857 times.
✗ Branch 1 not taken.
164526 string stripped_block = strip_whitespace(blocks[block]);
757 79857 int i = 0;
758 // if the block starts with ": "
759
6/6
✓ Branch 0 taken 162 times.
✓ Branch 1 taken 164364 times.
✓ Branch 2 taken 72 times.
✓ Branch 3 taken 90 times.
✓ Branch 4 taken 36 times.
✓ Branch 5 taken 79821 times.
164526 if(stripped_block[i] == ':' && stripped_block[i+1] == ' ') {
760 36 i++;
761
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 72 times.
144 while(stripped_block[i] == ' ') i++;
762 }
763 // if the block is a single :, skip that too.
764
5/6
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 164436 times.
✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 45 times.
✓ Branch 5 taken 79812 times.
164526 if(stripped_block[i] == ':' && stripped_block[i+1] == 0) i++;
765
766 // last block - strip trailing " :" if present.
767
10/10
✓ Branch 0 taken 159057 times.
✓ Branch 1 taken 5469 times.
✓ Branch 2 taken 109443 times.
✓ Branch 3 taken 49614 times.
✓ Branch 4 taken 9144 times.
✓ Branch 5 taken 100299 times.
✓ Branch 6 taken 36 times.
✓ Branch 7 taken 9108 times.
✓ Branch 8 taken 18 times.
✓ Branch 9 taken 79839 times.
164526 if(!moreonline && stripped_block.length() >= 2 && stripped_block[stripped_block.length()-2] == ' ' && stripped_block[stripped_block.length()-1] == ':') {
768
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 stripped_block.truncate(stripped_block.length()-2);
769 }
770
771
1/2
✓ Branch 0 taken 164526 times.
✗ Branch 1 not taken.
164526 callstack_push cs_push(callstack_entry_type::BLOCK, stripped_block.data() + i);
772
773
2/2
✓ Branch 0 taken 138870 times.
✓ Branch 1 taken 25656 times.
164526 assembleblock(stripped_block.data() + i, single_line_for_tracker);
774
2/2
✓ Branch 0 taken 138858 times.
✓ Branch 1 taken 12 times.
138870 checkbankcross();
775 190194 }
776
2/2
✓ Branch 0 taken 24858 times.
✓ Branch 1 taken 810 times.
25668 catch (errblock&) {}
777
2/2
✓ Branch 0 taken 90600 times.
✓ Branch 1 taken 49068 times.
139668 if (blocks[block][0]!='\0') asarverallowed=false;
778
2/2
✓ Branch 0 taken 133209 times.
✓ Branch 1 taken 6459 times.
139668 if(single_line_for_tracker == 1) single_line_for_tracker = 0;
779 }
780 183915 }
781
1/2
✓ Branch 0 taken 24858 times.
✗ Branch 1 not taken.
24858 catch (errline&) {}
782 134199 moreonline=moreonlinetmp;
783 183915 }
784
785 int incsrcdepth=0;
786
787 // Returns true if a file is protected via
788 // an "includeonce".
789 27654 bool file_included_once(const char* file)
790 {
791
2/2
✓ Branch 0 taken 720 times.
✓ Branch 1 taken 27528 times.
28248 for (int i = 0; i < includeonce.count; ++i)
792 {
793
2/2
✓ Branch 0 taken 360 times.
✓ Branch 1 taken 360 times.
720 if (includeonce[i] == file)
794 {
795 63 return true;
796 }
797 }
798
799 11241 return false;
800 }
801
802 autoarray<string> macro_defs;
803 int in_macro_def=0;
804
805 27564 void assemblefile(const char * filename)
806 {
807 27564 incsrcdepth++;
808
2/4
✓ Branch 0 taken 11259 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11259 times.
✗ Branch 3 not taken.
27564 string absolutepath = filesystem->create_absolute_path(get_current_file_name(), filename);
809
810
4/4
✓ Branch 0 taken 27501 times.
✓ Branch 1 taken 63 times.
✓ Branch 2 taken 63 times.
✓ Branch 3 taken 11196 times.
27564 if (file_included_once(absolutepath))
811 {
812 63 return;
813 }
814
815
1/2
✓ Branch 0 taken 11196 times.
✗ Branch 1 not taken.
11196 callstack_push cs_push(callstack_entry_type::FILE, absolutepath);
816
817 sourcefile file;
818 27438 file.contents = nullptr;
819 27438 file.numlines = 0;
820
1/2
✓ Branch 0 taken 16242 times.
✗ Branch 1 not taken.
27438 int startif=numif;
821
3/4
✓ Branch 0 taken 27438 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 910 times.
✓ Branch 3 taken 26528 times.
27438 if (!filecontents.exists(absolutepath))
822 {
823
2/2
✓ Branch 0 taken 904 times.
✓ Branch 1 taken 6 times.
910 char * temp = readfile(absolutepath, "");
824
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 886 times.
904 if (!temp)
825 {
826
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);
827
828 9 return;
829 }
830
1/2
✓ Branch 0 taken 886 times.
✗ Branch 1 not taken.
886 sourcefile& newfile = filecontents.create(absolutepath);
831
1/2
✓ Branch 0 taken 886 times.
✗ Branch 1 not taken.
886 newfile.contents =split(temp, '\n');
832 886 newfile.data = temp;
833
2/2
✓ Branch 0 taken 34789 times.
✓ Branch 1 taken 886 times.
35675 for (int i=0;newfile.contents[i];i++)
834 {
835 34789 newfile.numlines++;
836 17442 char * line = newfile.contents[i];
837 17442 int i_temp = i;
838 char * comment;
839
2/2
✓ Branch 0 taken 9234 times.
✓ Branch 1 taken 34783 times.
44017 while((comment = strqchr(line, ';'))) {
840
3/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 9198 times.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
9234 if(comment[1] == '[' && comment[2] == '[') {
841 // block comment - find where it ends
842 36 char* theline = comment + 3;
843 36 char* comment_end = strstr(theline, "]]");
844
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 30 times.
90 while(comment_end == nullptr) {
845 60 i_temp++;
846 60 char* new_line = newfile.contents[i_temp];
847
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 54 times.
60 if(new_line == nullptr) {
848
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 callstack_push cs_push(callstack_entry_type::LINE, line, i);
849
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 asar_throw_error(0, error_type_null, error_id_unclosed_block_comment);
850 // make sure this line is still parsed correctly
851 6 *comment = 0;
852 // but don't go looking at any other lines
853 6 goto break_outer;
854 6 }
855 54 comment_end = strstr(new_line, "]]");
856 // this line is itself part of the comment, so ignore it
857 //new_line[0] = 0;
858 // except not like that^, because that will break the
859 // memmove below
860 static char junk[]="";
861 // using a static here should be fine, since if the line
862 // doesn't contain ',' or '\' we won't go mutating it
863 54 newfile.contents[i_temp] = junk;
864 }
865 // comment_end+2 is a valid pointer, since comment_end is
866 // guaranteed to start with ]]
867 30 comment_end += 2;
868 // stitch together the part of the line before the comment,
869 // and the part of the line after it
870 30 memmove(comment, comment_end, strlen(comment_end) + 1);
871 // and then recheck for ; in the line again...
872 30 } else {
873 9198 *comment = 0;
874 }
875 }
876 34783 break_outer:
877
3/4
✓ Branch 0 taken 34789 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 34777 times.
34789 if (!confirmquotes(line)) {
878
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 callstack_push cs_push(callstack_entry_type::LINE, line, i);
879
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 asar_throw_error(0, error_type_null, error_id_mismatched_quotes);
880 12 line[0] = '\0';
881 12 }
882 34789 newfile.contents[i] = strip_whitespace(line);
883 }
884
2/2
✓ Branch 0 taken 34789 times.
✓ Branch 1 taken 886 times.
35675 for(int i=0;newfile.contents[i];i++)
885 {
886 17442 char* line = newfile.contents[i];
887
2/2
✓ Branch 0 taken 13166 times.
✓ Branch 1 taken 21623 times.
34789 if(!*line) continue;
888
3/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 21623 times.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
21653 for (int j=1;line[strlen(line) - 1] == ',' && newfile.contents[i+j];j++)
889 {
890 // not using strcat because the source and dest overlap here
891 15 char* otherline = newfile.contents[i+j];
892 30 char* line_end = line + strlen(line);
893
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 30 times.
414 while(*otherline) *line_end++ = *otherline++;
894 30 *line_end = '\0';
895 static char nullstr[]="";
896 30 newfile.contents[i+j]=nullstr;
897 }
898 }
899 886 file = newfile;
900 } else { // filecontents.exists(absolutepath)
901
1/2
✓ Branch 0 taken 26528 times.
✗ Branch 1 not taken.
26528 file = filecontents.find(absolutepath);
902 }
903 27414 asarverallowed=true;
904
3/4
✓ Branch 0 taken 148293 times.
✓ Branch 1 taken 2550 times.
✓ Branch 2 taken 148293 times.
✗ Branch 3 not taken.
150843 for (int i=0;file.contents[i] && i<file.numlines;i++)
905 {
906 71709 string connectedline;
907
1/2
✓ Branch 0 taken 148293 times.
✗ Branch 1 not taken.
148293 int skiplines = getconnectedlines<char**>(file.contents, i, connectedline);
908
909
2/2
✓ Branch 0 taken 123429 times.
✓ Branch 1 taken 24864 times.
148293 bool was_loop_end = do_line_logic(connectedline, absolutepath, i);
910 123429 i += skiplines;
911
912 // if a loop ended on this line, should it run again?
913
8/8
✓ Branch 0 taken 6318 times.
✓ Branch 1 taken 117111 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 59859 times.
123429 if (was_loop_end && whilestatus[numif].cond)
914
1/2
✓ Branch 0 taken 1998 times.
✗ Branch 1 not taken.
3996 i = whilestatus[numif].startline - 1;
915 148293 }
916
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 2550 times.
2586 while (in_macro_def > 0)
917 {
918
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());
919
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);
920 36 in_macro_def--;
921 36 macro_defs.remove(in_macro_def);
922 }
923
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2550 times.
2550 if (numif!=startif)
924 {
925 numif=startif;
926 numtrue=startif;
927 asar_throw_error(0, error_type_null, error_id_unclosed_if);
928 }
929 2550 incsrcdepth--;
930
4/4
✓ Branch 0 taken 1332 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 1332 times.
✓ Branch 3 taken 72 times.
52443 }
931
932 // RPG Hacker: At some point, this should probably be merged
933 // into assembleline(), since the two names just cause
934 // confusion otherwise.
935 // return value is "did a loop end on this line"
936 169377 bool do_line_logic(const char* line, const char* filename, int lineno)
937 {
938 169377 int prevnumif = numif;
939
2/2
✓ Branch 0 taken 5049 times.
✓ Branch 1 taken 82071 times.
169377 int single_line_for_tracker = 1;
940 try
941 {
942 82257 string current_line;
943
8/8
✓ Branch 0 taken 10098 times.
✓ Branch 1 taken 159279 times.
✓ Branch 2 taken 8640 times.
✓ Branch 3 taken 1458 times.
✓ Branch 4 taken 504 times.
✓ Branch 5 taken 8136 times.
✓ Branch 6 taken 77460 times.
✓ Branch 7 taken 4797 times.
169377 if (numif==numtrue || (numtrue+1==numif && stribegin(line, "elseif ")))
944 {
945
1/2
✓ Branch 0 taken 77460 times.
✗ Branch 1 not taken.
77460 callstack_push cs_push(callstack_entry_type::LINE, line, lineno);
946
2/2
✓ Branch 0 taken 159477 times.
✓ Branch 1 taken 306 times.
159783 string tmp=replace_macro_args(line);
947
1/2
✓ Branch 0 taken 159477 times.
✗ Branch 1 not taken.
159477 tmp.qnormalize();
948
2/2
✓ Branch 0 taken 159381 times.
✓ Branch 1 taken 96 times.
159477 resolvedefines(current_line, tmp);
949
2/4
✓ Branch 0 taken 159381 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 159381 times.
159381 if (!confirmquotes(current_line)) asar_throw_error(0, error_type_line, error_id_mismatched_quotes);
950 159879 }
951
1/2
✓ Branch 0 taken 4797 times.
✗ Branch 1 not taken.
4797 else current_line=line;
952
953
1/2
✓ Branch 0 taken 82056 times.
✗ Branch 1 not taken.
82056 callstack_push cs_push(callstack_entry_type::LINE, current_line, lineno);
954
955
6/6
✓ Branch 0 taken 1662 times.
✓ Branch 1 taken 167313 times.
✓ Branch 2 taken 834 times.
✓ Branch 3 taken 828 times.
✓ Branch 4 taken 780 times.
✓ Branch 5 taken 81276 times.
168975 if (stribegin(current_line, "macro ") && numif==numtrue)
956 {
957 // RPG Hacker: Slight redundancy here with code that is
958 // also in startmacro(). Could improve this for Asar 2.0.
959
1/2
✓ Branch 0 taken 1554 times.
✗ Branch 1 not taken.
1554 string macro_name = current_line.data()+6;
960 1554 char * startpar=strqchr(macro_name.data(), '(');
961
1/2
✓ Branch 0 taken 1554 times.
✗ Branch 1 not taken.
1554 if (startpar) *startpar=0;
962
1/2
✓ Branch 0 taken 1554 times.
✗ Branch 1 not taken.
1554 macro_defs.append(macro_name);
963
964 // RPG Hacker: I think it would make more logical sense
965 // to have this ++ after the if, but hat breaks compatibility
966 // with at least one test, and it generally leads to more
967 // errors being output after a broken macro declaration.
968 1554 in_macro_def++;
969
2/2
✓ Branch 0 taken 518 times.
✓ Branch 1 taken 1036 times.
1554 if (!pass)
970 {
971
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);
972
1/2
✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
96 else tomacro(current_line);
973 }
974 1554 }
975
6/6
✓ Branch 0 taken 86961 times.
✓ Branch 1 taken 80460 times.
✓ Branch 2 taken 1572 times.
✓ Branch 3 taken 85389 times.
✓ Branch 4 taken 816 times.
✓ Branch 5 taken 81270 times.
167421 else if (!stricmp(current_line, "endmacro") && numif==numtrue)
976 {
977
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);
978 else
979 {
980 1518 in_macro_def--;
981 1518 macro_defs.remove(in_macro_def);
982
2/2
✓ Branch 0 taken 506 times.
✓ Branch 1 taken 1012 times.
1518 if (!pass)
983 {
984
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);
985
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 else tomacro(current_line);
986 }
987 }
988 }
989
2/2
✓ Branch 0 taken 6846 times.
✓ Branch 1 taken 159057 times.
165903 else if (in_macro_def > 0)
990 {
991
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);
992 }
993 else
994 {
995
2/2
✓ Branch 0 taken 134199 times.
✓ Branch 1 taken 24858 times.
159057 assembleline(filename, lineno, current_line, single_line_for_tracker);
996 }
997 194241 }
998
2/2
✓ Branch 0 taken 24864 times.
✓ Branch 1 taken 402 times.
25266 catch (errline&) {}
999
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 127725 times.
127905 return (numif != prevnumif || single_line_for_tracker == 3)
1000
9/10
✓ Branch 0 taken 127905 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.
289116 && (whilestatus[numif].iswhile || whilestatus[numif].is_for);
1001 }
1002
1003
1004 499 void parse_std_includes(const char* textfile, autoarray<string>& outarray)
1005 {
1006 499 char* content = readfilenative(textfile);
1007
1008
1/2
✓ Branch 0 taken 499 times.
✗ Branch 1 not taken.
499 if (content != nullptr)
1009 {
1010 251 char* pos = content;
1011
1012
2/2
✓ Branch 0 taken 1000 times.
✓ Branch 1 taken 499 times.
1499 while (pos[0] != '\0')
1013 {
1014 504 string stdinclude;
1015
1016 do
1017 {
1018
3/4
✓ Branch 0 taken 24700 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24199 times.
✓ Branch 3 taken 501 times.
24700 if (pos[0] != '\r' && pos[0] != '\n')
1019 {
1020
1/2
✓ Branch 0 taken 24199 times.
✗ Branch 1 not taken.
24199 stdinclude += pos[0];
1021 }
1022 24700 pos++;
1023
4/4
✓ Branch 0 taken 24201 times.
✓ Branch 1 taken 499 times.
✓ Branch 2 taken 23700 times.
✓ Branch 3 taken 501 times.
24700 } while (pos[0] != '\0' && pos[0] != '\n');
1024
1025
1/2
✓ Branch 0 taken 1000 times.
✗ Branch 1 not taken.
1000 strip_whitespace(stdinclude);
1026
1027
2/2
✓ Branch 0 taken 501 times.
✓ Branch 1 taken 499 times.
1000 if (stdinclude != "")
1028 {
1029
3/4
✓ Branch 0 taken 501 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 500 times.
501 if (!path_is_absolute(stdinclude))
1030 {
1031
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;
1032 }
1033
2/4
✓ Branch 0 taken 501 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 501 times.
✗ Branch 3 not taken.
501 outarray.append(normalize_path(stdinclude));
1034 }
1035 1000 }
1036
1037 499 free(content);
1038 }
1039 499 }
1040
1041 769 void parse_std_defines(const char* textfile)
1042 {
1043
1044 // RPG Hacker: add built-in defines.
1045 // (They're not really standard defines, but I was lazy and this was
1046 // one convenient place for doing it).
1047 769 builtindefines.create("assembler") = "asar";
1048
5/8
✓ Branch 0 taken 643 times.
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 274 times.
✓ Branch 4 taken 126 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 274 times.
✗ Branch 7 not taken.
769 builtindefines.create("assembler_ver") = dec(get_version_int());
1049
2/4
✓ Branch 0 taken 769 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 400 times.
✗ Branch 3 not taken.
769 builtindefines.create("assembler_time") = dec(time(nullptr));
1050
1051
2/2
✓ Branch 0 taken 397 times.
✓ Branch 1 taken 372 times.
769 if(textfile == nullptr) return;
1052
1053 499 char* content = readfilenative(textfile);
1054
1055
1/2
✓ Branch 0 taken 499 times.
✗ Branch 1 not taken.
499 if (content != nullptr)
1056 {
1057 251 char* pos = content;
1058
2/2
✓ Branch 0 taken 2993 times.
✓ Branch 1 taken 499 times.
3492 while (*pos != 0) {
1059 1505 string define_name;
1060 1505 string define_val;
1061
1062
4/4
✓ Branch 0 taken 29907 times.
✓ Branch 1 taken 1994 times.
✓ Branch 2 taken 28908 times.
✓ Branch 3 taken 999 times.
31901 while (*pos != '=' && *pos != '\n') {
1063
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28908 times.
28908 if(*pos == '\r') { pos++; continue; }
1064
1/2
✓ Branch 0 taken 28908 times.
✗ Branch 1 not taken.
28908 define_name += *pos;
1065 28908 pos++;
1066 }
1067
5/6
✓ Branch 0 taken 2497 times.
✓ Branch 1 taken 496 times.
✓ Branch 2 taken 1505 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1002 times.
✓ Branch 5 taken 503 times.
2993 if (*pos != 0 && *pos != '\r' && *pos != '\n') pos++; // skip =
1068
3/4
✓ Branch 0 taken 13464 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10471 times.
✓ Branch 3 taken 2993 times.
13464 while (*pos != 0 && *pos != '\n') {
1069
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10471 times.
10471 if(*pos == '\r') { pos++; continue; }
1070
1/2
✓ Branch 0 taken 10471 times.
✗ Branch 1 not taken.
10471 define_val += *pos;
1071 10471 pos++;
1072 }
1073
1/2
✓ Branch 0 taken 2993 times.
✗ Branch 1 not taken.
2993 if (*pos != 0)
1074 2993 pos++; // skip \n
1075 // clean define_name
1076
1/2
✓ Branch 0 taken 2993 times.
✗ Branch 1 not taken.
2993 strip_whitespace(define_name);
1077
1/2
✓ Branch 0 taken 2993 times.
✗ Branch 1 not taken.
2993 define_name.strip_prefix('!'); // remove leading ! if present
1078
1079
2/2
✓ Branch 0 taken 499 times.
✓ Branch 1 taken 2494 times.
2993 if (define_name == "")
1080 {
1081
1/2
✓ Branch 0 taken 499 times.
✗ Branch 1 not taken.
499 if (define_val == "")
1082 {
1083 499 continue;
1084 }
1085
1086 asar_throw_error(pass, error_type_null, error_id_stddefines_no_identifier);
1087 }
1088
1089
3/8
✓ Branch 0 taken 624 times.
✓ Branch 1 taken 1870 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 624 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2494 if (!validatedefinename(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_invalid, "stddefines.txt", define_name.data());
1090
1091 // clean define_val
1092 1254 const char* defval = define_val.data();
1093 1254 string cleaned_defval;
1094
1095
2/2
✓ Branch 0 taken 500 times.
✓ Branch 1 taken 1994 times.
2494 if (*defval == 0) {
1096 // no value
1097
2/6
✓ Branch 0 taken 500 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 500 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
500 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
1098
2/4
✓ Branch 0 taken 500 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 252 times.
✗ Branch 3 not taken.
500 clidefines.create(define_name) = "";
1099 500 continue;
1100 }
1101
1102
3/4
✓ Branch 0 taken 998 times.
✓ Branch 1 taken 1994 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1994 times.
2992 while (*defval == ' ' || *defval == '\t') defval++; // skip whitespace in beginning
1103
2/2
✓ Branch 0 taken 499 times.
✓ Branch 1 taken 1495 times.
1994 if (*defval == '"') {
1104 499 defval++; // skip opening quote
1105
3/4
✓ Branch 0 taken 6479 times.
✓ Branch 1 taken 499 times.
✓ Branch 2 taken 6479 times.
✗ Branch 3 not taken.
6978 while (*defval != '"' && *defval != 0)
1106
1/2
✓ Branch 0 taken 6479 times.
✗ Branch 1 not taken.
6479 cleaned_defval += *defval++;
1107
1108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 499 times.
499 if (*defval == 0) {
1109 asar_throw_error(pass, error_type_null, error_id_mismatched_quotes);
1110 }
1111 499 defval++; // skip closing quote
1112
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 499 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 499 times.
499 while (*defval == ' ' || *defval == '\t') defval++; // skip whitespace
1113
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 499 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
499 if (*defval != 0 && *defval != '\n')
1114 asar_throw_error(pass, error_type_null, error_id_stddefine_after_closing_quote);
1115
1116
2/6
✓ Branch 0 taken 499 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 499 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
499 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
1117
2/4
✓ Branch 0 taken 499 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 251 times.
✗ Branch 3 not taken.
499 clidefines.create(define_name) = cleaned_defval;
1118 499 continue;
1119 }
1120 else
1121 {
1122 // slightly hacky way to remove trailing whitespace
1123 1495 const char* defval_end = strchr(defval, '\n'); // slightly hacky way to get end of string or newline
1124
1/2
✓ Branch 0 taken 1495 times.
✗ Branch 1 not taken.
1495 if (!defval_end) defval_end = strchr(defval, 0);
1125 1495 defval_end--;
1126
3/4
✓ Branch 0 taken 501 times.
✓ Branch 1 taken 1495 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1495 times.
1996 while (*defval_end == ' ' || *defval_end == '\t') defval_end--;
1127
2/4
✓ Branch 0 taken 1495 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 744 times.
✗ Branch 3 not taken.
1495 cleaned_defval = string(defval, (int)(defval_end - defval + 1));
1128
1129
2/6
✓ Branch 0 taken 1495 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1495 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1495 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
1130
2/4
✓ Branch 0 taken 1495 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 751 times.
✗ Branch 3 not taken.
1495 clidefines.create(define_name) = cleaned_defval;
1131 1495 continue;
1132 1495 }
1133
1134 2993 }
1135 499 free(content);
1136 }
1137 }
1138
1139 bool checksum_fix_enabled = true;
1140 bool force_checksum_fix = false;
1141
1142 #define cfree(x) free((void*)x)
1143 414 static void clearmacro(const string & key, macrodata* & macro)
1144 {
1145 (void)key;
1146 414 freemacro(macro);
1147 414 }
1148
1149 885 static void clearfile(const string & key, sourcefile& filecontent)
1150 {
1151 (void)key;
1152 885 cfree(filecontent.data);
1153 885 cfree(filecontent.contents);
1154 885 }
1155 #undef cfree
1156
1157 4794 static void adddefine(const string & key, string & value)
1158 {
1159
1/2
✓ Branch 0 taken 4794 times.
✗ Branch 1 not taken.
4794 if (!defines.exists(key)) defines.create(key) = value;
1160 4794 }
1161
1162
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
182 string create_symbols_file(string format, uint32_t romCrc){
1163 92 string symbolfile;
1164
1165 92 std::vector<std::pair<unsigned int, const char*>> all_labels;
1166
1/2
✓ Branch 0 taken 182 times.
✗ Branch 1 not taken.
364 labels.each([&all_labels](const string& key, snes_label& label) {
1167
2/4
✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 186 times.
✗ Branch 3 not taken.
368 all_labels.push_back(std::make_pair(label.pos, key.data()));
1168 368 });
1169
1/2
✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
182 std::sort(all_labels.begin(), all_labels.end(),
1170 876 [](auto& l, auto& r) {
1171
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 792 times.
876 if (l.first == r.first)
1172 84 return strcmp(l.second, r.second) < 0;
1173 792 return l.first < r.first;
1174 });
1175
1176
1/2
✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
182 format = lower(format);
1177
1/2
✓ Branch 0 taken 182 times.
✗ Branch 1 not taken.
182 if(format == "wla")
1178 {
1179
1/2
✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
92 symbolfile = "; wla symbolic information file\n";
1180
1/2
✓ Branch 0 taken 182 times.
✗ Branch 1 not taken.
182 symbolfile += "; generated by asar\n";
1181
1182
1/2
✓ Branch 0 taken 182 times.
✗ Branch 1 not taken.
182 symbolfile += "\n[labels]\n";
1183
2/2
✓ Branch 0 taken 368 times.
✓ Branch 1 taken 182 times.
550 for (auto& p : all_labels) {
1184 char buffer[10];
1185
1/2
✓ Branch 0 taken 182 times.
✗ Branch 1 not taken.
368 std::snprintf(buffer, sizeof(buffer), "%02X:%04X ", (p.first >> 16) & 0xFF, p.first & 0xFFFF);
1186
1187
1/2
✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
368 symbolfile += buffer;
1188
1/2
✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
368 symbolfile += p.second;
1189
1/2
✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
368 symbolfile += "\n";
1190 }
1191
1192
1/2
✓ Branch 0 taken 182 times.
✗ Branch 1 not taken.
182 symbolfile += "\n[source files]\n";
1193 92 const autoarray<AddressToLineMapping::FileInfo>& addrToLineFileList = addressToLineMapping.getFileList();
1194
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 182 times.
372 for (int i = 0; i < addrToLineFileList.count; ++i)
1195 {
1196 char addrToFileListStr[256];
1197 286 snprintf(addrToFileListStr, 256, "%.4x %.8x %s\n",
1198 i,
1199
1/2
✓ Branch 0 taken 190 times.
✗ Branch 1 not taken.
190 addrToLineFileList[i].fileCrc,
1200
1/2
✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
96 addrToLineFileList[i].filename.data()
1201 );
1202
1/2
✓ Branch 0 taken 190 times.
✗ Branch 1 not taken.
190 symbolfile += addrToFileListStr;
1203 }
1204
1205
1/2
✓ Branch 0 taken 182 times.
✗ Branch 1 not taken.
182 symbolfile += "\n[rom checksum]\n";
1206 {
1207 char romCrcStr[32];
1208
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
182 snprintf(romCrcStr, 32, "%.8x\n",
1209 romCrc
1210 );
1211
1/2
✓ Branch 0 taken 182 times.
✗ Branch 1 not taken.
182 symbolfile += romCrcStr;
1212 }
1213
1214
1/2
✓ Branch 0 taken 182 times.
✗ Branch 1 not taken.
182 symbolfile += "\n[addr-to-line mapping]\n";
1215 92 const autoarray<AddressToLineMapping::AddrToLineInfo>& addrToLineInfo = addressToLineMapping.getAddrToLineInfo();
1216
2/2
✓ Branch 0 taken 5432 times.
✓ Branch 1 taken 182 times.
5614 for (int i = 0; i < addrToLineInfo.count; ++i)
1217 {
1218 char addrToLineStr[32];
1219 13589 snprintf(addrToLineStr, 32, "%.2x:%.4x %.4x:%.8x\n",
1220 8151 (addrToLineInfo[i].addr & 0xFF0000) >> 16,
1221
1/2
✓ Branch 0 taken 2719 times.
✗ Branch 1 not taken.
5432 addrToLineInfo[i].addr & 0xFFFF,
1222
1/2
✓ Branch 0 taken 2719 times.
✗ Branch 1 not taken.
5432 addrToLineInfo[i].fileIdx & 0xFFFF,
1223
2/4
✓ Branch 0 taken 5432 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2719 times.
✗ Branch 3 not taken.
5432 addrToLineInfo[i].line & 0xFFFFFFFF
1224 );
1225
1/2
✓ Branch 0 taken 5432 times.
✗ Branch 1 not taken.
5432 symbolfile += addrToLineStr;
1226 }
1227
1228 }
1229 else if (format == "nocash")
1230 {
1231 symbolfile = ";no$sns symbolic information file\n";
1232 symbolfile += ";generated by asar\n";
1233 symbolfile += "\n";
1234 for (auto& p : all_labels) {
1235 char buffer[10];
1236 std::snprintf(buffer, sizeof(buffer), "%08X ", p.first & 0xFFFFFF);
1237
1238 symbolfile += buffer;
1239 symbolfile += p.second;
1240 symbolfile += "\n";
1241 }
1242 }
1243 274 return symbolfile;
1244 92 }
1245
1246
1247 6 bool in_top_level_file()
1248 {
1249 3 int num_files = 0;
1250
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 6 times.
30 for (int i = callstack.count-1; i >= 0; --i)
1251 {
1252
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 18 times.
24 if (callstack[i].type == callstack_entry_type::FILE)
1253 {
1254 6 num_files++;
1255
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (num_files > 1) break;
1256 }
1257 }
1258 6 return (num_files <= 1);
1259 }
1260
1261 45224 const char* get_current_file_name()
1262 {
1263
2/2
✓ Branch 0 taken 170756 times.
✓ Branch 1 taken 2248 times.
173004 for (int i = callstack.count-1; i >= 0; --i)
1264 {
1265
2/2
✓ Branch 0 taken 42976 times.
✓ Branch 1 taken 127780 times.
170756 if (callstack[i].type == callstack_entry_type::FILE)
1266 42976 return callstack[i].content.raw();
1267 }
1268 1171 return nullptr;
1269 }
1270
1271 26750 int get_current_line()
1272 {
1273
2/2
✓ Branch 0 taken 79135 times.
✓ Branch 1 taken 21 times.
79156 for (int i = callstack.count-1; i >= 0; --i)
1274 {
1275
2/2
✓ Branch 0 taken 26729 times.
✓ Branch 1 taken 52406 times.
92480 if (callstack[i].type == callstack_entry_type::LINE) return callstack[i].lineno;
1276 }
1277 11 return -1;
1278 }
1279
1280 702 const char* get_current_block()
1281 {
1282
2/2
✓ Branch 0 taken 707 times.
✓ Branch 1 taken 31 times.
738 for (int i = callstack.count-1; i >= 0; --i)
1283 {
1284
6/6
✓ Branch 0 taken 539 times.
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 503 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 338 times.
✓ Branch 5 taken 18 times.
1307 if (callstack[i].type == callstack_entry_type::LINE || callstack[i].type == callstack_entry_type::BLOCK) return callstack[i].content.raw();
1285 }
1286 16 return nullptr;
1287 }
1288
1289
1290 774 void reseteverything()
1291 {
1292 403 string str;
1293 403 labels.reset();
1294 403 defines.reset();
1295
1/2
✓ Branch 0 taken 774 times.
✗ Branch 1 not taken.
774 builtindefines.each(adddefine);
1296
1/2
✓ Branch 0 taken 774 times.
✗ Branch 1 not taken.
774 clidefines.each(adddefine);
1297 403 structs.reset();
1298
1299
1/2
✓ Branch 0 taken 774 times.
✗ Branch 1 not taken.
774 macros.each(clearmacro);
1300 403 macros.reset();
1301
1302
1/2
✓ Branch 0 taken 774 times.
✗ Branch 1 not taken.
774 filecontents.each(clearfile);
1303 403 filecontents.reset();
1304
1305 774 writtenblocks.reset();
1306
1307 774 optimizeforbank=-1;
1308 774 optimize_dp = optimize_dp_flag::ALWAYS;
1309 774 dp_base = 0;
1310 774 optimize_address = optimize_address_flag::MIRRORS;
1311
1312
1/2
✓ Branch 0 taken 774 times.
✗ Branch 1 not taken.
774 closecachedfiles();
1313
1314 774 incsrcdepth=0;
1315 774 label_counter = 0;
1316 774 errored = false;
1317 774 checksum_fix_enabled = true;
1318 774 force_checksum_fix = false;
1319
1320 774 in_macro_def = 0;
1321
1322 #ifndef ASAR_SHARED
1323 250 free(const_cast<unsigned char*>(romdata_r));
1324 #endif
1325
1326 774 callstack.reset();
1327 774 simple_callstacks = true;
1328 #undef free
1329 774 }
1330