asar coverage - build #266


src/asar/
File: src/asar/main.cpp
Date: 2025-03-01 20:27:29
Lines:
615/687
89.5%
Functions:
37/38
97.4%
Branches:
855/1389
61.6%

Line Branch Exec Source
1 // "because satanism is best defeated by summoning a bigger satan"
2 // ~Alcaro, 2019 (discussing Asar)
3 #include "addr2line.h"
4 #include "asar.h"
5 #include "virtualfile.h"
6 #include "platform/file-helpers.h"
7 #include "assembleblock.h"
8 #include "asar_math.h"
9 #include "macro.h"
10 #include <algorithm>
11 #include <ctime>
12 // randomdude999: remember to also update the .rc files (in res/windows/) when changing this.
13 // Couldn't find a way to automate this without shoving the version somewhere in the CMake files
14 const int asarver_maj=2;
15 const int asarver_min=0;
16 const int asarver_bug=0;
17 const bool asarver_beta=true;
18
19 #ifdef _I_RELEASE
20 extern char blockbetareleases[(!asarver_beta)?1:-1];
21 #endif
22 #ifdef _I_DEBUG
23 extern char blockreleasedebug[(asarver_beta)?1:-1];
24 #endif
25
26 unsigned const char * romdata_r;
27 int romlen_r;
28
29 int pass;
30
31 int optimizeforbank=-1;
32 int optimize_dp = optimize_dp_flag::ALWAYS;
33 int dp_base = 0;
34 int optimize_address = optimize_address_flag::MIRRORS;
35
36 autoarray<callstack_entry> callstack;
37
38 bool errored=false;
39 bool ignoretitleerrors=false;
40
41 int recursioncount=0;
42
43 virtual_filesystem* filesystem = nullptr;
44
45 AddressToLineMapping addressToLineMapping;
46
47 284 int get_version_int()
48 {
49 284 return asarver_maj * 10000 + asarver_min * 100 + asarver_bug;
50 }
51
52 bool setmapper()
53 {
54 int maxscore=-99999;
55 mapper_t bestmap=lorom;
56 mapper_t maps[]={lorom, hirom, exlorom, exhirom};
57 for (size_t mapid=0;mapid<sizeof(maps)/sizeof(maps[0]);mapid++)
58 {
59 mapper=maps[mapid];
60 int score=0;
61 int highbits=0;
62 bool foundnull=false;
63 for (int i=0;i<21;i++)
64 {
65 unsigned char c=romdata[snestopc(0x00FFC0+i)];
66 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 if (c>=128) highbits++;
68 else if (is_upper(c)) score+=3;
69 else if (c==' ') score+=2;
70 else if (is_digit(c)) score+=1;
71 else if (is_lower(c)) score+=1;
72 else if (c=='-') score+=1;
73 else if (!c) foundnull=true;
74 else score-=3;
75 }
76 if (highbits>0 && highbits<=14) score-=21;//high bits set on some, but not all, bytes = unlikely to be a ROM
77 if ((romdata[snestopc(0x00FFDE)]^romdata[snestopc(0x00FFDC)])!=0xFF ||
78 (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 if (score>maxscore)
81 {
82 maxscore=score;
83 bestmap=mapper;
84 }
85 }
86 mapper=bestmap;
87
88 //detect oddball mappers
89 int mapperbyte=romdata[snestopc(0x00FFD5)];
90 int romtypebyte=romdata[snestopc(0x00FFD6)];
91 if (mapper==lorom)
92 {
93 if (mapperbyte==0x23 && (romtypebyte==0x32 || romtypebyte==0x34 || romtypebyte==0x35)) mapper=sa1rom;
94 }
95 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 3888 static string shorten_to_relative_path(const char* base_path, const char* target_path)
104 {
105
3/4
✓ Branch 0 taken 2659 times.
✓ Branch 1 taken 1229 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 185 times.
3888 if (stribegin(target_path, base_path)) target_path += strlen(base_path);
106 3888 return target_path;
107 }
108
109 3888 static string get_top_level_directory()
110 {
111 3888 string top_level_file_dir;
112
1/2
✓ Branch 0 taken 3888 times.
✗ Branch 1 not taken.
3888 for (int i = 0; i < callstack.count; ++i)
113 {
114
3/5
✓ Branch 0 taken 3888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2475 times.
✓ Branch 3 taken 1413 times.
✗ Branch 4 not taken.
3888 if (callstack[i].type == callstack_entry_type::FILE)
115 {
116
4/7
✓ Branch 0 taken 2475 times.
✓ Branch 1 taken 1413 times.
✓ Branch 2 taken 2475 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1413 times.
✗ Branch 6 not taken.
3888 top_level_file_dir = dir(callstack[i].content);
117 3888 break;
118 }
119 }
120 3888 return top_level_file_dir;
121 }
122
123 3846 static string generate_call_details_string(const char* current_block, const char* current_call, int indentation, bool add_lines)
124 {
125 3846 string e;
126
4/4
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 3784 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 12 times.
3846 if (current_block != nullptr || current_call != nullptr)
127 {
128 3834 string indent;
129
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3830 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
3834 if (add_lines) indent += "|";
130
3/4
✓ Branch 0 taken 1060 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1060 times.
✓ Branch 3 taken 3834 times.
4894 for (; indentation > 0; --indentation) indent += " ";
131
132
12/22
✓ Branch 0 taken 3784 times.
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 2427 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2427 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3784 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2427 times.
✓ Branch 9 taken 1357 times.
✓ Branch 10 taken 2427 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3784 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 1357 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 1357 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 1357 times.
✗ Branch 21 not taken.
3834 if (current_block != nullptr) e += STR "\n"+indent+"in block: ["+current_block+"]";
133
12/22
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 3784 times.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 50 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 21 times.
✓ Branch 9 taken 29 times.
✓ Branch 10 taken 21 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 50 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 29 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 29 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 29 times.
✗ Branch 21 not taken.
3834 if (current_call != nullptr) e += STR "\n"+indent+"in macro call: [%"+current_call+"]";
134 3834 }
135 3846 return e;
136 }
137
138 3888 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
4/7
✓ Branch 0 taken 2475 times.
✓ Branch 1 taken 1413 times.
✓ Branch 2 taken 2475 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1413 times.
✗ Branch 6 not taken.
7776 return shorten_to_relative_path(get_top_level_directory(), current_file);
146 }
147
148 311 static string generate_filename_and_line(const char* current_file, int current_line_no)
149 {
150
1/2
✓ Branch 0 taken 311 times.
✗ Branch 1 not taken.
622 return STR current_file
151
21/38
✓ Branch 0 taken 145 times.
✓ Branch 1 taken 160 times.
✓ Branch 2 taken 151 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 145 times.
✓ Branch 5 taken 154 times.
✓ Branch 6 taken 145 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 305 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 145 times.
✓ Branch 13 taken 160 times.
✓ Branch 14 taken 145 times.
✓ Branch 15 taken 12 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 20 taken 160 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 154 times.
✓ Branch 23 taken 6 times.
✓ Branch 24 taken 154 times.
✓ Branch 25 taken 6 times.
✓ Branch 26 taken 154 times.
✓ Branch 27 taken 6 times.
✓ Branch 28 taken 154 times.
✓ Branch 29 taken 6 times.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
933 + (current_line_no>=0?STR ":"+dec(current_line_no+1):"");
152 }
153
154 4 static string format_stack_line(const printable_callstack_entry& entry, int stack_frame_index)
155 {
156
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 string indent = "\n| ";
157
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
4 indent += dec(stack_frame_index);
158
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 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
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 if (stack_frame_index < 100) indent += " ";
162
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 if (stack_frame_index < 10) indent += " ";
163 return indent
164
2/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
8 + generate_filename_and_line(entry.prettypath, entry.lineno)
165
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
12 + entry.details;
166 4 }
167
168 3581 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 3581 printable_callstack_entry new_entry;
171
1/2
✓ Branch 0 taken 3581 times.
✗ Branch 1 not taken.
3581 new_entry.fullpath = current_file;
172
2/3
✓ Branch 0 taken 2324 times.
✓ Branch 1 taken 1257 times.
✗ Branch 2 not taken.
3581 new_entry.prettypath = get_pretty_filename(current_file);
173 3581 new_entry.lineno = current_line_no;
174
4/7
✓ Branch 0 taken 2324 times.
✓ Branch 1 taken 1257 times.
✓ Branch 2 taken 2324 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1257 times.
✗ Branch 6 not taken.
3581 new_entry.details = generate_call_details_string(current_block, current_call, indentation, add_lines).raw();
175
2/3
✓ Branch 0 taken 2324 times.
✓ Branch 1 taken 1257 times.
✗ Branch 2 not taken.
3581 out->append(new_entry);
176 4838 }
177
178 266 void get_current_line_details(string* location, string* details, bool exclude_block)
179 {
180 266 const char* current_file = nullptr;
181 266 const char* current_block = nullptr;
182 266 const char* current_call = nullptr;
183 266 int current_line_no = -1;
184
2/2
✓ Branch 0 taken 908 times.
✓ Branch 1 taken 1 times.
909 for (int i = callstack.count-1; i >= 0 ; --i)
185 {
186
5/6
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 135 times.
✓ Branch 2 taken 124 times.
✓ Branch 3 taken 319 times.
✓ Branch 4 taken 200 times.
✗ Branch 5 not taken.
908 switch (callstack[i].type)
187 {
188 265 case callstack_entry_type::FILE:
189 265 current_file = callstack[i].content;
190
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 265 times.
265 if (exclude_block) current_block = nullptr;
191
3/8
✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 265 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 135 times.
✗ Branch 7 not taken.
265 *location = generate_filename_and_line(get_pretty_filename(current_file), current_line_no);
192
2/3
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 135 times.
✗ Branch 2 not taken.
265 *details = generate_call_details_string(current_block, current_call, 4, false);
193 265 return;
194 case callstack_entry_type::MACRO_CALL:
195 if (current_call == nullptr) current_call = callstack[i].content;
196 break;
197 253 case callstack_entry_type::LINE:
198
3/4
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 197 times.
✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
253 if (current_block == nullptr && current_call == nullptr) current_block = callstack[i].content;
199
1/2
✓ Branch 0 taken 253 times.
✗ Branch 1 not taken.
253 if (current_line_no == -1) current_line_no = callstack[i].lineno;
200 253 break;
201 390 case callstack_entry_type::BLOCK:
202
2/2
✓ Branch 0 taken 197 times.
✓ Branch 1 taken 193 times.
390 if (current_block == nullptr) current_block = callstack[i].content;
203 390 break;
204 }
205 }
206 1 *location = "";
207 1 *details = "";
208 }
209
210 268 void get_full_printable_callstack(autoarray<printable_callstack_entry>* out, int indentation, bool add_lines)
211 {
212 268 out->reset();
213 268 const char* current_file = nullptr;
214 268 const char* current_block = nullptr;
215 268 const char* current_call = nullptr;
216 268 int current_line_no = -1;
217
2/2
✓ Branch 0 taken 15290 times.
✓ Branch 1 taken 268 times.
15558 for (int i = 0; i < callstack.count; ++i)
218 {
219
5/6
✓ Branch 0 taken 2454 times.
✓ Branch 1 taken 1415 times.
✓ Branch 2 taken 2477 times.
✓ Branch 3 taken 6226 times.
✓ Branch 4 taken 2718 times.
✗ Branch 5 not taken.
15290 switch (callstack[i].type)
220 {
221 3848 case callstack_entry_type::FILE:
222
2/2
✓ Branch 0 taken 3581 times.
✓ Branch 1 taken 267 times.
3848 if (current_file != nullptr)
223 {
224 3581 push_stack_line(out, current_file, current_block, current_call, current_line_no, indentation, add_lines);
225 }
226 3848 current_file = callstack[i].content;
227 3848 current_block = nullptr;
228 3848 current_call = nullptr;
229 3848 current_line_no = -1;
230 3848 break;
231 50 case callstack_entry_type::MACRO_CALL:
232 50 current_block = nullptr;
233 50 current_call = callstack[i].content;
234 50 break;
235 3836 case callstack_entry_type::LINE:
236 3836 current_line_no = callstack[i].lineno;
237 3836 current_block = callstack[i].content;
238 3836 break;
239 7556 case callstack_entry_type::BLOCK:
240 7556 current_block = callstack[i].content;
241 7556 break;
242 }
243 }
244 268 }
245
246 2 static string get_full_callstack()
247 {
248 2 autoarray<printable_callstack_entry> printable_stack;
249
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 get_full_printable_callstack(&printable_stack, 12, true);
250
251 2 string e;
252
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (printable_stack.count > 0)
253 {
254
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 e += "\nFull call stack:";
255
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (int i = printable_stack.count-1; i >= 0; --i)
256 {
257
3/10
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
4 e += format_stack_line(printable_stack[i], i);
258 }
259 }
260 4 return e;
261 2 }
262
263 // RPG Hacker: This function essetially replicates classic Asar behavior
264 // of only printing a single macro call below the current level.
265 264 static string get_simple_callstack()
266 {
267 int i;
268 264 const char* current_call = nullptr;
269
2/2
✓ Branch 0 taken 15066 times.
✓ Branch 1 taken 222 times.
15288 for (i = callstack.count-1; i >= 0 ; --i)
270 {
271
3/3
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 9677 times.
✓ Branch 2 taken 5368 times.
15066 if (callstack[i].type == callstack_entry_type::MACRO_CALL)
272 {
273 42 current_call = callstack[i].content;
274 42 break;
275 }
276 }
277
278 264 const char* current_file = nullptr;
279 264 int current_line_no = -1;
280
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 222 times.
264 if (current_call != nullptr)
281 {
282 42 bool stop = false;
283
1/2
✓ Branch 0 taken 168 times.
✗ Branch 1 not taken.
168 for (int j = i-1; j >= 0 ; --j)
284 {
285
5/6
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 63 times.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
168 switch (callstack[j].type)
286 {
287 42 case callstack_entry_type::FILE:
288
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (current_file != nullptr)
289 {
290 stop = true;
291 break;
292 }
293 42 current_file = callstack[j].content;
294 42 break;
295 case callstack_entry_type::MACRO_CALL:
296 stop = true;
297 break;
298 42 case callstack_entry_type::LINE:
299
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 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 42 times.
✓ Branch 1 taken 126 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
168 if (current_file != nullptr && current_line_no != -1) stop = true;
306
307
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 126 times.
168 if (stop) break;
308 }
309 }
310
311 264 string e;
312
3/4
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 222 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
264 if (current_call != nullptr && current_file != nullptr)
313 {
314
6/15
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 42 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 21 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 21 times.
✗ Branch 14 not taken.
84 e += STR "\n called from: " + generate_filename_and_line(get_pretty_filename(current_file), current_line_no)
315
7/13
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 42 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 21 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 21 times.
✗ Branch 12 not taken.
105 + ": [%" + current_call + "]";
316 }
317 264 return e;
318 }
319
320 266 string get_callstack()
321 {
322
4/4
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 136 times.
✓ Branch 2 taken 134 times.
✓ Branch 3 taken 2 times.
266 if (simple_callstacks)
323 264 return get_simple_callstack();
324 else
325 2 return get_full_callstack();
326 }
327
328 36 asar_error_id vfile_error_to_error_id(virtual_file_error vfile_error)
329 {
330
2/5
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
36 switch (vfile_error)
331 {
332 12 case vfe_doesnt_exist:
333 12 return error_id_file_not_found;
334 case vfe_access_denied:
335 return error_id_failed_to_open_file_access_denied;
336 24 case vfe_not_regular_file:
337 24 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 36 virtual_file_error asar_get_last_io_error()
348 {
349
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 if (filesystem != nullptr)
350 {
351 36 return filesystem->get_last_error();
352 }
353
354 return vfe_unknown;
355 }
356
357 657 int getlenforlabel(int labelpos, int label_fs_id, bool exists)
358 {
359 657 unsigned int bank = labelpos>>16;
360 657 unsigned int word = labelpos&0xFFFF;
361 657 bool lblfreespace = label_fs_id > 0;
362 unsigned int relaxed_bank;
363
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 633 times.
657 if(optimizeforbank >= 0) {
364 24 relaxed_bank = optimizeforbank;
365 } else {
366
2/2
✓ Branch 0 taken 505 times.
✓ Branch 1 taken 128 times.
633 if(freespaceid == 0) {
367 505 relaxed_bank = snespos >> 16;
368 } else {
369 128 int target_bank = freespaces[freespaceid].bank;
370
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 44 times.
128 if(target_bank == -2) relaxed_bank = 0;
371
1/2
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
44 else if(target_bank == -1) relaxed_bank = 0x40;
372 else relaxed_bank = target_bank;
373 }
374 }
375
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 657 times.
657 if (!exists)
376 {
377 return 2;
378 }
379
6/8
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 645 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
657 else if((optimize_dp == optimize_dp_flag::RAM) && bank == 0x7E && (word-dp_base < 0x100) && !lblfreespace)
380 {
381 6 return 1;
382 }
383
8/10
✓ Branch 0 taken 437 times.
✓ Branch 1 taken 214 times.
✓ Branch 2 taken 437 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 437 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 91 times.
✓ Branch 7 taken 346 times.
✓ Branch 8 taken 23 times.
✓ Branch 9 taken 68 times.
651 else if(optimize_dp == optimize_dp_flag::ALWAYS && (bank == 0x7E || !(bank & 0x40)) && (word-dp_base < 0x100) && !lblfreespace)
384 {
385 23 return 1;
386 }
387 628 else if (
388 // if we should optimize ram accesses...
389
4/4
✓ Branch 0 taken 592 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 484 times.
✓ Branch 3 taken 108 times.
628 (optimize_address == optimize_address_flag::RAM || optimize_address == optimize_address_flag::MIRRORS)
390 // and we're in a bank with ram mirrors... (optimizeforbank=0x7E is checked later)
391
2/2
✓ Branch 0 taken 488 times.
✓ Branch 1 taken 32 times.
520 && !(relaxed_bank & 0x40)
392 // and the label is in low RAM
393
4/6
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 470 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
488 && bank == 0x7E && word < 0x2000 && !lblfreespace)
394 {
395 18 return 2;
396 }
397 610 else if (
398 // if we should optimize mirrors...
399
2/2
✓ Branch 0 taken 478 times.
✓ Branch 1 taken 132 times.
610 optimize_address == optimize_address_flag::MIRRORS
400 // we're in a bank with ram mirrors...
401
2/2
✓ Branch 0 taken 452 times.
✓ Branch 1 taken 26 times.
478 && !(relaxed_bank & 0x40)
402 // and the label is in a mirrored section
403
5/6
✓ Branch 0 taken 452 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90 times.
✓ Branch 3 taken 362 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 66 times.
452 && !(bank & 0x40) && word < 0x8000 && !lblfreespace)
404 {
405 24 return 2;
406 }
407
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 562 times.
586 else if (optimizeforbank>=0)
408 {
409 // if optimizing for a specific bank:
410 // if the label is in freespace, never optimize
411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (lblfreespace) return 3;
412
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 else if (bank==(unsigned int)optimizeforbank) return 2;
413 12 else return 3;
414 }
415
4/4
✓ Branch 0 taken 408 times.
✓ Branch 1 taken 154 times.
✓ Branch 2 taken 54 times.
✓ Branch 3 taken 354 times.
562 else if (lblfreespace || freespaceid > 0)
416 {
417 // optimize only if the label is in the same freespace
418 // TODO: check whether they're pinned to the same bank
419
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 32 times.
208 if (label_fs_id != freespaceid) return 3;
420 32 else return 2;
421 }
422
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 324 times.
354 else if ((int)bank != snespos >> 16){ return 3; }
423 324 else { return 2;}
424 }
425 645 int getlenforlabel(snes_label thislabel, bool exists) {
426 645 return getlenforlabel(thislabel.pos, thislabel.freespace_id, exists);
427 }
428
429
430 315 bool is_hex_constant(const char* str){
431
3/3
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 156 times.
✓ Branch 2 taken 51 times.
315 if (*str=='$')
432 {
433 216 str++;
434
3/3
✓ Branch 0 taken 300 times.
✓ Branch 1 taken 408 times.
✓ Branch 2 taken 108 times.
816 while(is_xdigit(*str)) {
435 600 str++;
436 }
437
2/3
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
216 if(*str=='\0'){
438 216 return true;
439 }
440 }
441 99 return false;
442 }
443
444 struct strcompare {
445 bool operator() (const char * lhs, const char * rhs) const
446 {
447 return strcmp(lhs, rhs)<0;
448 }
449 };
450
451 struct stricompare {
452 bool operator() (const char * lhs, const char * rhs) const
453 {
454 return stricmp(lhs, rhs)<0;
455 }
456 };
457
458 struct sourcefile {
459 char *data;
460 char** contents;
461 int numlines;
462 };
463
464 static assocarr<sourcefile> filecontents;
465 assocarr<string> defines;
466 // needs to be separate because defines is reset between parsing arguments and patching
467 assocarr<string> clidefines;
468 assocarr<string> builtindefines;
469
470 202 bool validatedefinename(const char * name)
471 {
472
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
✓ Branch 2 taken 106 times.
202 if (!name[0]) return false;
473
4/4
✓ Branch 0 taken 429 times.
✓ Branch 1 taken 96 times.
✓ Branch 2 taken 489 times.
✓ Branch 3 taken 106 times.
1120 for (int i = 0;name[i];i++)
474 {
475
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 429 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 489 times.
918 if (!is_ualnum(name[i])) return false;
476 }
477
478 202 return true;
479 }
480
481 59786 void resolvedefines(string& out, const char * start)
482 {
483
3/3
✓ Branch 0 taken 30245 times.
✓ Branch 1 taken 29540 times.
✓ Branch 2 taken 1 times.
59786 recurseblock rec;
484 59784 const char * here=start;
485
4/4
✓ Branch 0 taken 25037 times.
✓ Branch 1 taken 34747 times.
✓ Branch 2 taken 24280 times.
✓ Branch 3 taken 5259 times.
59784 if (!strchr(here, '!'))
486 {
487
2/3
✓ Branch 0 taken 25037 times.
✓ Branch 1 taken 24280 times.
✗ Branch 2 not taken.
49317 out += here;
488 49317 return;
489 }
490
3/3
✓ Branch 0 taken 35730 times.
✓ Branch 1 taken 41403 times.
✓ Branch 2 taken 5243 times.
82376 while (*here)
491 {
492
6/6
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 35730 times.
✓ Branch 2 taken 36189 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 21 times.
71940 if (here[0] == '\\' && here[1] == '\\')
493 {
494 // allow using \\ as escape sequence
495
1/5
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 if (in_macro_def > 0) out += "\\";
496
2/3
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 out += "\\";
497 6 here += 2;
498 }
499
4/6
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 35727 times.
✓ Branch 2 taken 36207 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
71934 else if (here[0] == '\\' && here[1] == '!')
500 {
501 // allow using \! to escape !
502
4/5
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
42 if (in_macro_def > 0) out += "\\";
503
2/3
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
42 out+="!";
504 42 here += 2;
505 }
506
3/3
✓ Branch 0 taken 5589 times.
✓ Branch 1 taken 35769 times.
✓ Branch 2 taken 30534 times.
71892 else if (*here=='!')
507 {
508
14/14
✓ Branch 0 taken 5472 times.
✓ Branch 1 taken 5769 times.
✓ Branch 2 taken 1680 times.
✓ Branch 3 taken 2754 times.
✓ Branch 4 taken 2328 times.
✓ Branch 5 taken 390 times.
✓ Branch 6 taken 60 times.
✓ Branch 7 taken 2526 times.
✓ Branch 8 taken 429 times.
✓ Branch 9 taken 54 times.
✓ Branch 10 taken 60 times.
✓ Branch 11 taken 1236 times.
✓ Branch 12 taken 6 times.
✓ Branch 13 taken 54 times.
11241 bool first=(here==start || (here>=start+4 && here[-1]==' ' && here[-2]==':' && here[-3]==' '));//check if it's the start of a block
509 11241 string defname;
510 11241 here++;
511
512 11241 int depth = 0;
513
3/3
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 5646 times.
✓ Branch 2 taken 5652 times.
11355 for (const char* depth_str = here; *depth_str=='^'; depth_str++)
514 {
515 114 depth++;
516 }
517 11241 here += depth;
518
519
2/2
✓ Branch 0 taken 1323 times.
✓ Branch 1 taken 9918 times.
11241 if (depth != in_macro_def)
520 {
521
2/3
✓ Branch 0 taken 660 times.
✓ Branch 1 taken 663 times.
✗ Branch 2 not taken.
1323 out += '!';
522
5/5
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 693 times.
✓ Branch 4 taken 663 times.
1389 for (int i=0; i < depth; ++i) out += '^';
523
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 1305 times.
1323 if (depth > in_macro_def) asar_throw_error(0, error_type_line, error_id_invalid_depth_resolve, "define", "define", depth, in_macro_def);
524 1305 continue;
525 1305 }
526
527
3/3
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 4929 times.
✓ Branch 2 taken 4935 times.
9918 if (*here=='{')
528 {
529 108 here++;
530 108 string unprocessedname;
531 108 int braces=1;
532 while (true)
533 {
534
3/3
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 576 times.
✓ Branch 2 taken 540 times.
1152 if (*here=='{') braces++;
535
3/3
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 576 times.
✓ Branch 2 taken 486 times.
1152 if (*here=='}') braces--;
536
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 576 times.
✓ Branch 2 taken 576 times.
1152 if (!*here) asar_throw_error(0, error_type_line, error_id_mismatched_braces);
537
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 1044 times.
1152 if (!braces) break;
538
2/4
✓ Branch 0 taken 522 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 522 times.
✗ Branch 3 not taken.
1044 unprocessedname+=*here++;
539 }
540 108 here++;
541
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 resolvedefines(defname, unprocessedname);
542
3/4
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
108 if (!validatedefinename(defname)) asar_throw_error(0, error_type_line, error_id_invalid_define_name);
543 108 }
544 else
545 {
546
5/7
✓ Branch 0 taken 24771 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 49786 times.
✓ Branch 3 taken 4875 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 25015 times.
✓ Branch 6 taken 4935 times.
59596 while (is_ualnum(*here)) defname+=*here++;
547 }
548
549
2/2
✓ Branch 0 taken 4968 times.
✓ Branch 1 taken 4950 times.
9918 if (first)
550 {
551 enum {
552 null,
553 append,
554 expand,
555 domath,
556 setifnotset,
557 } mode;
558 if(0);
559
2/2
✓ Branch 0 taken 522 times.
✓ Branch 1 taken 4749 times.
5271 else if (stribegin(here, " = ")) { here+=3; mode=null; }
560
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 4647 times.
4749 else if (stribegin(here, " += ")) { here+=4; mode=append; }
561
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 4590 times.
4647 else if (stribegin(here, " := ")) { here+=4; mode=expand; }
562
2/2
✓ Branch 0 taken 1926 times.
✓ Branch 1 taken 2664 times.
4590 else if (stribegin(here, " #= ")) { here+=4; mode=domath; }
563
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2664 times.
2664 else if (stribegin(here, " ?= ")) { here+=4; mode=setifnotset; }
564 2664 else goto notdefineset;
565 2607 string val;
566
3/3
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 1299 times.
✓ Branch 2 taken 1215 times.
2607 if (*here=='"')
567 {
568 189 here++;
569 while (true)
570 {
571
3/3
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 513 times.
✓ Branch 2 taken 414 times.
1023 if (*here=='"')
572 {
573
5/6
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 93 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 96 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
195 if (!here[1] || here[1]==' ') break;
574
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 else if (here[1]=='"') here++;
575 else asar_throw_error(0, error_type_line, error_id_broken_define_declaration);
576 }
577
2/4
✓ Branch 0 taken 417 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 417 times.
✗ Branch 3 not taken.
834 val+=*here++;
578 }
579 189 here++;
580 }
581 else
582 {
583
7/9
✓ Branch 0 taken 8286 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16635 times.
✓ Branch 3 taken 1203 times.
✓ Branch 4 taken 8286 times.
✓ Branch 5 taken 8349 times.
✓ Branch 6 taken 1215 times.
✓ Branch 7 taken 8349 times.
✗ Branch 8 not taken.
19053 while (*here && *here!=' ') val+=*here++;
584 }
585 //if (strqchr(val.data(), ';')) *strqchr(val.data(), ';')=0;
586
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 1296 times.
✓ Branch 2 taken 1311 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1296 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1311 times.
2607 if (*here && !stribegin(here, " : ")) asar_throw_error(0, error_type_line, error_id_broken_define_declaration);
587 // RPG Hacker: Is it really a good idea to normalize
588 // the content of defines? That kinda violates their
589 // functionality as a string replacement mechanism.
590 //val.qnormalize();
591
592 // RPG Hacker: throw an error if we're trying to overwrite built-in defines.
593
3/4
✓ Branch 0 taken 2607 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 2601 times.
2607 if (builtindefines.exists(defname))
594 {
595 6 asar_throw_error(0, error_type_line, error_id_overriding_builtin_define, defname.data());
596 }
597
598
4/6
✓ Branch 0 taken 516 times.
✓ Branch 1 taken 102 times.
✓ Branch 2 taken 57 times.
✓ Branch 3 taken 1926 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
2601 switch (mode)
599 {
600 516 case null:
601 {
602
3/5
✓ Branch 0 taken 516 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 252 times.
✓ Branch 3 taken 264 times.
✗ Branch 4 not taken.
516 defines.create(defname) = val;
603 516 break;
604 }
605 102 case append:
606 {
607
2/4
✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 102 times.
102 if (!defines.exists(defname)) asar_throw_error(0, error_type_line, error_id_define_not_found, defname.data());
608
4/7
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 51 times.
✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 51 times.
✗ Branch 6 not taken.
102 string oldval = defines.find(defname);
609
2/3
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
102 val=oldval+val;
610
3/5
✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 51 times.
✓ Branch 3 taken 51 times.
✗ Branch 4 not taken.
102 defines.create(defname) = val;
611 102 break;
612 102 }
613 57 case expand:
614 {
615 57 string newval;
616
1/2
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
57 resolvedefines(newval, val);
617
3/5
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 30 times.
✗ Branch 4 not taken.
57 defines.create(defname) = newval;
618 57 break;
619 57 }
620 1926 case domath:
621 {
622 1926 string newval;
623
1/2
✓ Branch 0 taken 1926 times.
✗ Branch 1 not taken.
1926 resolvedefines(newval, val);
624
7/10
✓ Branch 0 taken 963 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1923 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 960 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 960 times.
✓ Branch 7 taken 3 times.
✓ Branch 8 taken 960 times.
✗ Branch 9 not taken.
1935 double num= parse_math_expr(newval)->evaluate_static().get_double();
625
4/7
✓ Branch 0 taken 960 times.
✓ Branch 1 taken 960 times.
✓ Branch 2 taken 960 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 960 times.
✗ Branch 6 not taken.
1920 defines.create(defname) = ftostr(num);
626 1920 break;
627 1926 }
628 case setifnotset:
629 {
630 if (!defines.exists(defname)) defines.create(defname) = val;
631 break;
632 }
633 }
634 2607 }
635 else
636 {
637 5982 notdefineset:
638
4/5
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 7242 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 39 times.
✗ Branch 4 not taken.
7311 if (!defname) out+="!";
639 else
640 {
641
3/4
✓ Branch 0 taken 7242 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 7241 times.
7242 if (!defines.exists(defname)) asar_throw_error(0, error_type_line, error_id_define_not_found, defname.data());
642 else {
643
4/7
✓ Branch 0 taken 3603 times.
✓ Branch 1 taken 3638 times.
✓ Branch 2 taken 3603 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3638 times.
✗ Branch 6 not taken.
7241 string thisone = defines.find(defname);
644
1/2
✓ Branch 0 taken 7241 times.
✗ Branch 1 not taken.
7241 resolvedefines(out, thisone);
645 7241 }
646 }
647 }
648
2/2
✓ Branch 0 taken 9905 times.
✓ Branch 1 taken 1305 times.
11241 }
649
2/4
✓ Branch 0 taken 30117 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30534 times.
✗ Branch 3 not taken.
60651 else out+=*here++;
650 }
651
7/12
✓ Branch 0 taken 5193 times.
✓ Branch 1 taken 5243 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 5193 times.
✓ Branch 4 taken 5243 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
10436 if (!confirmquotes(out)) { asar_throw_error(0, error_type_null, error_id_mismatched_quotes); out = ""; }
652
2/2
✓ Branch 0 taken 10436 times.
✓ Branch 1 taken 49317 times.
59784 }
653
654 bool moreonline;
655 bool asarverallowed = false;
656
657 48858 void assembleline(const char * fname, int linenum, const char * line, int& single_line_for_tracker)
658 {
659
2/3
✓ Branch 0 taken 24818 times.
✓ Branch 1 taken 24040 times.
✗ Branch 2 not taken.
48858 recurseblock rec;
660
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24040 times.
48858 bool moreonlinetmp=moreonline;
661 // randomdude999: redundant, assemblefile already converted the path to absolute
662 //string absolutepath = filesystem->create_absolute_path("", fname);
663
2/3
✓ Branch 0 taken 24818 times.
✓ Branch 1 taken 24040 times.
✗ Branch 2 not taken.
48858 string absolutepath = fname;
664 48858 single_line_for_tracker = 1;
665 try
666 {
667
2/3
✓ Branch 0 taken 24818 times.
✓ Branch 1 taken 24040 times.
✗ Branch 2 not taken.
48858 string out=line;
668
2/3
✓ Branch 0 taken 24818 times.
✓ Branch 1 taken 24040 times.
✗ Branch 2 not taken.
48858 autoptr<char**> blocks=qsplitstr(out.temp_raw(), " : ");
669 48858 moreonline=true;
670
4/4
✓ Branch 0 taken 25718 times.
✓ Branch 1 taken 70336 times.
✓ Branch 2 taken 25009 times.
✓ Branch 3 taken 22812 times.
96054 for (int block=0;moreonline;block++)
671 {
672 50727 moreonline=(blocks[block+1] != nullptr);
673 try
674 {
675 // it's possible that our input looks something like:
676 // nop : : nop
677 // nop : : : : : nop
678 // also, it's possible that there were empty blocks at the start or end of the line:
679 // : nop :
680 // after qsplit, we still need to deal with possibly a single ": " from a preceding empty block,
681 // and if it's the last block, possibly a following " :".
682
2/4
✓ Branch 0 taken 25718 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25009 times.
✗ Branch 3 not taken.
50727 string stripped_block = strip_whitespace(blocks[block]);
683 50727 int i = 0;
684 // if the block starts with ": "
685
10/11
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 25691 times.
✓ Branch 2 taken 39 times.
✓ Branch 3 taken 24997 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 25706 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
✓ Branch 8 taken 15 times.
✓ Branch 9 taken 12 times.
✓ Branch 10 taken 24997 times.
50727 if(stripped_block[i] == ':' && stripped_block[i+1] == ' ') {
686 24 i++;
687
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 12 times.
48 while(stripped_block[i] == ' ') i++;
688 }
689 // if the block is a single :, skip that too.
690
9/11
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 25703 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 24994 times.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 25703 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 15 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 15 times.
✓ Branch 10 taken 24994 times.
50727 if(stripped_block[i] == ':' && stripped_block[i+1] == 0) i++;
691
692 // last block - strip trailing " :" if present.
693
15/17
✓ Branch 0 taken 24818 times.
✓ Branch 1 taken 25909 times.
✓ Branch 2 taken 40490 times.
✓ Branch 3 taken 9337 times.
✓ Branch 4 taken 1554 times.
✓ Branch 5 taken 30496 times.
✓ Branch 6 taken 8446 times.
✓ Branch 7 taken 1548 times.
✓ Branch 8 taken 6 times.
✓ Branch 9 taken 27302 times.
✓ Branch 10 taken 14010 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 6 times.
✓ Branch 14 taken 1584 times.
✓ Branch 15 taken 6 times.
✓ Branch 16 taken 25003 times.
50727 if(!moreonline && stripped_block.length() >= 2 && stripped_block[stripped_block.length()-2] == ' ' && stripped_block[stripped_block.length()-1] == ':') {
694
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 stripped_block.truncate(stripped_block.length()-2);
695 }
696
697
2/4
✓ Branch 0 taken 25718 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25009 times.
✗ Branch 3 not taken.
50727 callstack_push cs_push(callstack_entry_type::BLOCK, stripped_block.data() + i);
698
699
3/3
✓ Branch 0 taken 23247 times.
✓ Branch 1 taken 26078 times.
✓ Branch 2 taken 1402 times.
50727 assembleblock(stripped_block.data() + i, single_line_for_tracker);
700
2/2
✓ Branch 0 taken 46850 times.
✓ Branch 1 taken 4 times.
46854 checkbankcross();
701 54604 }
702
2/2
✓ Branch 0 taken 3531 times.
✓ Branch 1 taken 346 times.
3877 catch (errblock&) {}
703
4/4
✓ Branch 0 taken 15137 times.
✓ Branch 1 taken 8278 times.
✓ Branch 2 taken 15437 times.
✓ Branch 3 taken 8344 times.
47196 if (blocks[block][0]!='\0') asarverallowed=false;
704
3/3
✓ Branch 0 taken 22350 times.
✓ Branch 1 taken 23712 times.
✓ Branch 2 taken 1134 times.
47196 if(single_line_for_tracker == 1) single_line_for_tracker = 0;
705 }
706 52389 }
707
1/2
✓ Branch 0 taken 3531 times.
✗ Branch 1 not taken.
3531 catch (errline&) {}
708 45327 moreonline=moreonlinetmp;
709 75201 }
710
711 int incsrcdepth=0;
712
713 // Returns true if a file is protected via
714 // an "includeonce".
715 4546 bool file_included_once(const char* file)
716 {
717
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 4504 times.
4744 for (int i = 0; i < includeonce.count; ++i)
718 {
719
4/4
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 99 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 99 times.
240 if (includeonce[i] == file)
720 {
721 42 return true;
722 }
723 }
724
725 4504 return false;
726 }
727
728 autoarray<string> macro_defs;
729 int in_macro_def=0;
730
731 4516 void assemblefile(const char * filename)
732 {
733 4516 incsrcdepth++;
734
4/6
✓ Branch 0 taken 2737 times.
✓ Branch 1 taken 1779 times.
✓ Branch 2 taken 2737 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1779 times.
✗ Branch 5 not taken.
4516 string absolutepath = filesystem->create_absolute_path(get_current_file_name(), filename);
735
736
3/4
✓ Branch 0 taken 4516 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 4474 times.
4516 if (file_included_once(absolutepath))
737 {
738 42 return;
739 }
740
741
2/3
✓ Branch 0 taken 2716 times.
✓ Branch 1 taken 1758 times.
✗ Branch 2 not taken.
4474 callstack_push cs_push(callstack_entry_type::FILE, absolutepath);
742
743 1758 sourcefile file;
744 4474 file.contents = nullptr;
745 4474 file.numlines = 0;
746 4474 int startif=numif;
747
3/4
✓ Branch 0 taken 4474 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 331 times.
✓ Branch 3 taken 4143 times.
4474 if (!filecontents.exists(absolutepath))
748 {
749
2/2
✓ Branch 0 taken 329 times.
✓ Branch 1 taken 2 times.
331 char * temp = readfile(absolutepath, "");
750
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 323 times.
329 if (!temp)
751 {
752
5/12
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
6 asar_throw_error(0, error_type_null, vfile_error_to_error_id(asar_get_last_io_error()), filename);
753
754 6 return;
755 }
756
1/2
✓ Branch 0 taken 323 times.
✗ Branch 1 not taken.
323 sourcefile& newfile = filecontents.create(absolutepath);
757
1/2
✓ Branch 0 taken 323 times.
✗ Branch 1 not taken.
323 newfile.contents =split(temp, '\n');
758 323 newfile.data = temp;
759
4/4
✓ Branch 0 taken 5847 times.
✓ Branch 1 taken 142 times.
✓ Branch 2 taken 5948 times.
✓ Branch 3 taken 181 times.
12118 for (int i=0;newfile.contents[i];i++)
760 {
761 11795 newfile.numlines++;
762 11795 char * line = newfile.contents[i];
763 11795 int i_temp = i;
764 char * comment;
765
2/2
✓ Branch 0 taken 3132 times.
✓ Branch 1 taken 11793 times.
14925 while((comment = strqchr(line, ';'))) {
766
5/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1560 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 1560 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
3132 if(comment[1] == '[' && comment[2] == '[') {
767 // block comment - find where it ends
768 12 char* theline = comment + 3;
769
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
12 char* comment_end = strstr(theline, "]]");
770
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 10 times.
30 while(comment_end == nullptr) {
771 20 i_temp++;
772 20 char* new_line = newfile.contents[i_temp];
773
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18 times.
20 if(new_line == nullptr) {
774
2/3
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 callstack_push cs_push(callstack_entry_type::LINE, line, i);
775
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 asar_throw_error(0, error_type_null, error_id_unclosed_block_comment);
776 // make sure this line is still parsed correctly
777 2 *comment = 0;
778 // but don't go looking at any other lines
779 2 goto break_outer;
780 2 }
781
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
18 comment_end = strstr(new_line, "]]");
782 // this line is itself part of the comment, so ignore it
783 //new_line[0] = 0;
784 // except not like that^, because that will break the
785 // memmove below
786 static char junk[]="";
787 // using a static here should be fine, since if the line
788 // doesn't contain ',' or '\' we won't go mutating it
789 18 newfile.contents[i_temp] = junk;
790 }
791 // comment_end+2 is a valid pointer, since comment_end is
792 // guaranteed to start with ]]
793 10 comment_end += 2;
794 // stitch together the part of the line before the comment,
795 // and the part of the line after it
796
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
10 memmove(comment, comment_end, strlen(comment_end) + 1);
797 // and then recheck for ; in the line again...
798 10 } else {
799 3120 *comment = 0;
800 }
801 }
802 11794 break_outer:
803
3/4
✓ Branch 0 taken 11795 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 11791 times.
11795 if (!confirmquotes(line)) {
804
2/3
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 callstack_push cs_push(callstack_entry_type::LINE, line, i);
805
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 asar_throw_error(0, error_type_null, error_id_mismatched_quotes);
806 4 line[0] = '\0';
807 4 }
808 11795 newfile.contents[i] = strip_whitespace(line);
809 }
810
4/4
✓ Branch 0 taken 5847 times.
✓ Branch 1 taken 142 times.
✓ Branch 2 taken 5948 times.
✓ Branch 3 taken 181 times.
12118 for(int i=0;newfile.contents[i];i++)
811 {
812 11795 char* line = newfile.contents[i];
813
3/3
✓ Branch 0 taken 2230 times.
✓ Branch 1 taken 5863 times.
✓ Branch 2 taken 3702 times.
11795 if(!*line) continue;
814
6/8
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 7324 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 3702 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
7329 for (int j=1;line[strlen(line) - 1] == ',' && newfile.contents[i+j];j++)
815 {
816 // not using strcat because the source and dest overlap here
817 10 char* otherline = newfile.contents[i+j];
818
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
10 char* line_end = line + strlen(line);
819
4/4
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 64 times.
✓ Branch 3 taken 5 times.
138 while(*otherline) *line_end++ = *otherline++;
820 10 *line_end = '\0';
821 static char nullstr[]="";
822 10 newfile.contents[i+j]=nullstr;
823 }
824 }
825 323 file = newfile;
826 } else { // filecontents.exists(absolutepath)
827
1/2
✓ Branch 0 taken 4143 times.
✗ Branch 1 not taken.
4143 file = filecontents.find(absolutepath);
828 }
829 4466 asarverallowed=true;
830
5/6
✓ Branch 0 taken 23022 times.
✓ Branch 1 taken 408 times.
✓ Branch 2 taken 45272 times.
✓ Branch 3 taken 525 times.
✓ Branch 4 taken 22250 times.
✗ Branch 5 not taken.
46205 for (int i=0;file.contents[i] && i<file.numlines;i++)
831 {
832 45272 string connectedline;
833
1/2
✓ Branch 0 taken 45272 times.
✗ Branch 1 not taken.
45272 int skiplines = getconnectedlines<char**>(file.contents, i, connectedline);
834
835
2/2
✓ Branch 0 taken 41739 times.
✓ Branch 1 taken 3533 times.
45272 bool was_loop_end = do_line_logic(connectedline, absolutepath, i);
836 41739 i += skiplines;
837
838 // if a loop ended on this line, should it run again?
839
12/12
✓ Branch 0 taken 2268 times.
✓ Branch 1 taken 39471 times.
✓ Branch 2 taken 1134 times.
✓ Branch 3 taken 1134 times.
✓ Branch 4 taken 666 times.
✓ Branch 5 taken 468 times.
✓ Branch 6 taken 666 times.
✓ Branch 7 taken 21186 times.
✓ Branch 8 taken 666 times.
✓ Branch 9 taken 468 times.
✓ Branch 10 taken 666 times.
✓ Branch 11 taken 20355 times.
41739 if (was_loop_end && whilestatus[numif].cond)
840
2/3
✓ Branch 0 taken 666 times.
✓ Branch 1 taken 666 times.
✗ Branch 2 not taken.
1332 i = whilestatus[numif].startline - 1;
841 45272 }
842
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 933 times.
945 while (in_macro_def > 0)
843 {
844
3/5
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
12 asar_throw_error(0, error_type_null, error_id_unclosed_macro, macro_defs[in_macro_def-1].data());
845
5/6
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
12 if (!pass && in_macro_def == 1) endmacro(false);
846 12 in_macro_def--;
847 12 macro_defs.remove(in_macro_def);
848 }
849
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 933 times.
933 if (numif!=startif)
850 {
851 numif=startif;
852 numtrue=startif;
853 asar_throw_error(0, error_type_null, error_id_unclosed_if);
854 }
855 933 incsrcdepth--;
856
4/4
✓ Branch 0 taken 933 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 933 times.
✓ Branch 3 taken 48 times.
8057 }
857
858 // RPG Hacker: At some point, this should probably be merged
859 // into assembleline(), since the two names just cause
860 // confusion otherwise.
861 // return value is "did a loop end on this line"
862 52310 bool do_line_logic(const char* line, const char* filename, int lineno)
863 {
864 52310 int prevnumif = numif;
865 52310 int single_line_for_tracker = 1;
866 try
867 {
868 52310 string current_line;
869
8/8
✓ Branch 0 taken 3276 times.
✓ Branch 1 taken 49034 times.
✓ Branch 2 taken 2790 times.
✓ Branch 3 taken 486 times.
✓ Branch 4 taken 168 times.
✓ Branch 5 taken 2622 times.
✓ Branch 6 taken 49202 times.
✓ Branch 7 taken 3108 times.
52310 if (numif==numtrue || (numtrue+1==numif && stribegin(line, "elseif ")))
870 {
871
2/3
✓ Branch 0 taken 24981 times.
✓ Branch 1 taken 24221 times.
✗ Branch 2 not taken.
49202 callstack_push cs_push(callstack_entry_type::LINE, line, lineno);
872
3/3
✓ Branch 0 taken 24930 times.
✓ Branch 1 taken 24221 times.
✓ Branch 2 taken 51 times.
49202 string tmp=replace_macro_args(line);
873
1/2
✓ Branch 0 taken 49100 times.
✗ Branch 1 not taken.
49100 tmp.qnormalize();
874
2/2
✓ Branch 0 taken 49068 times.
✓ Branch 1 taken 32 times.
49100 resolvedefines(current_line, tmp);
875
2/4
✓ Branch 0 taken 49068 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 49068 times.
49068 if (!confirmquotes(current_line)) asar_throw_error(0, error_type_line, error_id_mismatched_quotes);
876 49234 }
877
1/2
✓ Branch 0 taken 3108 times.
✗ Branch 1 not taken.
3108 else current_line=line;
878
879
2/3
✓ Branch 0 taken 26468 times.
✓ Branch 1 taken 25708 times.
✗ Branch 2 not taken.
52176 callstack_push cs_push(callstack_entry_type::LINE, current_line, lineno);
880
881
6/6
✓ Branch 0 taken 558 times.
✓ Branch 1 taken 51618 times.
✓ Branch 2 taken 522 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 522 times.
✓ Branch 5 taken 51654 times.
52176 if (stribegin(current_line, "macro ") && numif==numtrue)
882 {
883 // RPG Hacker: Slight redundancy here with code that is
884 // also in startmacro(). Could improve this for Asar 2.0.
885
2/4
✓ Branch 0 taken 258 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 264 times.
✗ Branch 3 not taken.
522 string macro_name = current_line.data()+6;
886 522 char * startpar=strqchr(macro_name.data(), '(');
887
1/2
✓ Branch 0 taken 522 times.
✗ Branch 1 not taken.
522 if (startpar) *startpar=0;
888
1/2
✓ Branch 0 taken 522 times.
✗ Branch 1 not taken.
522 macro_defs.append(macro_name);
889
890 // RPG Hacker: I think it would make more logical sense
891 // to have this ++ after the if, but hat breaks compatibility
892 // with at least one test, and it generally leads to more
893 // errors being output after a broken macro declaration.
894 522 in_macro_def++;
895
2/2
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 348 times.
522 if (!pass)
896 {
897
5/5
✓ Branch 0 taken 142 times.
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 69 times.
✓ Branch 3 taken 72 times.
✓ Branch 4 taken 1 times.
174 if (in_macro_def == 1) startmacro(current_line.data()+6);
898
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 else tomacro(current_line);
899 }
900 522 }
901
8/8
✓ Branch 0 taken 26210 times.
✓ Branch 1 taken 25444 times.
✓ Branch 2 taken 546 times.
✓ Branch 3 taken 51108 times.
✓ Branch 4 taken 510 times.
✓ Branch 5 taken 36 times.
✓ Branch 6 taken 510 times.
✓ Branch 7 taken 51144 times.
51654 else if (!stricmp(current_line, "endmacro") && numif==numtrue)
902 {
903
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 510 times.
510 if (in_macro_def == 0) asar_throw_error(0, error_type_line, error_id_misplaced_endmacro);
904 else
905 {
906 510 in_macro_def--;
907 510 macro_defs.remove(in_macro_def);
908
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 340 times.
510 if (!pass)
909 {
910
3/4
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 140 times.
✗ Branch 3 not taken.
170 if (in_macro_def == 0) endmacro(true);
911
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 else tomacro(current_line);
912 }
913 }
914 }
915
2/2
✓ Branch 0 taken 2286 times.
✓ Branch 1 taken 48858 times.
51144 else if (in_macro_def > 0)
916 {
917
3/4
✓ Branch 0 taken 762 times.
✓ Branch 1 taken 1524 times.
✓ Branch 2 taken 762 times.
✗ Branch 3 not taken.
2286 if (!pass) tomacro(current_line);
918 }
919 else
920 {
921
2/2
✓ Branch 0 taken 45327 times.
✓ Branch 1 taken 3531 times.
48858 assembleline(filename, lineno, current_line, single_line_for_tracker);
922 }
923 55843 }
924
2/2
✓ Branch 0 taken 3533 times.
✓ Branch 1 taken 134 times.
3667 catch (errline&) {}
925
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 43257 times.
43317 return (numif != prevnumif || single_line_for_tracker == 3)
926
14/17
✓ Branch 0 taken 43317 times.
✓ Branch 1 taken 5460 times.
✓ Branch 2 taken 2760 times.
✓ Branch 3 taken 2760 times.
✓ Branch 4 taken 1471 times.
✓ Branch 5 taken 1289 times.
✓ Branch 6 taken 1471 times.
✓ Branch 7 taken 2760 times.
✓ Branch 8 taken 1926 times.
✓ Branch 9 taken 2305 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1471 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 1471 times.
✓ Branch 15 taken 455 times.
✓ Branch 16 taken 1016 times.
92094 && (whilestatus[numif].iswhile || whilestatus[numif].is_for);
927 }
928
929
930 4 void parse_std_includes(const char* textfile, autoarray<string>& outarray)
931 {
932 4 char* content = readfilenative(textfile);
933
934
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (content != nullptr)
935 {
936 1 char* pos = content;
937
938
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 times.
5 while (pos[0] != '\0')
939 {
940 4 string stdinclude;
941
942 do
943 {
944
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
✓ Branch 5 taken 3 times.
30 if (pos[0] != '\r' && pos[0] != '\n')
945 {
946
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 stdinclude += pos[0];
947 }
948 30 pos++;
949
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
✓ Branch 5 taken 3 times.
30 } while (pos[0] != '\0' && pos[0] != '\n');
950
951
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 strip_whitespace(stdinclude);
952
953
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (stdinclude != "")
954 {
955
3/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
3 if (!path_is_absolute(stdinclude))
956 {
957
2/7
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 stdinclude = dir(textfile) + stdinclude;
958 }
959
2/7
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
3 outarray.append(normalize_path(stdinclude));
960 }
961 4 }
962
963 1 free(content);
964 }
965 4 }
966
967 282 void parse_std_defines(const char* textfile)
968 {
969
970 // RPG Hacker: add built-in defines.
971 // (They're not really standard defines, but I was lazy and this was
972 // one convenient place for doing it).
973 282 builtindefines.create("assembler") = "asar";
974
6/9
✓ Branch 0 taken 279 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 125 times.
✓ Branch 3 taken 154 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 154 times.
✗ Branch 8 not taken.
282 builtindefines.create("assembler_ver") = dec(get_version_int());
975
5/7
✓ Branch 0 taken 125 times.
✓ Branch 1 taken 157 times.
✓ Branch 2 taken 125 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 125 times.
✓ Branch 5 taken 157 times.
✗ Branch 6 not taken.
282 builtindefines.create("assembler_time") = dec(time(nullptr));
976
977
2/2
✓ Branch 0 taken 278 times.
✓ Branch 1 taken 4 times.
282 if(textfile == nullptr) return;
978
979 4 char* content = readfilenative(textfile);
980
981
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (content != nullptr)
982 {
983 1 char* pos = content;
984
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 times.
6 while (*pos != 0) {
985 5 string define_name;
986 5 string define_val;
987
988
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 3 times.
29 while (*pos != '=' && *pos != '\n') {
989
1/3
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
24 if(*pos == '\r') { pos++; continue; }
990
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 define_name += *pos;
991 24 pos++;
992 }
993
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 3 times.
5 if (*pos != 0 && *pos != '\r' && *pos != '\n') pos++; // skip =
994
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 5 times.
18 while (*pos != 0 && *pos != '\n') {
995
1/3
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
13 if(*pos == '\r') { pos++; continue; }
996
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 define_val += *pos;
997 13 pos++;
998 }
999
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 if (*pos != 0)
1000 5 pos++; // skip \n
1001 // clean define_name
1002
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 strip_whitespace(define_name);
1003
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 define_name.strip_prefix('!'); // remove leading ! if present
1004
1005
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 if (define_name == "")
1006 {
1007
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (define_val == "")
1008 {
1009 1 continue;
1010 }
1011
1012 asar_throw_error(pass, error_type_null, error_id_stddefines_no_identifier);
1013 }
1014
1015
2/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
4 if (!validatedefinename(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_invalid, "stddefines.txt", define_name.data());
1016
1017 // clean define_val
1018 4 const char* defval = define_val.data();
1019 4 string cleaned_defval;
1020
1021
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 if (*defval == 0) {
1022 // no value
1023
2/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
2 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
1024
2/5
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
2 clidefines.create(define_name) = "";
1025 2 continue;
1026 }
1027
1028
3/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
4 while (*defval == ' ' || *defval == '\t') defval++; // skip whitespace in beginning
1029
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
2 if (*defval == '"') {
1030 1 defval++; // skip opening quote
1031
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
6 while (*defval != '"' && *defval != 0)
1032
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 cleaned_defval += *defval++;
1033
1034
1/3
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (*defval == 0) {
1035 asar_throw_error(pass, error_type_null, error_id_mismatched_quotes);
1036 }
1037 1 defval++; // skip closing quote
1038
2/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
1 while (*defval == ' ' || *defval == '\t') defval++; // skip whitespace
1039
1/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1 if (*defval != 0 && *defval != '\n')
1040 asar_throw_error(pass, error_type_null, error_id_stddefine_after_closing_quote);
1041
1042
2/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
1043
2/5
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 clidefines.create(define_name) = cleaned_defval;
1044 1 continue;
1045 }
1046 else
1047 {
1048 // slightly hacky way to remove trailing whitespace
1049
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 const char* defval_end = strchr(defval, '\n'); // slightly hacky way to get end of string or newline
1050
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!defval_end) defval_end = strchr(defval, 0);
1051 1 defval_end--;
1052
3/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
4 while (*defval_end == ' ' || *defval_end == '\t') defval_end--;
1053
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 cleaned_defval = string(defval, (int)(defval_end - defval + 1));
1054
1055
2/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
1056
2/5
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 clidefines.create(define_name) = cleaned_defval;
1057 1 continue;
1058 1 }
1059
1060 5 }
1061 1 free(content);
1062 }
1063 }
1064
1065 bool checksum_fix_enabled = true;
1066 bool force_checksum_fix = false;
1067
1068 #define cfree(x) free((void*)x)
1069 140 static void clearmacro(const string & key, macrodata* & macro)
1070 {
1071 (void)key;
1072 140 freemacro(macro);
1073 140 }
1074
1075 323 static void clearfile(const string & key, sourcefile& filecontent)
1076 {
1077 (void)key;
1078 323 cfree(filecontent.data);
1079 323 cfree(filecontent.contents);
1080 323 }
1081 #undef cfree
1082
1083 849 static void adddefine(const string & key, string & value)
1084 {
1085
2/3
✓ Branch 0 taken 375 times.
✓ Branch 1 taken 474 times.
✗ Branch 2 not taken.
849 if (!defines.exists(key)) defines.create(key) = value;
1086 849 }
1087
1088 2 string create_symbols_file(string format, uint32_t romCrc){
1089 2 string symbolfile;
1090
1091 2 std::vector<std::pair<unsigned int, const char*>> all_labels;
1092
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
6 labels.each([&all_labels](const string& key, snes_label& label) {
1093
2/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
4 all_labels.push_back(std::make_pair(label.pos, key.data()));
1094 4 });
1095
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 std::sort(all_labels.begin(), all_labels.end(),
1096 2 [](auto& l, auto& r) {
1097
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if (l.first == r.first)
1098 return strcmp(l.second, r.second) < 0;
1099 2 return l.first < r.first;
1100 });
1101
1102
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 format = lower(format);
1103
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(format == "wla")
1104 {
1105
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 symbolfile = "; wla symbolic information file\n";
1106
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 symbolfile += "; generated by asar\n";
1107
1108
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 symbolfile += "\n[labels]\n";
1109
2/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
6 for (auto& p : all_labels) {
1110 4 char buffer[10];
1111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 std::snprintf(buffer, sizeof(buffer), "%02X:%04X ", (p.first >> 16) & 0xFF, p.first & 0xFFFF);
1112
1113
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 symbolfile += buffer;
1114
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 symbolfile += p.second;
1115
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 symbolfile += "\n";
1116 }
1117
1118
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 symbolfile += "\n[source files]\n";
1119 2 const autoarray<AddressToLineMapping::FileInfo>& addrToLineFileList = addressToLineMapping.getFileList();
1120
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 for (int i = 0; i < addrToLineFileList.count; ++i)
1121 {
1122 2 char addrToFileListStr[256];
1123 2 snprintf(addrToFileListStr, 256, "%.4x %.8x %s\n",
1124 i,
1125
2/5
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
2 addrToLineFileList[i].fileCrc,
1126
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 addrToLineFileList[i].filename.data()
1127 );
1128
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 symbolfile += addrToFileListStr;
1129 }
1130
1131
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 symbolfile += "\n[rom checksum]\n";
1132 {
1133 2 char romCrcStr[32];
1134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 snprintf(romCrcStr, 32, "%.8x\n",
1135 romCrc
1136 );
1137
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 symbolfile += romCrcStr;
1138 }
1139
1140
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 symbolfile += "\n[addr-to-line mapping]\n";
1141 2 const autoarray<AddressToLineMapping::AddrToLineInfo>& addrToLineInfo = addressToLineMapping.getAddrToLineInfo();
1142
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 2 times.
8 for (int i = 0; i < addrToLineInfo.count; ++i)
1143 {
1144 6 char addrToLineStr[32];
1145 snprintf(addrToLineStr, 32, "%.2x:%.4x %.4x:%.8x\n",
1146
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 (addrToLineInfo[i].addr & 0xFF0000) >> 16,
1147
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 addrToLineInfo[i].addr & 0xFFFF,
1148
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 addrToLineInfo[i].fileIdx & 0xFFFF,
1149
1/5
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 addrToLineInfo[i].line & 0xFFFFFFFF
1150 );
1151
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 symbolfile += addrToLineStr;
1152 }
1153
1154 }
1155 else if (format == "nocash")
1156 {
1157 symbolfile = ";no$sns symbolic information file\n";
1158 symbolfile += ";generated by asar\n";
1159 symbolfile += "\n";
1160 for (auto& p : all_labels) {
1161 char buffer[10];
1162 std::snprintf(buffer, sizeof(buffer), "%08X ", p.first & 0xFFFFFF);
1163
1164 symbolfile += buffer;
1165 symbolfile += p.second;
1166 symbolfile += "\n";
1167 }
1168 }
1169 4 return symbolfile;
1170 2 }
1171
1172
1173 2 bool in_top_level_file()
1174 {
1175 2 int num_files = 0;
1176
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 for (int i = callstack.count-1; i >= 0; --i)
1177 {
1178
3/3
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 3 times.
8 if (callstack[i].type == callstack_entry_type::FILE)
1179 {
1180 2 num_files++;
1181
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (num_files > 1) break;
1182 }
1183 }
1184 2 return (num_files <= 1);
1185 }
1186
1187 10577 const char* get_current_file_name()
1188 {
1189
2/2
✓ Branch 0 taken 38564 times.
✓ Branch 1 taken 827 times.
39391 for (int i = callstack.count-1; i >= 0; --i)
1190 {
1191
3/3
✓ Branch 0 taken 5382 times.
✓ Branch 1 taken 20298 times.
✓ Branch 2 taken 12884 times.
38564 if (callstack[i].type == callstack_entry_type::FILE)
1192 9750 return callstack[i].content.raw();
1193 }
1194 827 return nullptr;
1195 }
1196
1197 9041 int get_current_line()
1198 {
1199
2/2
✓ Branch 0 taken 26702 times.
✓ Branch 1 taken 11 times.
26713 for (int i = callstack.count-1; i >= 0; --i)
1200 {
1201
3/3
✓ Branch 0 taken 4495 times.
✓ Branch 1 taken 13333 times.
✓ Branch 2 taken 8874 times.
26702 if (callstack[i].type == callstack_entry_type::LINE) return callstack[i].lineno;
1202 }
1203 11 return -1;
1204 }
1205
1206 266 const char* get_current_block()
1207 {
1208
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 11 times.
278 for (int i = callstack.count-1; i >= 0; --i)
1209 {
1210
9/9
✓ Branch 0 taken 103 times.
✓ Branch 1 taken 136 times.
✓ Branch 2 taken 125 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 125 times.
✓ Branch 5 taken 108 times.
✓ Branch 6 taken 6 times.
✓ Branch 7 taken 130 times.
✓ Branch 8 taken 6 times.
267 if (callstack[i].type == callstack_entry_type::LINE || callstack[i].type == callstack_entry_type::BLOCK) return callstack[i].content.raw();
1211 }
1212 11 return nullptr;
1213 }
1214
1215
1216 286 void reseteverything()
1217 {
1218 286 string str;
1219 286 labels.reset();
1220 286 defines.reset();
1221
1/2
✓ Branch 0 taken 286 times.
✗ Branch 1 not taken.
286 builtindefines.each(adddefine);
1222
1/2
✓ Branch 0 taken 286 times.
✗ Branch 1 not taken.
286 clidefines.each(adddefine);
1223 286 structs.reset();
1224
1225
2/3
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
286 macros.each(clearmacro);
1226 286 macros.reset();
1227
1228
1/2
✓ Branch 0 taken 286 times.
✗ Branch 1 not taken.
286 filecontents.each(clearfile);
1229 286 filecontents.reset();
1230
1231 286 writtenblocks.reset();
1232
1233 286 optimizeforbank=-1;
1234 286 optimize_dp = optimize_dp_flag::ALWAYS;
1235 286 dp_base = 0;
1236 286 optimize_address = optimize_address_flag::MIRRORS;
1237
1238
1/2
✓ Branch 0 taken 286 times.
✗ Branch 1 not taken.
286 closecachedfiles();
1239
1240 286 incsrcdepth=0;
1241 286 label_counter = 0;
1242 286 errored = false;
1243 286 checksum_fix_enabled = true;
1244 286 force_checksum_fix = false;
1245
1246 286 in_macro_def = 0;
1247
1248 #ifndef ASAR_SHARED
1249 3 free(const_cast<unsigned char*>(romdata_r));
1250 #endif
1251
1252 286 callstack.reset();
1253 286 simple_callstacks = true;
1254 #undef free
1255 446 }
1256