asar coverage - build #312


src/asar/
File: src/asar/main.cpp
Date: 2025-09-20 22:58:46
Lines:
598/691
86.5%
Functions:
35/38
92.1%
Branches:
821/1388
59.1%

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 std::vector<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 286 int get_version_int()
48 {
49 286 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 10351 static string shorten_to_relative_path(const char* base_path, const char* target_path)
104 {
105
3/4
✓ Branch 0 taken 5349 times.
✓ Branch 1 taken 5002 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 175 times.
10351 if (stribegin(target_path, base_path)) target_path += strlen(base_path);
106 10351 return target_path;
107 }
108
109 10351 static string get_top_level_directory()
110 {
111 10351 string top_level_file_dir;
112
1/2
✓ Branch 0 taken 10351 times.
✗ Branch 1 not taken.
10351 for (size_t i = 0; i < callstack.size(); ++i)
113 {
114
2/3
✓ Branch 0 taken 5174 times.
✓ Branch 1 taken 5177 times.
✗ Branch 2 not taken.
10351 if (callstack[i].type == callstack_entry_type::FILE)
115 {
116
2/4
✓ Branch 0 taken 5174 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5177 times.
✗ Branch 3 not taken.
10351 top_level_file_dir = dir(callstack[i].content);
117 10351 break;
118 }
119 }
120 10351 return top_level_file_dir;
121 }
122
123 10309 static string generate_call_details_string(const char* current_block, const char* current_call, int indentation, bool add_lines)
124 {
125 10309 string e;
126
4/4
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 10261 times.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 6 times.
10309 if (current_block != nullptr || current_call != nullptr)
127 {
128 10303 string indent;
129
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10303 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10303 if (add_lines) indent += "|";
130
3/4
✓ Branch 0 taken 1028 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1028 times.
✓ Branch 3 taken 10303 times.
11331 for (; indentation > 0; --indentation) indent += " ";
131
132
12/22
✓ Branch 0 taken 10261 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 5129 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5129 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10261 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5129 times.
✓ Branch 9 taken 5132 times.
✓ Branch 10 taken 5129 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 10261 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 5132 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 5132 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 5132 times.
✗ Branch 21 not taken.
10303 if (current_block != nullptr) e += STR "\n"+indent+"in block: ["+current_block+"]";
133
12/22
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 10261 times.
✓ Branch 2 taken 21 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 taken 21 times.
✓ Branch 9 taken 21 times.
✓ Branch 10 taken 21 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 42 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 21 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 21 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 21 times.
✗ Branch 21 not taken.
10303 if (current_call != nullptr) e += STR "\n"+indent+"in macro call: [%"+current_call+"]";
134 10303 }
135 10309 return e;
136 }
137
138 10351 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 5174 times.
✓ Branch 1 taken 5177 times.
✓ Branch 2 taken 5174 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5177 times.
✗ Branch 6 not taken.
10351 return shorten_to_relative_path(get_top_level_directory(), current_file);
146 }
147
148 305 static string generate_filename_and_line(const char* current_file, int current_line_no)
149 {
150
1/2
✓ Branch 0 taken 305 times.
✗ Branch 1 not taken.
610 return STR current_file
151
21/38
✓ Branch 0 taken 148 times.
✓ Branch 1 taken 154 times.
✓ Branch 2 taken 151 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 148 times.
✓ Branch 5 taken 151 times.
✓ Branch 6 taken 148 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 302 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 148 times.
✓ Branch 13 taken 154 times.
✓ Branch 14 taken 148 times.
✓ Branch 15 taken 6 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 20 taken 154 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 151 times.
✓ Branch 23 taken 3 times.
✓ Branch 24 taken 151 times.
✓ Branch 25 taken 3 times.
✓ Branch 26 taken 151 times.
✓ Branch 27 taken 3 times.
✓ Branch 28 taken 151 times.
✓ Branch 29 taken 3 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.
915 + (current_line_no>=0?STR ":"+dec(current_line_no+1):"");
152 }
153
154 static string format_stack_line(const printable_callstack_entry& entry, int stack_frame_index)
155 {
156 string indent = "\n| ";
157 indent += dec(stack_frame_index);
158 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 if (stack_frame_index < 100) indent += " ";
162 if (stack_frame_index < 10) indent += " ";
163 return indent
164 + generate_filename_and_line(entry.prettypath, entry.lineno)
165 + entry.details;
166 }
167
168 10046 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 10046 printable_callstack_entry new_entry;
171
1/2
✓ Branch 0 taken 10046 times.
✗ Branch 1 not taken.
10046 new_entry.fullpath = current_file;
172
2/3
✓ Branch 0 taken 5023 times.
✓ Branch 1 taken 5023 times.
✗ Branch 2 not taken.
10046 new_entry.prettypath = get_pretty_filename(current_file);
173 10046 new_entry.lineno = current_line_no;
174
2/3
✓ Branch 0 taken 5023 times.
✓ Branch 1 taken 5023 times.
✗ Branch 2 not taken.
10046 new_entry.details = generate_call_details_string(current_block, current_call, indentation, add_lines);
175
2/3
✓ Branch 0 taken 5023 times.
✓ Branch 1 taken 5023 times.
✗ Branch 2 not taken.
10046 out->append(new_entry);
176 15069 }
177
178 268 void get_current_line_details(string* location, string* details, bool exclude_block)
179 {
180 268 const char* current_file = nullptr;
181 268 const char* current_block = nullptr;
182 268 const char* current_call = nullptr;
183 268 int current_line_no = -1;
184
2/2
✓ Branch 0 taken 725 times.
✓ Branch 1 taken 5 times.
730 for (int i = (int)callstack.size()-1; i >= 0 ; --i)
185 {
186
5/6
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 133 times.
✓ Branch 2 taken 127 times.
✓ Branch 3 taken 231 times.
✓ Branch 4 taken 104 times.
✗ Branch 5 not taken.
725 switch (callstack[i].type)
187 {
188 263 case callstack_entry_type::FILE:
189 263 current_file = callstack[i].content;
190
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 263 times.
263 if (exclude_block) current_block = nullptr;
191
3/8
✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 263 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 133 times.
✗ Branch 7 not taken.
263 *location = generate_filename_and_line(get_pretty_filename(current_file), current_line_no);
192 263 *location += ": ";
193
2/3
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 133 times.
✗ Branch 2 not taken.
263 *details = generate_call_details_string(current_block, current_call, 4, false);
194 263 return;
195 case callstack_entry_type::MACRO_CALL:
196 if (current_call == nullptr) current_call = callstack[i].content;
197 break;
198 257 case callstack_entry_type::LINE:
199
3/4
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 205 times.
✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
257 if (current_block == nullptr && current_call == nullptr) current_block = callstack[i].content;
200
1/2
✓ Branch 0 taken 257 times.
✗ Branch 1 not taken.
257 if (current_line_no == -1) current_line_no = callstack[i].lineno;
201 257 break;
202 205 case callstack_entry_type::BLOCK:
203
1/2
✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
205 if (current_block == nullptr) current_block = callstack[i].content;
204 205 break;
205 }
206 }
207 5 *location = "";
208 5 *details = "";
209 }
210
211 268 void get_full_printable_callstack(autoarray<printable_callstack_entry>* out, int indentation, bool add_lines)
212 {
213 268 out->reset();
214 268 const char* current_file = nullptr;
215 268 const char* current_block = nullptr;
216 268 const char* current_call = nullptr;
217 268 int current_line_no = -1;
218
2/2
✓ Branch 0 taken 30905 times.
✓ Branch 1 taken 268 times.
31173 for (size_t i = 0; i < callstack.size(); ++i)
219 {
220
5/6
✓ Branch 0 taken 5153 times.
✓ Branch 1 taken 5177 times.
✓ Branch 2 taken 5171 times.
✓ Branch 3 taken 10277 times.
✓ Branch 4 taken 5127 times.
✗ Branch 5 not taken.
30905 switch (callstack[i].type)
221 {
222 10309 case callstack_entry_type::FILE:
223
2/2
✓ Branch 0 taken 10046 times.
✓ Branch 1 taken 263 times.
10309 if (current_file != nullptr)
224 {
225 10046 push_stack_line(out, current_file, current_block, current_call, current_line_no, indentation, add_lines);
226 }
227 10309 current_file = callstack[i].content;
228 10309 current_block = nullptr;
229 10309 current_call = nullptr;
230 10309 current_line_no = -1;
231 10309 break;
232 42 case callstack_entry_type::MACRO_CALL:
233 42 current_block = nullptr;
234 42 current_call = callstack[i].content;
235 42 break;
236 10303 case callstack_entry_type::LINE:
237 10303 current_line_no = callstack[i].lineno;
238 10303 current_block = callstack[i].content;
239 10303 break;
240 10251 case callstack_entry_type::BLOCK:
241 10251 current_block = callstack[i].content;
242 10251 break;
243 }
244 }
245 268 }
246
247 static string get_full_callstack()
248 {
249 autoarray<printable_callstack_entry> printable_stack;
250 get_full_printable_callstack(&printable_stack, 12, true);
251
252 string e;
253 if (printable_stack.count > 0)
254 {
255 e += "\nFull call stack:";
256 for (int i = printable_stack.count-1; i >= 0; --i)
257 {
258 e += format_stack_line(printable_stack[i], i);
259 }
260 }
261 return e;
262 }
263
264 // RPG Hacker: This function essetially replicates classic Asar behavior
265 // of only printing a single macro call below the current level.
266 268 static string get_simple_callstack()
267 {
268 int i;
269 268 const char* current_call = nullptr;
270
2/2
✓ Branch 0 taken 30779 times.
✓ Branch 1 taken 226 times.
31005 for (i = (int)callstack.size()-1; i >= 0 ; --i)
271 {
272
3/3
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 15385 times.
✓ Branch 2 taken 15373 times.
30779 if (callstack[i].type == callstack_entry_type::MACRO_CALL)
273 {
274 42 current_call = callstack[i].content;
275 42 break;
276 }
277 }
278
279 268 const char* current_file = nullptr;
280 268 int current_line_no = -1;
281
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 226 times.
268 if (current_call != nullptr)
282 {
283 42 bool stop = false;
284
1/2
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
126 for (int j = i-1; j >= 0 ; --j)
285 {
286
5/6
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 42 times.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
126 switch (callstack[j].type)
287 {
288 42 case callstack_entry_type::FILE:
289
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (current_file != nullptr)
290 {
291 stop = true;
292 break;
293 }
294 42 current_file = callstack[j].content;
295 42 break;
296 case callstack_entry_type::MACRO_CALL:
297 stop = true;
298 break;
299 42 case callstack_entry_type::LINE:
300
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 if (current_line_no == -1) current_line_no = callstack[j].lineno;
301 42 break;
302 42 case callstack_entry_type::BLOCK:
303 42 break;
304 }
305
306
3/4
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 84 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
126 if (current_file != nullptr && current_line_no != -1) stop = true;
307
308
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 84 times.
126 if (stop) break;
309 }
310 }
311
312 268 string e;
313
3/4
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 226 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
268 if (current_call != nullptr && current_file != nullptr)
314 {
315
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)
316
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 + "]";
317 }
318 268 return e;
319 }
320
321 268 string get_callstack()
322 {
323
3/4
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 136 times.
✓ Branch 2 taken 136 times.
✗ Branch 3 not taken.
268 if (simple_callstacks)
324 268 return get_simple_callstack();
325 else
326 return get_full_callstack();
327 }
328
329 18 void throw_vfile_error(int whichpass, virtual_file_error vfile_error, const char* filename)
330 {
331
2/5
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
18 switch (vfile_error)
332 {
333 6 case vfe_doesnt_exist:
334 6 throw_err_block(whichpass, err_file_not_found, filename);
335 case vfe_access_denied:
336 throw_err_block(whichpass, err_failed_to_open_file_access_denied, filename);
337 12 case vfe_not_regular_file:
338 12 throw_err_block(whichpass, err_failed_to_open_not_regular_file, filename);
339 case vfe_unknown:
340 case vfe_none:
341 case vfe_num_errors:
342 throw_err_block(whichpass, err_failed_to_open_file, filename);
343 }
344
345 throw_err_block(whichpass, err_failed_to_open_file, filename);
346 }
347
348 18 virtual_file_error asar_get_last_io_error()
349 {
350
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 if (filesystem != nullptr)
351 {
352 18 return filesystem->get_last_error();
353 }
354
355 return vfe_unknown;
356 }
357
358 657 int getlenforlabel(int labelpos, int label_fs_id, bool exists)
359 {
360 657 unsigned int bank = labelpos>>16;
361 657 unsigned int word = labelpos&0xFFFF;
362 657 bool lblfreespace = label_fs_id > 0;
363 unsigned int relaxed_bank;
364
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 633 times.
657 if(optimizeforbank >= 0) {
365 24 relaxed_bank = optimizeforbank;
366 } else {
367
2/2
✓ Branch 0 taken 505 times.
✓ Branch 1 taken 128 times.
633 if(freespaceid == 0) {
368 505 relaxed_bank = snespos >> 16;
369 } else {
370 128 int target_bank = freespaces[freespaceid].bank;
371
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 44 times.
128 if(target_bank == -2) relaxed_bank = 0;
372
1/2
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
44 else if(target_bank == -1) relaxed_bank = 0x40;
373 else relaxed_bank = target_bank;
374 }
375 }
376
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 657 times.
657 if (!exists)
377 {
378 return 2;
379 }
380
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)
381 {
382 6 return 1;
383 }
384
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)
385 {
386 23 return 1;
387 }
388 628 else if (
389 // if we should optimize ram accesses...
390
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)
391 // and we're in a bank with ram mirrors... (optimizeforbank=0x7E is checked later)
392
2/2
✓ Branch 0 taken 488 times.
✓ Branch 1 taken 32 times.
520 && !(relaxed_bank & 0x40)
393 // and the label is in low RAM
394
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)
395 {
396 18 return 2;
397 }
398 610 else if (
399 // if we should optimize mirrors...
400
2/2
✓ Branch 0 taken 478 times.
✓ Branch 1 taken 132 times.
610 optimize_address == optimize_address_flag::MIRRORS
401 // we're in a bank with ram mirrors...
402
2/2
✓ Branch 0 taken 452 times.
✓ Branch 1 taken 26 times.
478 && !(relaxed_bank & 0x40)
403 // and the label is in a mirrored section
404
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)
405 {
406 24 return 2;
407 }
408
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 562 times.
586 else if (optimizeforbank>=0)
409 {
410 // if optimizing for a specific bank:
411 // if the label is in freespace, never optimize
412
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (lblfreespace) return 3;
413
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 else if (bank==(unsigned int)optimizeforbank) return 2;
414 12 else return 3;
415 }
416
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)
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 176 times.
✓ Branch 1 taken 32 times.
208 if (label_fs_id != freespaceid) return 3;
421 32 else return 2;
422 }
423
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 324 times.
354 else if ((int)bank != snespos >> 16){ return 3; }
424 324 else { return 2;}
425 }
426 645 int getlenforlabel(snes_label thislabel, bool exists) {
427 645 return getlenforlabel(thislabel.pos, thislabel.freespace_id, exists);
428 }
429
430
431 315 bool is_hex_constant(const char* str){
432
3/3
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 156 times.
✓ Branch 2 taken 51 times.
315 if (*str=='$')
433 {
434 216 str++;
435
3/3
✓ Branch 0 taken 300 times.
✓ Branch 1 taken 408 times.
✓ Branch 2 taken 108 times.
816 while(is_xdigit(*str)) {
436 600 str++;
437 }
438
2/3
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
216 if(*str=='\0'){
439 216 return true;
440 }
441 }
442 99 return false;
443 }
444
445 struct strcompare {
446 bool operator() (const char * lhs, const char * rhs) const
447 {
448 return strcmp(lhs, rhs)<0;
449 }
450 };
451
452 struct stricompare {
453 bool operator() (const char * lhs, const char * rhs) const
454 {
455 return stricmp(lhs, rhs)<0;
456 }
457 };
458
459 struct sourcefile {
460 char *data;
461 char** contents;
462 int numlines;
463 };
464
465 static assocarr<sourcefile> filecontents;
466 assocarr<string> defines;
467 // needs to be separate because defines is reset between parsing arguments and patching
468 assocarr<string> clidefines;
469 assocarr<string> builtindefines;
470
471 201 bool validatedefinename(const char * name)
472 {
473
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
✓ Branch 2 taken 105 times.
201 if (!name[0]) return false;
474
4/4
✓ Branch 0 taken 429 times.
✓ Branch 1 taken 96 times.
✓ Branch 2 taken 479 times.
✓ Branch 3 taken 105 times.
1109 for (int i = 0;name[i];i++)
475 {
476
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 429 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 479 times.
908 if (!is_ualnum(name[i])) return false;
477 }
478
479 201 return true;
480 }
481
482 67123 void resolvedefines(string& out, const char * start)
483 {
484
3/3
✓ Branch 0 taken 33422 times.
✓ Branch 1 taken 33700 times.
✓ Branch 2 taken 1 times.
67123 recurseblock rec;
485 67121 const char * here=start;
486
4/4
✓ Branch 0 taken 28202 times.
✓ Branch 1 taken 38919 times.
✓ Branch 2 taken 28447 times.
✓ Branch 3 taken 5252 times.
67121 if (!strchr(here, '!'))
487 {
488
2/3
✓ Branch 0 taken 28202 times.
✓ Branch 1 taken 28447 times.
✗ Branch 2 not taken.
56649 out += here;
489 56649 return;
490 }
491
3/3
✓ Branch 0 taken 35955 times.
✓ Branch 1 taken 41483 times.
✓ Branch 2 taken 5236 times.
82674 while (*here)
492 {
493
6/6
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 35955 times.
✓ Branch 2 taken 36257 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 21 times.
72233 if (here[0] == '\\' && here[1] == '\\')
494 {
495 // allow using \\ as escape sequence
496
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 += "\\";
497
2/3
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 out += "\\";
498 6 here += 2;
499 }
500
4/6
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 35952 times.
✓ Branch 2 taken 36275 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
72227 else if (here[0] == '\\' && here[1] == '!')
501 {
502 // allow using \! to escape !
503
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 += "\\";
504
2/3
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
42 out+="!";
505 42 here += 2;
506 }
507
3/3
✓ Branch 0 taken 5601 times.
✓ Branch 1 taken 35975 times.
✓ Branch 2 taken 30609 times.
72185 else if (*here=='!')
508 {
509
14/14
✓ Branch 0 taken 5486 times.
✓ Branch 1 taken 5760 times.
✓ Branch 2 taken 1692 times.
✓ Branch 3 taken 2756 times.
✓ Branch 4 taken 2337 times.
✓ Branch 5 taken 393 times.
✓ Branch 6 taken 60 times.
✓ Branch 7 taken 2543 times.
✓ Branch 8 taken 423 times.
✓ Branch 9 taken 54 times.
✓ Branch 10 taken 60 times.
✓ Branch 11 taken 1244 times.
✓ Branch 12 taken 6 times.
✓ Branch 13 taken 54 times.
11246 bool first=(here==start || (here>=start+4 && here[-1]==' ' && here[-2]==':' && here[-3]==' '));//check if it's the start of a block
510 11246 string defname;
511 11246 here++;
512
513 11246 int depth = 0;
514
3/3
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 5658 times.
✓ Branch 2 taken 5645 times.
11360 for (const char* depth_str = here; *depth_str=='^'; depth_str++)
515 {
516 114 depth++;
517 }
518 11246 here += depth;
519
520
2/2
✓ Branch 0 taken 1320 times.
✓ Branch 1 taken 9926 times.
11246 if (depth != in_macro_def)
521 {
522
2/3
✓ Branch 0 taken 660 times.
✓ Branch 1 taken 660 times.
✗ Branch 2 not taken.
1320 out += '!';
523
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 660 times.
1386 for (int i=0; i < depth; ++i) out += '^';
524
3/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 1302 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
1320 if (depth > in_macro_def) throw_err_line(0, err_invalid_depth_resolve, "define", "define", depth, in_macro_def);
525 1302 continue;
526 1302 }
527
528
3/3
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 4941 times.
✓ Branch 2 taken 4931 times.
9926 if (*here=='{')
529 {
530 108 here++;
531 108 string unprocessedname;
532 108 int braces=1;
533 while (true)
534 {
535
3/3
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 576 times.
✓ Branch 2 taken 540 times.
1152 if (*here=='{') braces++;
536
3/3
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 576 times.
✓ Branch 2 taken 486 times.
1152 if (*here=='}') braces--;
537
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 576 times.
✓ Branch 2 taken 576 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1152 if (!*here) throw_err_line(0, err_mismatched_braces);
538
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 1044 times.
1152 if (!braces) break;
539
2/4
✓ Branch 0 taken 522 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 522 times.
✗ Branch 3 not taken.
1044 unprocessedname+=*here++;
540 }
541 108 here++;
542
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 resolvedefines(defname, unprocessedname);
543
3/7
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
108 if (!validatedefinename(defname)) throw_err_line(0, err_invalid_define_name);
544 108 }
545 else
546 {
547
5/7
✓ Branch 0 taken 24774 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 49755 times.
✓ Branch 3 taken 4887 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 24981 times.
✓ Branch 6 taken 4931 times.
59573 while (is_ualnum(*here)) defname+=*here++;
548 }
549
550
2/2
✓ Branch 0 taken 4973 times.
✓ Branch 1 taken 4953 times.
9926 if (first)
551 {
552 enum {
553 null,
554 append,
555 expand,
556 domath,
557 setifnotset,
558 } mode;
559 if(0);
560
2/2
✓ Branch 0 taken 519 times.
✓ Branch 1 taken 4743 times.
5262 else if (stribegin(here, " = ")) { here+=3; mode=null; }
561
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 4641 times.
4743 else if (stribegin(here, " += ")) { here+=4; mode=append; }
562
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 4587 times.
4641 else if (stribegin(here, " := ")) { here+=4; mode=expand; }
563
2/2
✓ Branch 0 taken 1926 times.
✓ Branch 1 taken 2661 times.
4587 else if (stribegin(here, " #= ")) { here+=4; mode=domath; }
564
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2661 times.
2661 else if (stribegin(here, " ?= ")) { here+=4; mode=setifnotset; }
565 2661 else goto notdefineset;
566 2601 string val;
567
3/3
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 1299 times.
✓ Branch 2 taken 1209 times.
2601 if (*here=='"')
568 {
569 189 here++;
570 while (true)
571 {
572
3/3
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 513 times.
✓ Branch 2 taken 414 times.
1023 if (*here=='"')
573 {
574
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;
575
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++;
576 else throw_err_line(0, err_broken_define_declaration);
577 }
578
2/4
✓ Branch 0 taken 417 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 417 times.
✗ Branch 3 not taken.
834 val+=*here++;
579 }
580 189 here++;
581 }
582 else
583 {
584
7/9
✓ Branch 0 taken 8286 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16590 times.
✓ Branch 3 taken 1203 times.
✓ Branch 4 taken 8286 times.
✓ Branch 5 taken 8304 times.
✓ Branch 6 taken 1209 times.
✓ Branch 7 taken 8304 times.
✗ Branch 8 not taken.
19002 while (*here && *here!=' ') val+=*here++;
585 }
586 //if (strqchr(val.data(), ';')) *strqchr(val.data(), ';')=0;
587
4/11
✗ Branch 0 not taken.
✓ Branch 1 taken 1296 times.
✓ Branch 2 taken 1305 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1296 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1305 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
2601 if (*here && !stribegin(here, " : ")) throw_err_line(0, err_broken_define_declaration);
588 // RPG Hacker: Is it really a good idea to normalize
589 // the content of defines? That kinda violates their
590 // functionality as a string replacement mechanism.
591 //val.qnormalize();
592
593 // RPG Hacker: throw an error if we're trying to overwrite built-in defines.
594
3/4
✓ Branch 0 taken 2601 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 2595 times.
2601 if (builtindefines.exists(defname))
595 {
596
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 throw_err_line(0, err_overriding_builtin_define, defname.data());
597 }
598
599
4/6
✓ Branch 0 taken 513 times.
✓ Branch 1 taken 102 times.
✓ Branch 2 taken 54 times.
✓ Branch 3 taken 1926 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
2595 switch (mode)
600 {
601 513 case null:
602 {
603
3/5
✓ Branch 0 taken 513 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 252 times.
✓ Branch 3 taken 261 times.
✗ Branch 4 not taken.
513 defines.create(defname) = val;
604 513 break;
605 }
606 102 case append:
607 {
608
2/6
✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 102 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
102 if (!defines.exists(defname)) throw_err_line(0, err_define_not_found, defname.data());
609
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);
610
2/3
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
102 val=oldval+val;
611
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;
612 102 break;
613 102 }
614 54 case expand:
615 {
616 54 string newval;
617
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 resolvedefines(newval, val);
618
3/5
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 27 times.
✗ Branch 4 not taken.
54 defines.create(defname) = newval;
619 54 break;
620 54 }
621 1926 case domath:
622 {
623 1926 string newval;
624
1/2
✓ Branch 0 taken 1926 times.
✗ Branch 1 not taken.
1926 resolvedefines(newval, val);
625
5/8
✓ Branch 0 taken 963 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1923 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 960 times.
✓ Branch 7 taken 3 times.
1932 math_val num = parse_math_expr(newval)->evaluate_static();
626 1920 string num_str;
627
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1920 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1920 if(num.m_type == math_val_type::string) num_str = num.get_str();
628
6/8
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1908 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.
1920 else if(num.m_type == math_val_type::floating) num_str = ftostr(num.get_double());
629
4/6
✓ Branch 0 taken 954 times.
✓ Branch 1 taken 954 times.
✓ Branch 2 taken 954 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 954 times.
✗ Branch 5 not taken.
1908 else num_str = dec(num.get_integer());
630
2/3
✓ Branch 0 taken 960 times.
✓ Branch 1 taken 960 times.
✗ Branch 2 not taken.
1920 defines.create(defname) = std::move(num_str);
631 1920 break;
632 1926 }
633 case setifnotset:
634 {
635 if (!defines.exists(defname)) defines.create(defname) = val;
636 break;
637 }
638 }
639 2601 }
640 else
641 {
642 5996 notdefineset:
643
4/5
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 7244 times.
✓ Branch 2 taken 39 times.
✓ Branch 3 taken 42 times.
✗ Branch 4 not taken.
7325 if (!defname) out+="!";
644 else
645 {
646
4/6
✓ Branch 0 taken 7244 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 7243 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
7244 if (!defines.exists(defname)) throw_err_line(0, err_define_not_found, defname.data());
647 else {
648
4/7
✓ Branch 0 taken 3606 times.
✓ Branch 1 taken 3637 times.
✓ Branch 2 taken 3606 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3637 times.
✗ Branch 6 not taken.
7243 string thisone = defines.find(defname);
649
1/2
✓ Branch 0 taken 7243 times.
✗ Branch 1 not taken.
7243 resolvedefines(out, thisone);
650 7243 }
651 }
652 }
653
2/2
✓ Branch 0 taken 9913 times.
✓ Branch 1 taken 1302 times.
11246 }
654
2/4
✓ Branch 0 taken 30330 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30609 times.
✗ Branch 3 not taken.
60939 else out+=*here++;
655 }
656
2/2
✓ Branch 0 taken 10441 times.
✓ Branch 1 taken 56649 times.
67121 }
657
658 bool moreonline;
659 bool asarverallowed = false;
660
661 56833 void assembleline(const char * fname, int linenum, const string& line, int& single_line_for_tracker)
662 {
663
2/3
✓ Branch 0 taken 28295 times.
✓ Branch 1 taken 28538 times.
✗ Branch 2 not taken.
56833 recurseblock rec;
664
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28538 times.
56833 bool moreonlinetmp=moreonline;
665 56833 single_line_for_tracker = 1;
666 try
667 {
668
2/3
✓ Branch 0 taken 28295 times.
✓ Branch 1 taken 28538 times.
✗ Branch 2 not taken.
56833 string out=line;
669
2/3
✓ Branch 0 taken 28295 times.
✓ Branch 1 taken 28538 times.
✗ Branch 2 not taken.
56833 autoptr<char**> blocks=qsplitstr(out.temp_raw(), " : ");
670 56833 moreonline=true;
671
4/4
✓ Branch 0 taken 29195 times.
✓ Branch 1 taken 76334 times.
✓ Branch 2 taken 29507 times.
✓ Branch 3 taken 23535 times.
105529 for (int block_i=0;moreonline;block_i++)
672 {
673 58702 moreonline=(blocks[block_i+1] != nullptr);
674 try
675 {
676 // it's possible that our input looks something like:
677 // nop : : nop
678 // nop : : : : : nop
679 // also, it's possible that there were empty blocks at the start or end of the line:
680 // : nop :
681 // after qsplit, we still need to deal with possibly a single ": " from a preceding empty block,
682 // and if it's the last block, possibly a following " :".
683 58702 char* thisblock = strip_whitespace(blocks[block_i]);
684 // if the block starts with ": "
685
6/6
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 29195 times.
✓ Branch 2 taken 29492 times.
✓ Branch 3 taken 15 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 15 times.
58702 if(thisblock[0] == ':' && thisblock[1] == ' ') {
686 24 thisblock++;
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(*thisblock == ' ') thisblock++;
688 }
689 // if the block is a single :, skip that too.
690
4/6
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 29195 times.
✓ Branch 2 taken 29507 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
58702 if(thisblock[0] == ':' && thisblock[1] == 0) thisblock++;
691
692
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29507 times.
58702 int len_blk = strlen(thisblock);
693 // last block - strip trailing " :" if present.
694
12/12
✓ Branch 0 taken 28295 times.
✓ Branch 1 taken 30407 times.
✓ Branch 2 taken 47748 times.
✓ Branch 3 taken 10054 times.
✓ Branch 4 taken 20959 times.
✓ Branch 5 taken 26789 times.
✓ Branch 6 taken 6 times.
✓ Branch 7 taken 1560 times.
✓ Branch 8 taken 1596 times.
✓ Branch 9 taken 17797 times.
✓ Branch 10 taken 6 times.
✓ Branch 11 taken 1590 times.
58702 if(!moreonline && len_blk >= 2 && thisblock[len_blk-2] == ' ' && thisblock[len_blk-1] == ':') {
695 12 thisblock[len_blk - 2] = 0;
696 }
697
698
2/3
✓ Branch 0 taken 29195 times.
✓ Branch 1 taken 29507 times.
✗ Branch 2 not taken.
58702 callstack_push cs_push(callstack_entry_type::BLOCK, thisblock);
699
700
2/2
✓ Branch 0 taken 48392 times.
✓ Branch 1 taken 10310 times.
58702 assembleblock(thisblock, single_line_for_tracker);
701
2/2
✓ Branch 0 taken 48388 times.
✓ Branch 1 taken 4 times.
48392 checkbankcross();
702 58702 }
703
2/2
✓ Branch 0 taken 10006 times.
✓ Branch 1 taken 308 times.
10314 catch (errblock&) {}
704
4/4
✓ Branch 0 taken 15197 times.
✓ Branch 1 taken 8995 times.
✓ Branch 2 taken 15455 times.
✓ Branch 3 taken 9049 times.
48696 if (blocks[block_i][0]!='\0') asarverallowed=false;
705
3/3
✓ Branch 0 taken 23127 times.
✓ Branch 1 taken 24435 times.
✓ Branch 2 taken 1134 times.
48696 if(single_line_for_tracker == 1) single_line_for_tracker = 0;
706 }
707 66839 }
708
1/2
✓ Branch 0 taken 10006 times.
✗ Branch 1 not taken.
10006 catch (errline&) {}
709 46827 moreonline=moreonlinetmp;
710 80368 }
711
712 int incsrcdepth=0;
713
714 // Returns true if a file is protected via
715 // an "includeonce".
716 11030 bool file_included_once(const char* file)
717 {
718
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 10988 times.
11228 for (int i = 0; i < includeonce.count; ++i)
719 {
720
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)
721 {
722 42 return true;
723 }
724 }
725
726 10988 return false;
727 }
728
729 autoarray<string> macro_defs;
730 int in_macro_def=0;
731
732 11000 void assemblefile(const char * filename)
733 {
734 11000 incsrcdepth++;
735
3/5
✓ Branch 0 taken 10991 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5548 times.
✗ Branch 4 not taken.
11000 string absolutepath = filesystem->create_absolute_path(get_current_file_name(), filename);
736
737
3/4
✓ Branch 0 taken 11000 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 10958 times.
11000 if (file_included_once(absolutepath))
738 {
739 42 return;
740 }
741
742 // don't do this yet; we want "file not found" errors to show the location
743 // that called assemblefile
744 //callstack_push cs_push(callstack_entry_type::FILE, absolutepath);
745
746 5536 sourcefile file;
747 10958 file.contents = nullptr;
748 10958 file.numlines = 0;
749 10958 int startif=numif;
750
3/4
✓ Branch 0 taken 10958 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 334 times.
✓ Branch 3 taken 10624 times.
10958 if (!filecontents.exists(absolutepath))
751 {
752
2/2
✓ Branch 0 taken 332 times.
✓ Branch 1 taken 2 times.
334 char * temp = readfile(absolutepath, "");
753
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 326 times.
332 if (!temp)
754 {
755
3/5
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
6 throw_vfile_error(0, asar_get_last_io_error(), filename);
756 return;
757 }
758
2/3
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
326 callstack_push cs_push(callstack_entry_type::FILE, absolutepath);
759
760
1/2
✓ Branch 0 taken 326 times.
✗ Branch 1 not taken.
326 sourcefile& newfile = filecontents.create(absolutepath);
761
1/2
✓ Branch 0 taken 326 times.
✗ Branch 1 not taken.
326 newfile.contents =split(temp, '\n');
762 326 newfile.data = temp;
763
4/4
✓ Branch 0 taken 6115 times.
✓ Branch 1 taken 144 times.
✓ Branch 2 taken 6196 times.
✓ Branch 3 taken 182 times.
12637 for (int i=0;newfile.contents[i];i++)
764 {
765 12311 newfile.numlines++;
766 12311 char * line = newfile.contents[i];
767 12311 int i_temp = i;
768 char * comment;
769
2/2
✓ Branch 0 taken 3624 times.
✓ Branch 1 taken 12309 times.
15933 while((comment = strqchr(line, ';'))) {
770
5/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1806 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 1806 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
3624 if(comment[1] == '[' && comment[2] == '[') {
771 // block comment - find where it ends
772 12 char* theline = comment + 3;
773
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
12 char* comment_end = strstr(theline, "]]");
774
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 10 times.
30 while(comment_end == nullptr) {
775 20 i_temp++;
776 20 char* new_line = newfile.contents[i_temp];
777
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18 times.
20 if(new_line == nullptr) {
778
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);
779
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 throw_err_null(0, err_unclosed_block_comment);
780 // make sure this line is still parsed correctly
781 2 *comment = 0;
782 // but don't go looking at any other lines
783 2 goto break_outer;
784 2 }
785
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
18 comment_end = strstr(new_line, "]]");
786 // this line is itself part of the comment, so ignore it
787 //new_line[0] = 0;
788 // except not like that^, because that will break the
789 // memmove below
790 static char junk[]="";
791 // using a static here should be fine, since if the line
792 // doesn't contain ',' or '\' we won't go mutating it
793 18 newfile.contents[i_temp] = junk;
794 }
795 // comment_end+2 is a valid pointer, since comment_end is
796 // guaranteed to start with ]]
797 10 comment_end += 2;
798 // stitch together the part of the line before the comment,
799 // and the part of the line after it
800
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);
801 // and then recheck for ; in the line again...
802 10 } else {
803 3612 *comment = 0;
804 }
805 }
806 12310 break_outer:
807
3/4
✓ Branch 0 taken 12311 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 12307 times.
12311 if (!confirmquotes(line)) {
808
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);
809
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 throw_err_null(0, err_mismatched_quotes);
810 4 line[0] = '\0';
811 4 }
812 12311 newfile.contents[i] = strip_whitespace(line);
813 }
814
4/4
✓ Branch 0 taken 6115 times.
✓ Branch 1 taken 144 times.
✓ Branch 2 taken 6196 times.
✓ Branch 3 taken 182 times.
12637 for(int i=0;newfile.contents[i];i++)
815 {
816 12311 char* line = newfile.contents[i];
817
3/3
✓ Branch 0 taken 2480 times.
✓ Branch 1 taken 6129 times.
✓ Branch 2 taken 3702 times.
12311 if(!*line) continue;
818
6/8
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 7342 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.
7347 for (int j=1;line[strlen(line) - 1] == ',' && newfile.contents[i+j];j++)
819 {
820 // not using strcat because the source and dest overlap here
821 10 char* otherline = newfile.contents[i+j];
822
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
10 char* line_end = line + strlen(line);
823
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++;
824 10 *line_end = '\0';
825 static char nullstr[]="";
826 10 newfile.contents[i+j]=nullstr;
827 }
828 }
829 326 file = newfile;
830 326 } else { // filecontents.exists(absolutepath)
831
1/2
✓ Branch 0 taken 10624 times.
✗ Branch 1 not taken.
10624 file = filecontents.find(absolutepath);
832 }
833 // previous callstack_push got dropped by the end of the if scope
834
2/3
✓ Branch 0 taken 5418 times.
✓ Branch 1 taken 5532 times.
✗ Branch 2 not taken.
20958 callstack_push cs_push(callstack_entry_type::FILE, absolutepath);
835 10950 asarverallowed=true;
836
5/6
✓ Branch 0 taken 26526 times.
✓ Branch 1 taken 414 times.
✓ Branch 2 taken 53295 times.
✓ Branch 3 taken 528 times.
✓ Branch 4 taken 26769 times.
✗ Branch 5 not taken.
54237 for (int i=0;file.contents[i] && i<file.numlines;i++)
837 {
838 53295 string connectedline;
839
1/2
✓ Branch 0 taken 53295 times.
✗ Branch 1 not taken.
53295 int skiplines = getconnectedlines<char**>(file.contents, i, connectedline);
840
841
2/2
✓ Branch 0 taken 43287 times.
✓ Branch 1 taken 10008 times.
53295 bool was_loop_end = do_line_logic(connectedline, absolutepath, i);
842 43287 i += skiplines;
843
844 // if a loop ended on this line, should it run again?
845
12/12
✓ Branch 0 taken 1560 times.
✓ Branch 1 taken 41727 times.
✓ Branch 2 taken 780 times.
✓ Branch 3 taken 780 times.
✓ Branch 4 taken 666 times.
✓ Branch 5 taken 114 times.
✓ Branch 6 taken 666 times.
✓ Branch 7 taken 21636 times.
✓ Branch 8 taken 666 times.
✓ Branch 9 taken 114 times.
✓ Branch 10 taken 666 times.
✓ Branch 11 taken 21099 times.
43287 if (was_loop_end && whilestatus[numif].cond)
846
2/3
✓ Branch 0 taken 666 times.
✓ Branch 1 taken 666 times.
✗ Branch 2 not taken.
1332 i = whilestatus[numif].startline - 1;
847 53295 }
848
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 942 times.
954 while (in_macro_def > 0)
849 {
850
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 throw_err_null(0, err_unclosed_macro, macro_defs[in_macro_def-1].data());
851
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);
852 12 in_macro_def--;
853 12 macro_defs.remove(in_macro_def);
854 }
855
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 942 times.
942 if (numif!=startif)
856 {
857 numif=startif;
858 numtrue=startif;
859 throw_err_null(0, err_unclosed_if);
860 }
861 942 incsrcdepth--;
862
2/2
✓ Branch 0 taken 942 times.
✓ Branch 1 taken 42 times.
11000 }
863
864 // RPG Hacker: At some point, this should probably be merged
865 // into assembleline(), since the two names just cause
866 // confusion otherwise.
867 // return value is "did a loop end on this line"
868 60369 bool do_line_logic(const string& line, const char* filename, int lineno)
869 {
870 60369 int prevnumif = numif;
871 60369 int single_line_for_tracker = 1;
872 try
873 {
874 60369 string current_line;
875
9/9
✓ Branch 0 taken 3276 times.
✓ Branch 1 taken 57093 times.
✓ Branch 2 taken 2790 times.
✓ Branch 3 taken 486 times.
✓ Branch 4 taken 84 times.
✓ Branch 5 taken 1395 times.
✓ Branch 6 taken 29820 times.
✓ Branch 7 taken 30306 times.
✓ Branch 8 taken 1554 times.
60369 if (numif==numtrue || (numtrue+1==numif && stribegin(line, "elseif ")))
876 {
877
2/4
✓ Branch 0 taken 28509 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28752 times.
✗ Branch 3 not taken.
57261 callstack_push cs_push(callstack_entry_type::LINE, line, lineno);
878
3/3
✓ Branch 0 taken 28464 times.
✓ Branch 1 taken 28752 times.
✓ Branch 2 taken 45 times.
57261 string tmp=replace_macro_args(line);
879
1/2
✓ Branch 0 taken 57171 times.
✗ Branch 1 not taken.
57171 tmp.qnormalize();
880
2/2
✓ Branch 0 taken 57139 times.
✓ Branch 1 taken 32 times.
57171 resolvedefines(current_line, tmp);
881
4/6
✓ Branch 0 taken 57139 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 57133 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
57139 if (!confirmquotes(current_line)) throw_err_line(0, err_mismatched_quotes);
882 57299 }
883
1/2
✓ Branch 0 taken 3108 times.
✗ Branch 1 not taken.
3108 else current_line=line;
884
885
2/3
✓ Branch 0 taken 29999 times.
✓ Branch 1 taken 30242 times.
✗ Branch 2 not taken.
60241 callstack_push cs_push(callstack_entry_type::LINE, current_line, lineno);
886
887
6/6
✓ Branch 0 taken 552 times.
✓ Branch 1 taken 59689 times.
✓ Branch 2 taken 516 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 516 times.
✓ Branch 5 taken 59725 times.
60241 if (stribegin(current_line, "macro ") && numif==numtrue)
888 {
889 // RPG Hacker: Slight redundancy here with code that is
890 // also in startmacro(). Could improve this for Asar 2.0.
891
2/4
✓ Branch 0 taken 258 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 258 times.
✗ Branch 3 not taken.
516 string macro_name = current_line.data()+6;
892 516 char * startpar=strqchr(macro_name.raw(), '(');
893
1/2
✓ Branch 0 taken 516 times.
✗ Branch 1 not taken.
516 if (startpar) *startpar=0;
894
1/2
✓ Branch 0 taken 516 times.
✗ Branch 1 not taken.
516 macro_defs.append(macro_name);
895
896 // RPG Hacker: I think it would make more logical sense
897 // to have this ++ after the if, but hat breaks compatibility
898 // with at least one test, and it generally leads to more
899 // errors being output after a broken macro declaration.
900 516 in_macro_def++;
901
2/2
✓ Branch 0 taken 172 times.
✓ Branch 1 taken 344 times.
516 if (!pass)
902 {
903
5/5
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 69 times.
✓ Branch 3 taken 70 times.
✓ Branch 4 taken 1 times.
172 if (in_macro_def == 1) startmacro(current_line.data()+6);
904
4/6
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
32 else tomacro(current_line);
905 }
906 516 }
907
8/8
✓ Branch 0 taken 29741 times.
✓ Branch 1 taken 29984 times.
✓ Branch 2 taken 540 times.
✓ Branch 3 taken 59185 times.
✓ Branch 4 taken 504 times.
✓ Branch 5 taken 36 times.
✓ Branch 6 taken 504 times.
✓ Branch 7 taken 59221 times.
59725 else if (!stricmp(current_line, "endmacro") && numif==numtrue)
908 {
909
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 504 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
504 if (in_macro_def == 0) throw_err_line(0, err_misplaced_endmacro);
910 else
911 {
912 504 in_macro_def--;
913 504 macro_defs.remove(in_macro_def);
914
2/2
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 336 times.
504 if (!pass)
915 {
916
3/4
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 138 times.
✗ Branch 3 not taken.
168 if (in_macro_def == 0) endmacro(true);
917
4/6
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
30 else tomacro(current_line);
918 }
919 }
920 }
921
2/2
✓ Branch 0 taken 2388 times.
✓ Branch 1 taken 56833 times.
59221 else if (in_macro_def > 0)
922 {
923
6/8
✓ Branch 0 taken 796 times.
✓ Branch 1 taken 1592 times.
✓ Branch 2 taken 398 times.
✓ Branch 3 taken 398 times.
✓ Branch 4 taken 398 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 398 times.
✗ Branch 7 not taken.
2388 if (!pass) tomacro(current_line);
924 }
925 else
926 {
927
2/2
✓ Branch 0 taken 46827 times.
✓ Branch 1 taken 10006 times.
56833 assembleline(filename, lineno, current_line, single_line_for_tracker);
928 }
929 70377 }
930
2/2
✓ Branch 0 taken 10008 times.
✓ Branch 1 taken 128 times.
10136 catch (errline&) {}
931
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 47571 times.
47631 return (numif < prevnumif || single_line_for_tracker == 3)
932
14/17
✓ Branch 0 taken 47631 times.
✓ Branch 1 taken 2730 times.
✓ Branch 2 taken 1395 times.
✓ Branch 3 taken 1395 times.
✓ Branch 4 taken 432 times.
✓ Branch 5 taken 963 times.
✓ Branch 6 taken 432 times.
✓ Branch 7 taken 1395 times.
✓ Branch 8 taken 606 times.
✓ Branch 9 taken 1221 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 432 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 432 times.
✓ Branch 15 taken 174 times.
✓ Branch 16 taken 258 times.
148353 && (whilestatus[numif].iswhile || whilestatus[numif].is_for);
933 }
934
935
936 4 void parse_std_includes(const char* textfile, autoarray<string>& outarray)
937 {
938 4 char* content = readfilenative(textfile);
939
940
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (content != nullptr)
941 {
942 1 char* pos = content;
943
944
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 times.
5 while (pos[0] != '\0')
945 {
946 4 string stdinclude;
947
948 do
949 {
950
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')
951 {
952
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 stdinclude += pos[0];
953 }
954 30 pos++;
955
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');
956
957
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 strip_whitespace(stdinclude);
958
959
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (stdinclude != "")
960 {
961
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))
962 {
963
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;
964 }
965
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));
966 }
967 4 }
968
969 1 free(content);
970 }
971 4 }
972
973 285 void parse_std_defines(const char* textfile)
974 {
975
976 // RPG Hacker: add built-in defines.
977 // (They're not really standard defines, but I was lazy and this was
978 // one convenient place for doing it).
979 285 builtindefines.create("assembler") = "asar";
980
6/9
✓ Branch 0 taken 282 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 127 times.
✓ Branch 3 taken 155 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 155 times.
✗ Branch 8 not taken.
285 builtindefines.create("assembler_ver") = dec(get_version_int());
981
4/7
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 158 times.
✓ Branch 2 taken 127 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 158 times.
✗ Branch 6 not taken.
285 builtindefines.create("assembler_time") = dec(time(nullptr));
982
983
2/2
✓ Branch 0 taken 281 times.
✓ Branch 1 taken 4 times.
285 if(textfile == nullptr) return;
984
985 4 char* content = readfilenative(textfile);
986
987
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (content != nullptr)
988 {
989 1 char* pos = content;
990
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 times.
6 while (*pos != 0) {
991 5 string define_name;
992 5 string define_val;
993
994
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') {
995
1/3
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
24 if(*pos == '\r') { pos++; continue; }
996
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 define_name += *pos;
997 24 pos++;
998 }
999
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 =
1000
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') {
1001
1/3
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
13 if(*pos == '\r') { pos++; continue; }
1002
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 define_val += *pos;
1003 13 pos++;
1004 }
1005
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 if (*pos != 0)
1006 5 pos++; // skip \n
1007 // clean define_name
1008
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 strip_whitespace(define_name);
1009
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 define_name.strip_prefix('!'); // remove leading ! if present
1010
1011
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 if (define_name == "")
1012 {
1013
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (define_val == "")
1014 {
1015 1 continue;
1016 }
1017
1018 throw_err_null(pass, err_stddefines_no_identifier);
1019 }
1020
1021
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)) throw_err_null(pass, err_cmdl_define_invalid, "stddefines.txt", define_name.data());
1022
1023 // clean define_val
1024 4 const char* defval = define_val.data();
1025 4 string cleaned_defval;
1026
1027
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 if (*defval == 0) {
1028 // no value
1029
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)) throw_err_null(pass, err_cmdl_define_override, "Std define", define_name.data());
1030
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) = "";
1031 2 continue;
1032 }
1033
1034
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
1035
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
2 if (*defval == '"') {
1036 1 defval++; // skip opening quote
1037
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)
1038
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 cleaned_defval += *defval++;
1039
1040
1/3
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (*defval == 0) {
1041 throw_err_null(pass, err_mismatched_quotes);
1042 }
1043 1 defval++; // skip closing quote
1044
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
1045
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')
1046 throw_err_null(pass, err_stddefine_after_closing_quote);
1047
1048
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)) throw_err_null(pass, err_cmdl_define_override, "Std define", define_name.data());
1049
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;
1050 1 continue;
1051 }
1052 else
1053 {
1054 // slightly hacky way to remove trailing whitespace
1055
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
1056
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);
1057 1 defval_end--;
1058
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--;
1059
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));
1060
1061
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)) throw_err_null(pass, err_cmdl_define_override, "Std define", define_name.data());
1062
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;
1063 1 continue;
1064 1 }
1065
1066 5 }
1067 1 free(content);
1068 }
1069 }
1070
1071 bool checksum_fix_enabled = true;
1072 bool force_checksum_fix = false;
1073
1074 #define cfree(x) free((void*)x)
1075 138 static void clearmacro(const string & key, macrodata* & macro)
1076 {
1077 (void)key;
1078 138 freemacro(macro);
1079 138 }
1080
1081 326 static void clearfile(const string & key, sourcefile& filecontent)
1082 {
1083 (void)key;
1084 326 cfree(filecontent.data);
1085 326 cfree(filecontent.contents);
1086 326 }
1087 #undef cfree
1088
1089 858 static void adddefine(const string & key, string & value)
1090 {
1091
2/3
✓ Branch 0 taken 381 times.
✓ Branch 1 taken 477 times.
✗ Branch 2 not taken.
858 if (!defines.exists(key)) defines.create(key) = value;
1092 858 }
1093
1094 1 string create_symbols_file(string format, uint32_t romCrc){
1095 1 string symbolfile;
1096
1097 1 std::vector<std::pair<unsigned int, const char*>> all_labels;
1098
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 labels.each([&all_labels](const string& key, snes_label& label) {
1099
2/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
2 all_labels.push_back(std::make_pair(label.pos, key.data()));
1100 2 });
1101
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 std::sort(all_labels.begin(), all_labels.end(),
1102 1 [](auto& l, auto& r) {
1103
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (l.first == r.first)
1104 return strcmp(l.second, r.second) < 0;
1105 1 return l.first < r.first;
1106 });
1107
1108
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 format = lower(format);
1109
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(format == "wla")
1110 {
1111
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 symbolfile = "; wla symbolic information file\n";
1112
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 symbolfile += "; generated by asar\n";
1113
1114
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 symbolfile += "\n[labels]\n";
1115
2/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
3 for (auto& p : all_labels) {
1116 2 char buffer[10];
1117
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 std::snprintf(buffer, sizeof(buffer), "%02X:%04X ", (p.first >> 16) & 0xFF, p.first & 0xFFFF);
1118
1119
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 symbolfile += buffer;
1120
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 symbolfile += p.second;
1121
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 symbolfile += "\n";
1122 }
1123
1124
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 symbolfile += "\n[source files]\n";
1125 1 const autoarray<AddressToLineMapping::FileInfo>& addrToLineFileList = addressToLineMapping.getFileList();
1126
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
2 for (int i = 0; i < addrToLineFileList.count; ++i)
1127 {
1128 1 char addrToFileListStr[256];
1129 1 snprintf(addrToFileListStr, 256, "%.4x %.8x %s\n",
1130 i,
1131
2/5
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 addrToLineFileList[i].fileCrc,
1132
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 addrToLineFileList[i].filename.data()
1133 );
1134
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 symbolfile += addrToFileListStr;
1135 }
1136
1137
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 symbolfile += "\n[rom checksum]\n";
1138 {
1139 1 char romCrcStr[32];
1140
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 snprintf(romCrcStr, 32, "%.8x\n",
1141 romCrc
1142 );
1143
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 symbolfile += romCrcStr;
1144 }
1145
1146
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 symbolfile += "\n[addr-to-line mapping]\n";
1147 1 const autoarray<AddressToLineMapping::AddrToLineInfo>& addrToLineInfo = addressToLineMapping.getAddrToLineInfo();
1148
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
4 for (int i = 0; i < addrToLineInfo.count; ++i)
1149 {
1150 3 char addrToLineStr[32];
1151 snprintf(addrToLineStr, 32, "%.2x:%.4x %.4x:%.8x\n",
1152
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 (addrToLineInfo[i].addr & 0xFF0000) >> 16,
1153
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 addrToLineInfo[i].addr & 0xFFFF,
1154
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 addrToLineInfo[i].fileIdx & 0xFFFF,
1155
1/5
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
3 addrToLineInfo[i].line & 0xFFFFFFFF
1156 );
1157
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 symbolfile += addrToLineStr;
1158 }
1159
1160 }
1161 else if (format == "nocash")
1162 {
1163 symbolfile = ";no$sns symbolic information file\n";
1164 symbolfile += ";generated by asar\n";
1165 symbolfile += "\n";
1166 for (auto& p : all_labels) {
1167 char buffer[10];
1168 std::snprintf(buffer, sizeof(buffer), "%08X ", p.first & 0xFFFFFF);
1169
1170 symbolfile += buffer;
1171 symbolfile += p.second;
1172 symbolfile += "\n";
1173 }
1174 }
1175 1 return symbolfile;
1176 1 }
1177
1178
1179 2 bool in_top_level_file()
1180 {
1181 2 int num_files = 0;
1182
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 for (int i = (int)callstack.size()-1; i >= 0; --i)
1183 {
1184
3/3
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
6 if (callstack[i].type == callstack_entry_type::FILE)
1185 {
1186 2 num_files++;
1187
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (num_files > 1) break;
1188 }
1189 }
1190 2 return (num_files <= 1);
1191 }
1192
1193 17050 const char* get_current_file_name()
1194 {
1195
2/2
✓ Branch 0 taken 48426 times.
✓ Branch 1 taken 840 times.
49266 for (int i = (int)callstack.size()-1; i >= 0; --i)
1196 {
1197
3/3
✓ Branch 0 taken 8078 times.
✓ Branch 1 taken 24186 times.
✓ Branch 2 taken 16162 times.
48426 if (callstack[i].type == callstack_entry_type::FILE)
1198 16210 return callstack[i].content;
1199 }
1200 840 return nullptr;
1201 }
1202
1203 9038 int get_current_line()
1204 {
1205
2/2
✓ Branch 0 taken 17868 times.
✓ Branch 1 taken 11 times.
17879 for (int i = (int)callstack.size()-1; i >= 0; --i)
1206 {
1207
3/3
✓ Branch 0 taken 4497 times.
✓ Branch 1 taken 8934 times.
✓ Branch 2 taken 4437 times.
17868 if (callstack[i].type == callstack_entry_type::LINE) return callstack[i].lineno;
1208 }
1209 11 return -1;
1210 }
1211
1212 268 const char* get_current_block()
1213 {
1214
2/2
✓ Branch 0 taken 263 times.
✓ Branch 1 taken 11 times.
274 for (int i = (int)callstack.size()-1; i >= 0; --i)
1215 {
1216
9/9
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 133 times.
✓ Branch 2 taken 127 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 127 times.
✓ Branch 5 taken 107 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 130 times.
✓ Branch 8 taken 3 times.
263 if (callstack[i].type == callstack_entry_type::LINE || callstack[i].type == callstack_entry_type::BLOCK) return callstack[i].content;
1217 }
1218 11 return nullptr;
1219 }
1220
1221
1222 288 void reseteverything()
1223 {
1224 288 string str;
1225 288 labels.reset();
1226 288 defines.reset();
1227
1/2
✓ Branch 0 taken 288 times.
✗ Branch 1 not taken.
288 builtindefines.each(adddefine);
1228
1/2
✓ Branch 0 taken 288 times.
✗ Branch 1 not taken.
288 clidefines.each(adddefine);
1229 288 structs.reset();
1230
1231
2/3
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
288 macros.each(clearmacro);
1232 288 macros.reset();
1233
1234
1/2
✓ Branch 0 taken 288 times.
✗ Branch 1 not taken.
288 filecontents.each(clearfile);
1235 288 filecontents.reset();
1236
1237 288 writtenblocks.reset();
1238
1239 288 optimizeforbank=-1;
1240 288 optimize_dp = optimize_dp_flag::ALWAYS;
1241 288 dp_base = 0;
1242 288 optimize_address = optimize_address_flag::MIRRORS;
1243
1244
1/2
✓ Branch 0 taken 288 times.
✗ Branch 1 not taken.
288 closecachedfiles();
1245
1246 288 incsrcdepth=0;
1247 288 label_counter = 0;
1248 288 errored = false;
1249 288 checksum_fix_enabled = true;
1250 288 force_checksum_fix = false;
1251
1252 288 in_macro_def = 0;
1253
1254 288 callstack.clear();
1255 288 simple_callstacks = true;
1256 448 }
1257