asar coverage - build #184


src/asar/
File: src/asar/main.cpp
Date: 2024-01-29 01:23:27
Lines:
678/719
94.3%
Functions:
37/38
97.4%
Branches:
782/1121
69.8%

Line Branch Exec Source
1 // "because satanism is best defeated by summoning a bigger satan"
2 // ~Alcaro, 2019 (discussing Asar)
3 #include "addr2line.h"
4 #include "asar.h"
5 #include "virtualfile.h"
6 #include "platform/file-helpers.h"
7 #include "assembleblock.h"
8 #include "asar_math.h"
9 #include "macro.h"
10 #include <ctime>
11 // randomdude999: remember to also update the .rc files (in res/windows/) when changing this.
12 // Couldn't find a way to automate this without shoving the version somewhere in the CMake files
13 const int asarver_maj=2;
14 const int asarver_min=0;
15 const int asarver_bug=0;
16 const bool asarver_beta=true;
17
18 #ifdef _I_RELEASE
19 extern char blockbetareleases[(!asarver_beta)?1:-1];
20 #endif
21 #ifdef _I_DEBUG
22 extern char blockreleasedebug[(asarver_beta)?1:-1];
23 #endif
24
25 unsigned const char * romdata_r;
26 int romlen_r;
27
28 int pass;
29
30 int optimizeforbank=-1;
31 int optimize_dp = optimize_dp_flag::ALWAYS;
32 int dp_base = 0;
33 int optimize_address = optimize_address_flag::MIRRORS;
34
35 autoarray<callstack_entry> callstack;
36
37 bool errored=false;
38 bool ignoretitleerrors=false;
39
40 volatile int recursioncount=0;
41
42 virtual_filesystem* filesystem = nullptr;
43
44 AddressToLineMapping addressToLineMapping;
45
46 566 int get_version_int()
47 {
48 566 return asarver_maj * 10000 + asarver_min * 100 + asarver_bug;
49 }
50
51 66 bool setmapper()
52 {
53 33 int maxscore=-99999;
54 33 mapper_t bestmap=lorom;
55 66 mapper_t maps[]={lorom, hirom, exlorom, exhirom};
56
2/2
✓ Branch 0 taken 264 times.
✓ Branch 1 taken 66 times.
330 for (size_t mapid=0;mapid<sizeof(maps)/sizeof(maps[0]);mapid++)
57 {
58 264 mapper=maps[mapid];
59 132 int score=0;
60 132 int highbits=0;
61 132 bool foundnull=false;
62
2/2
✓ Branch 0 taken 5544 times.
✓ Branch 1 taken 264 times.
5808 for (int i=0;i<21;i++)
63 {
64 5544 unsigned char c=romdata[snestopc(0x00FFC0+i)];
65
3/4
✓ Branch 0 taken 2000 times.
✓ Branch 1 taken 3544 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2000 times.
5544 if (foundnull && c) score-=4;//according to some documents, NUL terminated names are possible - but they shouldn't appear in the middle of the name
66
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5544 times.
5544 if (c>=128) highbits++;
67
2/2
✓ Branch 0 taken 960 times.
✓ Branch 1 taken 4584 times.
5544 else if (is_upper(c)) score+=3;
68
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 4200 times.
4584 else if (c==' ') score+=2;
69
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4200 times.
4200 else if (is_digit(c)) score+=1;
70
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4200 times.
4200 else if (is_lower(c)) score+=1;
71
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4200 times.
4200 else if (c=='-') score+=1;
72
2/2
✓ Branch 0 taken 2100 times.
✓ Branch 1 taken 2100 times.
4200 else if (!c) foundnull=true;
73 else score-=3;
74 }
75
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 264 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
264 if (highbits>0 && highbits<=14) score-=21;//high bits set on some, but not all, bytes = unlikely to be a ROM
76
4/4
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 198 times.
✓ Branch 2 taken 99 times.
✓ Branch 3 taken 33 times.
297 if ((romdata[snestopc(0x00FFDE)]^romdata[snestopc(0x00FFDC)])!=0xFF ||
77
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
165 (romdata[snestopc(0x00FFDF)]^romdata[snestopc(0x00FFDD)])!=0xFF) score=-99999;//checksum doesn't match up to 0xFFFF? Not a ROM.
78 //too lazy to check the real checksum
79
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 198 times.
264 if (score>maxscore)
80 {
81 33 maxscore=score;
82 33 bestmap=mapper;
83 }
84 }
85 66 mapper=bestmap;
86
87 //detect oddball mappers
88 66 int mapperbyte=romdata[snestopc(0x00FFD5)];
89 66 int romtypebyte=romdata[snestopc(0x00FFD6)];
90
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
66 if (mapper==lorom)
91 {
92
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
66 if (mapperbyte==0x23 && (romtypebyte==0x32 || romtypebyte==0x34 || romtypebyte==0x35)) mapper=sa1rom;
93 }
94 66 return (maxscore>=0);
95 }
96
97
98 bool simple_callstacks = true;
99
100 // Shortens target_path to a relative path, but only if it resides
101 // within base_path or a child directory of it.
102 24498 string shorten_to_relative_path(const char* base_path, const char* target_path)
103 {
104
2/2
✓ Branch 0 taken 15909 times.
✓ Branch 1 taken 8589 times.
24498 if (stribegin(target_path, base_path)) target_path += strlen(base_path);
105 24498 return target_path;
106 }
107
108 24498 string get_top_level_directory()
109 {
110 9039 string top_level_file_dir;
111
1/2
✓ Branch 0 taken 24498 times.
✗ Branch 1 not taken.
24498 for (int i = 0; i < callstack.count; ++i)
112 {
113
2/4
✓ Branch 0 taken 24498 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9039 times.
✗ Branch 3 not taken.
24498 if (callstack[i].type == callstack_entry_type::FILE)
114 {
115
3/6
✓ Branch 0 taken 24498 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9039 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9039 times.
✗ Branch 5 not taken.
24498 top_level_file_dir = dir(callstack[i].content);
116 24498 break;
117 }
118 }
119 24498 return top_level_file_dir;
120 }
121
122 24414 string generate_call_details_string(const char* current_block, const char* current_call, int indentation, bool add_lines)
123 {
124 8997 string e;
125
4/4
✓ Branch 0 taken 15480 times.
✓ Branch 1 taken 8934 times.
✓ Branch 2 taken 63 times.
✓ Branch 3 taken 25 times.
24414 if (current_block != nullptr || current_call != nullptr)
126 {
127 8972 string indent;
128
3/4
✓ Branch 0 taken 7907 times.
✓ Branch 1 taken 16457 times.
✓ Branch 2 taken 2883 times.
✗ Branch 3 not taken.
24364 if (add_lines) indent += "|";
129
4/4
✓ Branch 0 taken 97456 times.
✓ Branch 1 taken 15392 times.
✓ Branch 2 taken 35888 times.
✓ Branch 3 taken 8972 times.
121820 for (; indentation > 0; --indentation) indent += " ";
130
131
8/14
✓ Branch 0 taken 24238 times.
✓ Branch 1 taken 126 times.
✓ Branch 2 taken 8909 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8909 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8909 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8909 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 8909 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 8909 times.
✗ Branch 13 not taken.
39693 if (current_block != nullptr) e += STR "\n"+indent+"in block: ["+current_block+"]";
132
8/14
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 24238 times.
✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 63 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 63 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 63 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 63 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 63 times.
✗ Branch 13 not taken.
24427 if (current_call != nullptr) e += STR "\n"+indent+"in macro call: [%"+current_call+"]";
133 24364 }
134 24414 return e;
135 }
136
137 24498 string get_pretty_filename(const char* current_file)
138 {
139 // RPG Hacker: One could make an argument that we shouldn't shorten paths
140 // here, since some IDEs support jumping to files by double-clicking their
141 // paths. However, AFAIK, no IDE supports this for Asar yet, and if it's
142 // ever desired, we could just make it a command line option. Until then,
143 // I think it's more important to optimize for pretty command line display.
144
2/4
✓ Branch 0 taken 9039 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9039 times.
✗ Branch 3 not taken.
33537 return shorten_to_relative_path(get_top_level_directory(), current_file);
145 }
146
147 8684 string generate_filename_and_line(const char* current_file, int current_line_no)
148 {
149
1/2
✓ Branch 0 taken 3273 times.
✗ Branch 1 not taken.
11957 return STR current_file
150
13/20
✓ Branch 0 taken 8648 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 8648 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 8648 times.
✓ Branch 5 taken 18 times.
✓ Branch 6 taken 3255 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 18 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3273 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3255 times.
✓ Branch 13 taken 18 times.
✓ Branch 14 taken 3255 times.
✓ Branch 15 taken 18 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
20641 + (current_line_no>=0?STR ":"+dec(current_line_no+1):"");
151 }
152
153 7907 string format_stack_line(const printable_callstack_entry& entry, int stack_frame_index)
154 {
155
1/2
✓ Branch 0 taken 2883 times.
✗ Branch 1 not taken.
2883 string indent = "\n| ";
156
2/4
✓ Branch 0 taken 2883 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2883 times.
✗ Branch 3 not taken.
7907 indent += dec(stack_frame_index);
157
1/2
✓ Branch 0 taken 2883 times.
✗ Branch 1 not taken.
7907 indent += ": ";
158 // RPG Hacker: We'll probably never have a call stack in the
159 // hundreds even, so this very specific, lazy solution suffices.
160
3/4
✓ Branch 0 taken 248 times.
✓ Branch 1 taken 7659 times.
✓ Branch 2 taken 124 times.
✗ Branch 3 not taken.
7907 if (stack_frame_index < 100) indent += " ";
161
3/4
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 2939 times.
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
3007 if (stack_frame_index < 10) indent += " ";
162 return indent
163
2/4
✓ Branch 0 taken 2883 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2883 times.
✗ Branch 3 not taken.
15814 + generate_filename_and_line(entry.prettypath, entry.lineno)
164
1/2
✓ Branch 0 taken 2883 times.
✗ Branch 1 not taken.
13673 + entry.details;
165 7907 }
166
167 23721 void push_stack_line(autoarray<printable_callstack_entry>* out, const char* current_file, const char* current_block, const char* current_call, int current_line_no, int indentation, bool add_lines)
168 {
169 8649 printable_callstack_entry new_entry;
170
1/2
✓ Branch 0 taken 8649 times.
✗ Branch 1 not taken.
8649 new_entry.fullpath = current_file;
171
2/4
✓ Branch 0 taken 23721 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8649 times.
✗ Branch 3 not taken.
23721 new_entry.prettypath = get_pretty_filename(current_file);
172 23721 new_entry.lineno = current_line_no;
173
2/4
✓ Branch 0 taken 8649 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8649 times.
✗ Branch 3 not taken.
38793 new_entry.details = generate_call_details_string(current_block, current_call, indentation, add_lines).raw();
174
1/2
✓ Branch 0 taken 8649 times.
✗ Branch 1 not taken.
23721 out->append(new_entry);
175 23721 }
176
177 694 void get_current_line_details(string* location, string* details, bool exclude_block)
178 {
179 349 const char* current_file = nullptr;
180 349 const char* current_block = nullptr;
181 349 const char* current_call = nullptr;
182 349 int current_line_no = -1;
183
2/2
✓ Branch 0 taken 2316 times.
✓ Branch 1 taken 1 times.
2317 for (int i = callstack.count-1; i >= 0 ; --i)
184 {
185
3/5
✓ Branch 0 taken 693 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 657 times.
✓ Branch 3 taken 966 times.
✗ Branch 4 not taken.
2316 switch (callstack[i].type)
186 {
187 348 case callstack_entry_type::FILE:
188 348 current_file = callstack[i].content;
189
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 669 times.
693 if (exclude_block) current_block = nullptr;
190
3/6
✓ Branch 0 taken 348 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 348 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 348 times.
✗ Branch 5 not taken.
693 *location = generate_filename_and_line(get_pretty_filename(current_file), current_line_no);
191
2/4
✓ Branch 0 taken 348 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 348 times.
✗ Branch 3 not taken.
693 *details = generate_call_details_string(current_block, current_call, 4, false);
192 693 return;
193 case callstack_entry_type::MACRO_CALL:
194 if (current_call == nullptr) current_call = callstack[i].content;
195 break;
196 657 case callstack_entry_type::LINE:
197
3/4
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 489 times.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
657 if (current_block == nullptr && current_call == nullptr) current_block = callstack[i].content;
198
1/2
✓ Branch 0 taken 657 times.
✗ Branch 1 not taken.
984 if (current_line_no == -1) current_line_no = callstack[i].lineno;
199 330 break;
200 966 case callstack_entry_type::BLOCK:
201
2/2
✓ Branch 0 taken 489 times.
✓ Branch 1 taken 477 times.
966 if (current_block == nullptr) current_block = callstack[i].content;
202 486 break;
203 }
204 }
205 1 *location = "";
206 1 *details = "";
207 }
208
209 694 void get_full_printable_callstack(autoarray<printable_callstack_entry>* out, int indentation, bool add_lines)
210 {
211 694 out->reset();
212 349 const char* current_file = nullptr;
213 349 const char* current_block = nullptr;
214 349 const char* current_call = nullptr;
215 349 int current_line_no = -1;
216
2/2
✓ Branch 0 taken 97326 times.
✓ Branch 1 taken 694 times.
98020 for (int i = 0; i < callstack.count; ++i)
217 {
218
4/5
✓ Branch 0 taken 24414 times.
✓ Branch 1 taken 126 times.
✓ Branch 2 taken 24378 times.
✓ Branch 3 taken 48408 times.
✗ Branch 4 not taken.
97326 switch (callstack[i].type)
219 {
220 24414 case callstack_entry_type::FILE:
221
2/2
✓ Branch 0 taken 23721 times.
✓ Branch 1 taken 693 times.
24414 if (current_file != nullptr)
222 {
223 23721 push_stack_line(out, current_file, current_block, current_call, current_line_no, indentation, add_lines);
224 }
225 8997 current_file = callstack[i].content;
226 8997 current_block = nullptr;
227 8997 current_call = nullptr;
228 8997 current_line_no = -1;
229 24414 break;
230 126 case callstack_entry_type::MACRO_CALL:
231 63 current_block = nullptr;
232 63 current_call = callstack[i].content;
233 126 break;
234 8979 case callstack_entry_type::LINE:
235 24378 current_line_no = callstack[i].lineno;
236 8979 current_block = callstack[i].content;
237 24378 break;
238 17784 case callstack_entry_type::BLOCK:
239 17784 current_block = callstack[i].content;
240 48408 break;
241 }
242 }
243 694 }
244
245 230 string get_full_callstack()
246 {
247 115 autoarray<printable_callstack_entry> printable_stack;
248
1/2
✓ Branch 0 taken 230 times.
✗ Branch 1 not taken.
230 get_full_printable_callstack(&printable_stack, 12, true);
249
250 115 string e;
251
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 180 times.
230 if (printable_stack.count > 0)
252 {
253
1/2
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
50 e += "\nFull call stack:";
254
2/2
✓ Branch 0 taken 7907 times.
✓ Branch 1 taken 50 times.
7957 for (int i = printable_stack.count-1; i >= 0; --i)
255 {
256
3/6
✓ Branch 0 taken 2883 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2883 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2883 times.
✗ Branch 5 not taken.
7907 e += format_stack_line(printable_stack[i], i);
257 }
258 }
259 345 return e;
260 230 }
261
262 // RPG Hacker: This function essetially replicates classic Asar behavior
263 // of only printing a single macro call below the current level.
264 464 string get_simple_callstack()
265 {
266 int i;
267 234 const char* current_call = nullptr;
268
2/2
✓ Branch 0 taken 64552 times.
✓ Branch 1 taken 380 times.
64932 for (i = callstack.count-1; i >= 0 ; --i)
269 {
270
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 64468 times.
64552 if (callstack[i].type == callstack_entry_type::MACRO_CALL)
271 {
272 42 current_call = callstack[i].content;
273 84 break;
274 }
275 }
276
277 234 const char* current_file = nullptr;
278 234 int current_line_no = -1;
279
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 380 times.
464 if (current_call != nullptr)
280 {
281 42 bool stop = false;
282
1/2
✓ Branch 0 taken 336 times.
✗ Branch 1 not taken.
336 for (int j = i-1; j >= 0 ; --j)
283 {
284
3/5
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✓ Branch 3 taken 168 times.
✗ Branch 4 not taken.
336 switch (callstack[j].type)
285 {
286 84 case callstack_entry_type::FILE:
287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
84 if (current_file != nullptr)
288 {
289 stop = true;
290 break;
291 }
292 42 current_file = callstack[j].content;
293 84 break;
294 case callstack_entry_type::MACRO_CALL:
295 stop = true;
296 break;
297 84 case callstack_entry_type::LINE:
298
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
126 if (current_line_no == -1) current_line_no = callstack[j].lineno;
299 42 break;
300 84 case callstack_entry_type::BLOCK:
301 84 break;
302 }
303
304
3/4
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
336 if (current_file != nullptr && current_line_no != -1) stop = true;
305
306
2/2
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 126 times.
294 if (stop) break;
307 }
308 }
309
310 234 string e;
311
3/4
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 380 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
464 if (current_call != nullptr && current_file != nullptr)
312 {
313
4/8
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 42 times.
✗ Branch 7 not taken.
168 e += STR "\n called from: " + generate_filename_and_line(get_pretty_filename(current_file), current_line_no)
314
4/8
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 42 times.
✗ Branch 7 not taken.
168 + ": [%" + current_call + "]";
315 }
316 464 return e;
317 }
318
319 694 string get_callstack()
320 {
321
2/2
✓ Branch 0 taken 464 times.
✓ Branch 1 taken 230 times.
694 if (simple_callstacks)
322 464 return get_simple_callstack();
323 else
324 230 return get_full_callstack();
325 }
326
327
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
99 asar_error_id vfile_error_to_error_id(virtual_file_error vfile_error)
328 {
329
2/5
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
54 switch (vfile_error)
330 {
331 18 case vfe_doesnt_exist:
332 18 return error_id_file_not_found;
333 case vfe_access_denied:
334 return error_id_failed_to_open_file_access_denied;
335 36 case vfe_not_regular_file:
336 36 return error_id_failed_to_open_not_regular_file;
337 case vfe_unknown:
338 case vfe_none:
339 case vfe_num_errors:
340 return error_id_failed_to_open_file;
341 }
342
343 return error_id_failed_to_open_file;
344 }
345
346 99 virtual_file_error asar_get_last_io_error()
347 {
348
1/2
✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
99 if (filesystem != nullptr)
349 {
350 99 return filesystem->get_last_error();
351 }
352
353 return vfe_unknown;
354 }
355
356 static bool freespaced;
357 2278 static int getlenforlabel(snes_label thislabel, bool exists)
358 {
359 2278 unsigned int bank = thislabel.pos>>16;
360 2278 unsigned int word = thislabel.pos&0xFFFF;
361 1141 bool lblfreespace = thislabel.freespace_id > 0;
362 unsigned int relaxed_bank;
363
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 2224 times.
2278 if(optimizeforbank >= 0) {
364 54 relaxed_bank = optimizeforbank;
365 } else {
366
2/2
✓ Branch 0 taken 1792 times.
✓ Branch 1 taken 432 times.
2224 if(freespaceid == 0) {
367 1792 relaxed_bank = snespos >> 16;
368 } else {
369 432 int target_bank = freespaces[freespaceid].bank;
370
2/2
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 216 times.
432 if(target_bank == -2) relaxed_bank = 0;
371
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 72 times.
144 else if(target_bank == -1) relaxed_bank = 0x40;
372 else relaxed_bank = target_bank;
373 }
374 }
375
2/2
✓ Branch 0 taken 1137 times.
✓ Branch 1 taken 1141 times.
2278 if (!exists)
376 {
377 210 return 2;
378 }
379
7/8
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1822 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✓ Branch 7 taken 9 times.
1858 else if((optimize_dp == optimize_dp_flag::RAM) && bank == 0x7E && (word-dp_base < 0x100) && !lblfreespace)
380 {
381 9 return 1;
382 }
383
8/10
✓ Branch 0 taken 1252 times.
✓ Branch 1 taken 588 times.
✓ Branch 2 taken 1252 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1252 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 262 times.
✓ Branch 7 taken 990 times.
✓ Branch 8 taken 133 times.
✓ Branch 9 taken 129 times.
1840 else if(optimize_dp == optimize_dp_flag::ALWAYS && (bank == 0x7E || !(bank & 0x40)) && (word-dp_base < 0x100) && !lblfreespace)
384 {
385 31 return 1;
386 }
387 1782 else if (
388 // if we should optimize ram accesses...
389
4/4
✓ Branch 0 taken 1593 times.
✓ Branch 1 taken 189 times.
✓ Branch 2 taken 702 times.
✓ Branch 3 taken 135 times.
1782 (optimize_address == optimize_address_flag::RAM || optimize_address == optimize_address_flag::MIRRORS)
390 // and we're in a bank with ram mirrors... (optimizeforbank=0x7E is checked later)
391
2/2
✓ Branch 0 taken 1416 times.
✓ Branch 1 taken 96 times.
1512 && !(relaxed_bank & 0x40)
392 // and the label is in low RAM
393
5/6
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 1362 times.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
1416 && bank == 0x7E && word < 0x2000 && !lblfreespace)
394 {
395 27 return 2;
396 }
397
2/2
✓ Branch 0 taken 693 times.
✓ Branch 1 taken 171 times.
1728 else if (
398 // if we should optimize mirrors...
399
2/2
✓ Branch 0 taken 693 times.
✓ Branch 1 taken 171 times.
864 optimize_address == optimize_address_flag::MIRRORS
400 // we're in a bank with ram mirrors...
401
2/2
✓ Branch 0 taken 1308 times.
✓ Branch 1 taken 78 times.
1386 && !(relaxed_bank & 0x40)
402 // and the label is in a mirrored section
403
5/6
✓ Branch 0 taken 1308 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 753 times.
✓ Branch 3 taken 555 times.
✓ Branch 4 taken 36 times.
✓ Branch 5 taken 99 times.
1308 && !(bank & 0x40) && word < 0x8000 && !lblfreespace)
404 {
405 36 return 2;
406 }
407
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 1602 times.
1656 else if (optimizeforbank>=0)
408 {
409 // if optimizing for a specific bank:
410 // if the label is in freespace, never optimize
411
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 27 times.
54 if (thislabel.freespace_id > 0) return 3;
412
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 27 times.
54 else if (bank==(unsigned int)optimizeforbank) return 2;
413 36 else return 3;
414 }
415
4/4
✓ Branch 0 taken 1140 times.
✓ Branch 1 taken 462 times.
✓ Branch 2 taken 162 times.
✓ Branch 3 taken 978 times.
1602 else if (thislabel.freespace_id > 0 || freespaceid > 0)
416 {
417 // optimize only if the label is in the same freespace
418 // TODO: check whether they're pinned to the same bank
419
2/2
✓ Branch 0 taken 312 times.
✓ Branch 1 taken 312 times.
624 if (thislabel.freespace_id != freespaceid) return 3;
420 96 else return 2;
421 }
422
2/2
✓ Branch 0 taken 489 times.
✓ Branch 1 taken 489 times.
978 else if ((int)bank != snespos >> 16){ return 3; }
423 900 else { return 2;}
424 }
425
426
427 609 bool is_hex_constant(const char* str){
428
2/2
✓ Branch 0 taken 522 times.
✓ Branch 1 taken 87 times.
609 if (*str=='$')
429 {
430 522 str++;
431
2/2
✓ Branch 0 taken 1512 times.
✓ Branch 1 taken 522 times.
2034 while(is_xdigit(*str)) {
432 1512 str++;
433 }
434
2/2
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 261 times.
522 if(*str=='\0'){
435 261 return true;
436 }
437 }
438 45 return false;
439 }
440
441 9195 int getlen(const char * orgstr, bool optimizebankextraction)
442 {
443 9195 const char * str=orgstr;
444 9195 freespaced=false;
445
446 9195 const char* posneglabel = str;
447
1/2
✓ Branch 0 taken 4602 times.
✗ Branch 1 not taken.
9195 string posnegname = posneglabelname(&posneglabel, false);
448
449
3/4
✓ Branch 0 taken 9195 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 4596 times.
9195 if (posnegname.length() > 0)
450 {
451
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (*posneglabel != '\0') goto notposneglabel;
452
453
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
10 if (!pass) return 2;
454 4 snes_label label_data;
455 // RPG Hacker: Umm... what kind of magic constant is this?
456 4 label_data.pos = 31415926;
457
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 bool found = labelval(posnegname, &label_data);
458
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 return getlenforlabel(label_data, found);
459 }
460 9189 notposneglabel:
461 4596 int len=0;
462
2/2
✓ Branch 0 taken 9609 times.
✓ Branch 1 taken 9189 times.
18798 while (*str)
463 {
464 4806 int thislen=0;
465 9609 bool maybebankextraction=(str==orgstr);
466
2/2
✓ Branch 0 taken 7002 times.
✓ Branch 1 taken 2607 times.
9609 if (*str=='$')
467 {
468 7002 str++;
469 int i;
470
2/2
✓ Branch 0 taken 19008 times.
✓ Branch 1 taken 7002 times.
26010 for (i=0;is_xdigit(str[i]);i++);
471 //if (i&1) warn(S dec(i)+"-digit hex value");//blocked in getnum instead
472 7002 thislen=(i+1)/2;
473 7002 str+=i;
474 }
475
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2607 times.
2607 else if (*str=='%')
476 {
477 str++;
478 int i;
479 for (i=0;str[i]=='0' || str[i]=='1';i++);
480 //if (i&7) warn(S dec(i)+"-digit binary value");
481 thislen=(i+7)/8;
482 str+=i;
483 }
484
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2607 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2607 else if (str[0]=='\'' && str[2]=='\'')
485 {
486 thislen=1;
487 str+=3;
488 }
489
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 2574 times.
2607 else if (is_digit(*str))
490 {
491 33 int val=strtol(str, const_cast<char**>(&str), 10);
492
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 if (val>=0) thislen=1;
493
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 18 times.
33 if (val>=256) thislen=2;
494
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (val>=65536) thislen=3;
495 }
496
7/8
✓ Branch 0 taken 300 times.
✓ Branch 1 taken 2274 times.
✓ Branch 2 taken 300 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 150 times.
✓ Branch 5 taken 150 times.
✓ Branch 6 taken 1137 times.
✓ Branch 7 taken 150 times.
2574 else if (is_ualpha(*str) || *str=='.' || *str=='?')
497 {
498 1137 snes_label thislabel;
499
1/2
✓ Branch 0 taken 2274 times.
✗ Branch 1 not taken.
2274 bool exists=labelval(&str, &thislabel);
500
1/2
✓ Branch 0 taken 1137 times.
✗ Branch 1 not taken.
2274 thislen=getlenforlabel(thislabel, exists);
501 }
502 300 else str++;
503
4/4
✓ Branch 0 taken 1359 times.
✓ Branch 1 taken 8250 times.
✓ Branch 2 taken 576 times.
✓ Branch 3 taken 210 times.
9609 if (optimizebankextraction && maybebankextraction &&
504
4/6
✓ Branch 0 taken 1149 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1149 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 573 times.
✓ Branch 5 taken 576 times.
1149 (!strcmp(str, ">>16") || !strcmp(str, "/65536") || !strcmp(str, "/$10000")))
505 return 1;
506
2/2
✓ Branch 0 taken 4620 times.
✓ Branch 1 taken 186 times.
4806 if (thislen>len) len=thislen;
507 }
508 4596 return len;
509 9195 }
510
511 struct strcompare {
512 bool operator() (const char * lhs, const char * rhs) const
513 {
514 return strcmp(lhs, rhs)<0;
515 }
516 };
517
518 struct stricompare {
519 bool operator() (const char * lhs, const char * rhs) const
520 {
521 return stricmp(lhs, rhs)<0;
522 }
523 };
524
525 struct sourcefile {
526 char *data;
527 char** contents;
528 int numlines;
529 };
530
531 static assocarr<sourcefile> filecontents;
532 assocarr<string> defines;
533 // needs to be separate because defines is reset between parsing arguments and patching
534 assocarr<string> clidefines;
535 assocarr<string> builtindefines;
536
537 5256 bool validatedefinename(const char * name)
538 {
539
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5256 times.
5256 if (!name[0]) return false;
540
2/2
✓ Branch 0 taken 54744 times.
✓ Branch 1 taken 5256 times.
60000 for (int i = 0;name[i];i++)
541 {
542
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54744 times.
54744 if (!is_ualnum(name[i])) return false;
543 }
544
545 2631 return true;
546 }
547
548 189424 void resolvedefines(string& out, const char * start)
549 {
550
2/2
✓ Branch 0 taken 91598 times.
✓ Branch 1 taken 3 times.
91601 recurseblock rec;
551 91598 const char * here=start;
552
2/2
✓ Branch 0 taken 158132 times.
✓ Branch 1 taken 31286 times.
189418 if (!strchr(here, '!'))
553 {
554
1/2
✓ Branch 0 taken 75943 times.
✗ Branch 1 not taken.
158132 out += here;
555 75943 return;
556 }
557
2/2
✓ Branch 0 taken 213770 times.
✓ Branch 1 taken 31196 times.
244966 while (*here)
558 {
559
4/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 213626 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 126 times.
213770 if (here[0] == '\\' && here[1] == '\\')
560 {
561 // allow using \\ as escape sequence
562
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
18 if (in_macro_def > 0) out += "\\";
563
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
18 out += "\\";
564 18 here += 2;
565 }
566
3/4
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 213626 times.
✓ Branch 2 taken 126 times.
✗ Branch 3 not taken.
213752 else if (here[0] == '\\' && here[1] == '!')
567 {
568 // allow using \! to escape !
569
3/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
126 if (in_macro_def > 0) out += "\\";
570
1/2
✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
126 out+="!";
571 126 here += 2;
572 }
573
2/2
✓ Branch 0 taken 33584 times.
✓ Branch 1 taken 180042 times.
213626 else if (*here=='!')
574 {
575
10/10
✓ Branch 0 taken 16299 times.
✓ Branch 1 taken 17285 times.
✓ Branch 2 taken 10053 times.
✓ Branch 3 taken 6246 times.
✓ Branch 4 taken 7653 times.
✓ Branch 5 taken 2400 times.
✓ Branch 6 taken 360 times.
✓ Branch 7 taken 7293 times.
✓ Branch 8 taken 36 times.
✓ Branch 9 taken 324 times.
33584 bool first=(here==start || (here>=start+4 && here[-1]==' ' && here[-2]==':' && here[-3]==' '));//check if it's the start of a block
576 16810 string defname;
577 33584 here++;
578
579 16810 int depth = 0;
580
2/2
✓ Branch 0 taken 342 times.
✓ Branch 1 taken 33584 times.
33926 for (const char* depth_str = here; *depth_str=='^'; depth_str++)
581 {
582 342 depth++;
583 }
584 33584 here += depth;
585
586
2/2
✓ Branch 0 taken 3960 times.
✓ Branch 1 taken 29624 times.
33584 if (depth != in_macro_def)
587 {
588
1/2
✓ Branch 0 taken 1980 times.
✗ Branch 1 not taken.
3960 out += '!';
589
4/4
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 1980 times.
✓ Branch 2 taken 99 times.
✓ Branch 3 taken 1980 times.
4158 for (int i=0; i < depth; ++i) out += '^';
590
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 3906 times.
3960 if (depth > in_macro_def) asar_throw_error(0, error_type_line, error_id_invalid_depth_resolve, "define", "define", depth, in_macro_def);
591 1953 continue;
592 3906 }
593
594
2/2
✓ Branch 0 taken 324 times.
✓ Branch 1 taken 29300 times.
29624 if (*here=='{')
595 {
596 324 here++;
597 162 string unprocessedname;
598 162 int braces=1;
599 while (true)
600 {
601
2/2
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 3240 times.
3456 if (*here=='{') braces++;
602
2/2
✓ Branch 0 taken 540 times.
✓ Branch 1 taken 2916 times.
3456 if (*here=='}') braces--;
603
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3456 times.
3456 if (!*here) asar_throw_error(0, error_type_line, error_id_mismatched_braces);
604
2/2
✓ Branch 0 taken 1728 times.
✓ Branch 1 taken 1728 times.
3456 if (!braces) break;
605
1/2
✓ Branch 0 taken 1566 times.
✗ Branch 1 not taken.
3132 unprocessedname+=*here++;
606 }
607
1/2
✓ Branch 0 taken 162 times.
✗ Branch 1 not taken.
324 here++;
608
1/2
✓ Branch 0 taken 324 times.
✗ Branch 1 not taken.
324 resolvedefines(defname, unprocessedname);
609
3/4
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 108 times.
324 if (!validatedefinename(defname)) asar_throw_error(0, error_type_line, error_id_invalid_define_name);
610 324 }
611 else
612 {
613
4/4
✓ Branch 0 taken 149899 times.
✓ Branch 1 taken 14632 times.
✓ Branch 2 taken 75032 times.
✓ Branch 3 taken 14668 times.
179199 while (is_ualnum(*here)) defname+=*here++;
614 }
615
616
2/2
✓ Branch 0 taken 15791 times.
✓ Branch 1 taken 13833 times.
29624 if (first)
617 {
618 enum {
619 null,
620 append,
621 expand,
622 domath,
623 setifnotset,
624 } mode;
625 if(0);
626
2/2
✓ Branch 0 taken 1554 times.
✓ Branch 1 taken 14237 times.
15791 else if (stribegin(here, " = ")) { here+=3; mode=null; }
627
2/2
✓ Branch 0 taken 306 times.
✓ Branch 1 taken 13931 times.
14237 else if (stribegin(here, " += ")) { here+=4; mode=append; }
628
2/2
✓ Branch 0 taken 162 times.
✓ Branch 1 taken 13769 times.
13931 else if (stribegin(here, " := ")) { here+=4; mode=expand; }
629
2/2
✓ Branch 0 taken 5778 times.
✓ Branch 1 taken 7991 times.
13769 else if (stribegin(here, " #= ")) { here+=4; mode=domath; }
630
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 7979 times.
7991 else if (stribegin(here, " ?= ")) { here+=4; mode=setifnotset; }
631 7979 else goto notdefineset;
632 3909 string val;
633
2/2
✓ Branch 0 taken 561 times.
✓ Branch 1 taken 7251 times.
7812 if (*here=='"')
634 {
635 561 here++;
636 while (true)
637 {
638
2/2
✓ Branch 0 taken 579 times.
✓ Branch 1 taken 2484 times.
3063 if (*here=='"')
639 {
640
3/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 561 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
579 if (!here[1] || here[1]==' ') break;
641
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 else if (here[1]=='"') here++;
642 else asar_throw_error(0, error_type_line, error_id_broken_define_declaration);
643 }
644
1/2
✓ Branch 0 taken 1251 times.
✗ Branch 1 not taken.
2502 val+=*here++;
645 }
646 561 here++;
647 }
648 else
649 {
650
5/6
✓ Branch 0 taken 49863 times.
✓ Branch 1 taken 3624 times.
✓ Branch 2 taken 49863 times.
✓ Branch 3 taken 3627 times.
✓ Branch 4 taken 24936 times.
✗ Branch 5 not taken.
57114 while (*here && *here!=' ') val+=*here++;
651 }
652 //if (strqchr(val.data(), ';')) *strqchr(val.data(), ';')=0;
653
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 7812 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3909 times.
7812 if (*here && !stribegin(here, " : ")) asar_throw_error(0, error_type_line, error_id_broken_define_declaration);
654 // RPG Hacker: Is it really a good idea to normalize
655 // the content of defines? That kinda violates their
656 // functionality as a string replacement mechanism.
657
1/2
✓ Branch 0 taken 7812 times.
✗ Branch 1 not taken.
7812 val.qnormalize();
658
659 // RPG Hacker: throw an error if we're trying to overwrite built-in defines.
660
4/4
✓ Branch 0 taken 3918 times.
✓ Branch 1 taken 3894 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 3900 times.
7812 if (builtindefines.exists(defname))
661 {
662 18 asar_throw_error(0, error_type_line, error_id_overriding_builtin_define, defname.data());
663 }
664
665
5/6
✓ Branch 0 taken 1536 times.
✓ Branch 1 taken 306 times.
✓ Branch 2 taken 162 times.
✓ Branch 3 taken 5778 times.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
7794 switch (mode)
666 {
667 771 case null:
668 {
669
2/4
✓ Branch 0 taken 1536 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 771 times.
✗ Branch 3 not taken.
1536 defines.create(defname) = val;
670 771 break;
671 }
672 153 case append:
673 {
674
3/4
✓ Branch 0 taken 153 times.
✓ Branch 1 taken 153 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 153 times.
306 if (!defines.exists(defname)) asar_throw_error(0, error_type_line, error_id_define_not_found, defname.data());
675
2/4
✓ Branch 0 taken 153 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 153 times.
✗ Branch 3 not taken.
306 string oldval = defines.find(defname);
676
2/4
✓ Branch 0 taken 306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 153 times.
✗ Branch 3 not taken.
306 val=oldval+val;
677
2/4
✓ Branch 0 taken 306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 153 times.
✗ Branch 3 not taken.
306 defines.create(defname) = val;
678 153 break;
679 306 }
680 81 case expand:
681 {
682 81 string newval;
683
1/2
✓ Branch 0 taken 162 times.
✗ Branch 1 not taken.
162 resolvedefines(newval, val);
684
2/4
✓ Branch 0 taken 162 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 81 times.
✗ Branch 3 not taken.
162 defines.create(defname) = newval;
685 81 break;
686 162 }
687 2889 case domath:
688 {
689 2889 string newval;
690
1/2
✓ Branch 0 taken 5778 times.
✗ Branch 1 not taken.
5778 resolvedefines(newval, val);
691
1/2
✓ Branch 0 taken 5778 times.
✗ Branch 1 not taken.
5778 double num= getnumdouble(newval);
692
4/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 5742 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 18 times.
5778 if (foundlabel && !foundlabel_static) asar_throw_error(0, error_type_line, error_id_define_label_math);
693
3/6
✓ Branch 0 taken 5760 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2880 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2880 times.
✗ Branch 5 not taken.
5760 defines.create(defname) = ftostr(num);
694 2880 break;
695 5778 }
696 6 case setifnotset:
697 {
698
4/8
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
12 if (!defines.exists(defname)) defines.create(defname) = val;
699 6 break;
700 }
701 }
702 7812 }
703 else
704 {
705 13833 notdefineset:
706
5/6
✓ Branch 0 taken 10984 times.
✓ Branch 1 taken 10828 times.
✓ Branch 2 taken 66 times.
✓ Branch 3 taken 10855 times.
✓ Branch 4 taken 66 times.
✗ Branch 5 not taken.
21812 if (!defname) out+="!";
707 else
708 {
709
3/4
✓ Branch 0 taken 10855 times.
✓ Branch 1 taken 10828 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10855 times.
21683 if (!defines.exists(defname)) asar_throw_error(0, error_type_line, error_id_define_not_found, defname.data());
710 else {
711
2/4
✓ Branch 0 taken 10855 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10855 times.
✗ Branch 3 not taken.
21683 string thisone = defines.find(defname);
712
1/2
✓ Branch 0 taken 21683 times.
✗ Branch 1 not taken.
21683 resolvedefines(out, thisone);
713 21683 }
714 }
715 }
716
2/2
✓ Branch 0 taken 14812 times.
✓ Branch 1 taken 1953 times.
33584 }
717
1/2
✓ Branch 0 taken 90153 times.
✗ Branch 1 not taken.
180042 else out+=*here++;
718 }
719
5/8
✓ Branch 0 taken 31196 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 31178 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
31196 if (!confirmquotes(out)) { asar_throw_error(0, error_type_null, error_id_mismatched_quotes); out = ""; }
720
2/2
✓ Branch 0 taken 15610 times.
✓ Branch 1 taken 75943 times.
189418 }
721
722 bool moreonline;
723 bool asarverallowed = false;
724
725 157023 void assembleline(const char * fname, int linenum, const char * line, int& single_line_for_tracker)
726 {
727
1/2
✓ Branch 0 taken 75387 times.
✗ Branch 1 not taken.
75387 recurseblock rec;
728 157023 bool moreonlinetmp=moreonline;
729 // randomdude999: redundant, assemblefile already converted the path to absolute
730 //string absolutepath = filesystem->create_absolute_path("", fname);
731
1/2
✓ Branch 0 taken 75387 times.
✗ Branch 1 not taken.
75387 string absolutepath = fname;
732 157023 single_line_for_tracker = 1;
733 try
734 {
735
1/2
✓ Branch 0 taken 75387 times.
✗ Branch 1 not taken.
75387 string out=line;
736
1/2
✓ Branch 0 taken 157023 times.
✗ Branch 1 not taken.
157023 autoptr<char**> blocks=qsplitstr(out.temp_raw(), " : ");
737 157023 moreonline=true;
738
2/2
✓ Branch 0 taken 162474 times.
✓ Branch 1 taken 133428 times.
295902 for (int block=0;moreonline;block++)
739 {
740 162474 moreonline=(blocks[block+1] != nullptr);
741 try
742 {
743 // it's possible that our input looks something like:
744 // nop : : nop
745 // nop : : : : : nop
746 // also, it's possible that there were empty blocks at the start or end of the line:
747 // : nop :
748 // after qsplit, we still need to deal with possibly a single ": " from a preceding empty block,
749 // and if it's the last block, possibly a following " :".
750
1/2
✓ Branch 0 taken 78138 times.
✗ Branch 1 not taken.
162474 string stripped_block = strip_whitespace(blocks[block]);
751 78138 int i = 0;
752 // if the block starts with ": "
753
6/6
✓ Branch 0 taken 162 times.
✓ Branch 1 taken 162312 times.
✓ Branch 2 taken 72 times.
✓ Branch 3 taken 90 times.
✓ Branch 4 taken 36 times.
✓ Branch 5 taken 78102 times.
162474 if(stripped_block[i] == ':' && stripped_block[i+1] == ' ') {
754 36 i++;
755
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 72 times.
144 while(stripped_block[i] == ' ') i++;
756 }
757 // if the block is a single :, skip that too.
758
5/6
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 162384 times.
✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 45 times.
✓ Branch 5 taken 78093 times.
162474 if(stripped_block[i] == ':' && stripped_block[i+1] == 0) i++;
759
760 // last block - strip trailing " :" if present.
761
11/12
✓ Branch 0 taken 157023 times.
✓ Branch 1 taken 5451 times.
✓ Branch 2 taken 79941 times.
✓ Branch 3 taken 77082 times.
✓ Branch 4 taken 4599 times.
✓ Branch 5 taken 75342 times.
✓ Branch 6 taken 4581 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 18 times.
✓ Branch 9 taken 4563 times.
✓ Branch 10 taken 18 times.
✓ Branch 11 taken 78120 times.
244110 if(!moreonline && stripped_block[stripped_block.length()-2] == ' ' && stripped_block[stripped_block.length()-1] == ':') {
762
2/4
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
36 stripped_block.truncate(stripped_block.length()-2);
763 }
764
765
1/2
✓ Branch 0 taken 78138 times.
✗ Branch 1 not taken.
162474 callstack_push cs_push(callstack_entry_type::BLOCK, stripped_block.data() + i);
766
767
2/2
✓ Branch 0 taken 138087 times.
✓ Branch 1 taken 24387 times.
162474 assembleblock(stripped_block.data() + i, single_line_for_tracker);
768
2/2
✓ Branch 0 taken 138075 times.
✓ Branch 1 taken 12 times.
138087 checkbankcross();
769 186873 }
770
2/2
✓ Branch 0 taken 23595 times.
✓ Branch 1 taken 804 times.
24399 catch (errblock&) {}
771
2/2
✓ Branch 0 taken 90192 times.
✓ Branch 1 taken 48687 times.
138879 if (blocks[block][0]!='\0') asarverallowed=false;
772
2/2
✓ Branch 0 taken 132438 times.
✓ Branch 1 taken 6441 times.
138879 if(single_line_for_tracker == 1) single_line_for_tracker = 0;
773 }
774 180618 }
775
1/2
✓ Branch 0 taken 23595 times.
✗ Branch 1 not taken.
23595 catch (errline&) {}
776 133428 moreonline=moreonlinetmp;
777 180618 }
778
779 int incsrcdepth=0;
780
781 // Returns true if a file is protected via
782 // an "includeonce".
783 26340 bool file_included_once(const char* file)
784 {
785
2/2
✓ Branch 0 taken 720 times.
✓ Branch 1 taken 26214 times.
26934 for (int i = 0; i < includeonce.count; ++i)
786 {
787
2/2
✓ Branch 0 taken 360 times.
✓ Branch 1 taken 360 times.
720 if (includeonce[i] == file)
788 {
789 63 return true;
790 }
791 }
792
793 9936 return false;
794 }
795
796 autoarray<string> macro_defs;
797 int in_macro_def=0;
798
799 26250 void assemblefile(const char * filename)
800 {
801 26250 incsrcdepth++;
802
2/4
✓ Branch 0 taken 9954 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9954 times.
✗ Branch 3 not taken.
26250 string absolutepath = filesystem->create_absolute_path(get_current_file_name(), filename);
803
804
4/4
✓ Branch 0 taken 26187 times.
✓ Branch 1 taken 63 times.
✓ Branch 2 taken 63 times.
✓ Branch 3 taken 9891 times.
26250 if (file_included_once(absolutepath))
805 {
806 63 return;
807 }
808
809
1/2
✓ Branch 0 taken 9891 times.
✗ Branch 1 not taken.
9891 callstack_push cs_push(callstack_entry_type::FILE, absolutepath);
810
811 sourcefile file;
812 26124 file.contents = nullptr;
813 26124 file.numlines = 0;
814
2/2
✓ Branch 0 taken 433 times.
✓ Branch 1 taken 15800 times.
26124 int startif=numif;
815
4/4
✓ Branch 0 taken 10324 times.
✓ Branch 1 taken 15800 times.
✓ Branch 2 taken 460 times.
✓ Branch 3 taken 9431 times.
26124 if (!filecontents.exists(absolutepath))
816 {
817
2/2
✓ Branch 0 taken 887 times.
✓ Branch 1 taken 6 times.
893 char * temp = readfile(absolutepath, "");
818
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 869 times.
887 if (!temp)
819 {
820
6/12
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
18 asar_throw_error(0, error_type_null, vfile_error_to_error_id(asar_get_last_io_error()), filename);
821
822 18 return;
823 }
824
1/2
✓ Branch 0 taken 869 times.
✗ Branch 1 not taken.
869 sourcefile& newfile = filecontents.create(absolutepath);
825
1/2
✓ Branch 0 taken 869 times.
✗ Branch 1 not taken.
869 newfile.contents =split(temp, '\n');
826 869 newfile.data = temp;
827 448 bool in_block_comment = false;
828 448 int block_comment_start = -1;
829 448 string block_comment_start_line;
830
2/2
✓ Branch 0 taken 34530 times.
✓ Branch 1 taken 869 times.
35399 for (int i=0;newfile.contents[i];i++)
831 {
832 34530 newfile.numlines++;
833 17294 char * line= newfile.contents[i];
834
2/2
✓ Branch 0 taken 34488 times.
✓ Branch 1 taken 42 times.
34530 if(in_block_comment) {
835 42 char * end = strstr(line, "]]");
836
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 6 times.
42 if(!end) {
837 36 *line = 0;
838 36 continue;
839 }
840 6 line = end+2;
841 3 in_block_comment = false;
842 }
843 34494 redo_line:
844 34506 char * comment = strqchr(line, ';');
845
2/2
✓ Branch 0 taken 9138 times.
✓ Branch 1 taken 25368 times.
34506 if(comment) {
846
3/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 9114 times.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
9138 if(comment[1] == '[' && comment[2] == '[') {
847 12 in_block_comment = true;
848 12 block_comment_start = i;
849
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 block_comment_start_line = line;
850 // this is a little messy because a multiline comment could
851 // end right on the line where it started. so if we find
852 // the end, cut the comment out of the line and recheck for
853 // more comments.
854 24 char * end = strstr(line, "]]");
855
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if(end) {
856 12 memmove(comment, end+2, strlen(end+2)+1);
857 6 in_block_comment = false;
858 12 goto redo_line;
859 }
860 }
861 9126 *comment = 0;
862 }
863
5/8
✓ Branch 0 taken 34494 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 34482 times.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
34500 if (!confirmquotes(line)) { callstack_push cs_push(callstack_entry_type::LINE, line, i); asar_throw_error(0, error_type_null, error_id_mismatched_quotes); line[0] = '\0'; }
864 34494 newfile.contents[i] = strip_whitespace(line);
865 }
866
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 863 times.
869 if(in_block_comment) {
867
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 callstack_push cs_push(callstack_entry_type::LINE, block_comment_start_line, block_comment_start);
868
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 asar_throw_error(0, error_type_null, error_id_unclosed_block_comment);
869 6 }
870
2/2
✓ Branch 0 taken 34530 times.
✓ Branch 1 taken 869 times.
35399 for(int i=0;newfile.contents[i];i++)
871 {
872 17294 char* line = newfile.contents[i];
873
2/2
✓ Branch 0 taken 13042 times.
✓ Branch 1 taken 21488 times.
34530 if(!*line) continue;
874
3/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 21488 times.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
21518 for (int j=1;line[strlen(line) - 1] == ',' && newfile.contents[i+j];j++)
875 {
876 // not using strcat because the source and dest overlap here
877 15 char* otherline = newfile.contents[i+j];
878 30 char* line_end = line + strlen(line);
879
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 30 times.
414 while(*otherline) *line_end++ = *otherline++;
880 30 *line_end = '\0';
881 static char nullstr[]="";
882 30 newfile.contents[i+j]=nullstr;
883 }
884 }
885 869 file = newfile;
886 869 } else { // filecontents.exists(absolutepath)
887
1/2
✓ Branch 0 taken 9431 times.
✗ Branch 1 not taken.
25231 file = filecontents.find(absolutepath);
888 }
889 26100 asarverallowed=true;
890
3/4
✓ Branch 0 taken 146253 times.
✓ Branch 1 taken 2499 times.
✓ Branch 2 taken 146253 times.
✗ Branch 3 not taken.
148752 for (int i=0;file.contents[i] && i<file.numlines;i++)
891 {
892 70002 string connectedline;
893
1/2
✓ Branch 0 taken 70002 times.
✗ Branch 1 not taken.
146253 int skiplines = getconnectedlines<char**>(file.contents, i, connectedline);
894
895
2/2
✓ Branch 0 taken 122652 times.
✓ Branch 1 taken 23601 times.
146253 bool was_loop_end = do_line_logic(connectedline, absolutepath, i);
896 122652 i += skiplines;
897
898 // if a loop ended on this line, should it run again?
899
8/8
✓ Branch 0 taken 6306 times.
✓ Branch 1 taken 116346 times.
✓ Branch 2 taken 4308 times.
✓ Branch 3 taken 1998 times.
✓ Branch 4 taken 1998 times.
✓ Branch 5 taken 1155 times.
✓ Branch 6 taken 1998 times.
✓ Branch 7 taken 59415 times.
122652 if (was_loop_end && whilestatus[numif].cond)
900
1/2
✓ Branch 0 taken 1998 times.
✗ Branch 1 not taken.
3996 i = whilestatus[numif].startline - 1;
901 146253 }
902
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 2499 times.
2535 while (in_macro_def > 0)
903 {
904
2/4
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
36 asar_throw_error(0, error_type_null, error_id_unclosed_macro, macro_defs[in_macro_def-1].data());
905
5/6
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
36 if (!pass && in_macro_def == 1) endmacro(false);
906 36 in_macro_def--;
907
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
36 macro_defs.remove(in_macro_def);
908 }
909
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2499 times.
2499 if (numif!=startif)
910 {
911 numif=startif;
912 numtrue=startif;
913 asar_throw_error(0, error_type_null, error_id_unclosed_if);
914 }
915 2499 incsrcdepth--;
916
4/4
✓ Branch 0 taken 1290 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 1290 times.
✓ Branch 3 taken 72 times.
49866 }
917
918 // RPG Hacker: At some point, this should probably be merged
919 // into assembleline(), since the two names just cause
920 // confusion otherwise.
921 // return value is "did a loop end on this line"
922 167325 bool do_line_logic(const char* line, const char* filename, int lineno)
923 {
924 167325 int prevnumif = numif;
925 167325 int single_line_for_tracker = 1;
926 try
927 {
928 80538 string current_line;
929
8/8
✓ Branch 0 taken 10062 times.
✓ Branch 1 taken 157263 times.
✓ Branch 2 taken 8604 times.
✓ Branch 3 taken 1458 times.
✓ Branch 4 taken 504 times.
✓ Branch 5 taken 8100 times.
✓ Branch 6 taken 75759 times.
✓ Branch 7 taken 4779 times.
167325 if (numif==numtrue || (numtrue+1==numif && stribegin(line, "elseif ")))
930 {
931
1/2
✓ Branch 0 taken 75759 times.
✗ Branch 1 not taken.
75759 callstack_push cs_push(callstack_entry_type::LINE, line, lineno);
932
2/2
✓ Branch 0 taken 157461 times.
✓ Branch 1 taken 306 times.
157767 string tmp=replace_macro_args(line);
933
1/2
✓ Branch 0 taken 157461 times.
✗ Branch 1 not taken.
157461 tmp.qnormalize();
934
2/2
✓ Branch 0 taken 157365 times.
✓ Branch 1 taken 96 times.
157461 resolvedefines(current_line, tmp);
935 157863 }
936
1/2
✓ Branch 0 taken 4779 times.
✗ Branch 1 not taken.
4779 else current_line=line;
937
938
1/2
✓ Branch 0 taken 80337 times.
✗ Branch 1 not taken.
80337 callstack_push cs_push(callstack_entry_type::LINE, current_line, lineno);
939
940
6/6
✓ Branch 0 taken 1656 times.
✓ Branch 1 taken 165267 times.
✓ Branch 2 taken 828 times.
✓ Branch 3 taken 828 times.
✓ Branch 4 taken 774 times.
✓ Branch 5 taken 79563 times.
166923 if (stribegin(current_line, "macro ") && numif==numtrue)
941 {
942 // RPG Hacker: Slight redundancy here with code that is
943 // also in startmacro(). Could improve this for Asar 2.0.
944
1/2
✓ Branch 0 taken 774 times.
✗ Branch 1 not taken.
1548 string macro_name = current_line.data()+6;
945 1548 char * startpar=strqchr(macro_name.data(), '(');
946
1/2
✓ Branch 0 taken 1548 times.
✗ Branch 1 not taken.
1548 if (startpar) *startpar=0;
947
1/2
✓ Branch 0 taken 774 times.
✗ Branch 1 not taken.
1548 macro_defs.append(macro_name);
948
949 // RPG Hacker: I think it would make more logical sense
950 // to have this ++ after the if, but hat breaks compatibility
951 // with at least one test, and it generally leads to more
952 // errors being output after a broken macro declaration.
953 1548 in_macro_def++;
954
2/2
✓ Branch 0 taken 516 times.
✓ Branch 1 taken 1032 times.
1548 if (!pass)
955 {
956
4/4
✓ Branch 0 taken 420 times.
✓ Branch 1 taken 96 times.
✓ Branch 2 taken 414 times.
✓ Branch 3 taken 6 times.
516 if (in_macro_def == 1) startmacro(current_line.data()+6);
957
1/2
✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
96 else tomacro(current_line);
958 }
959 1548 }
960
6/6
✓ Branch 0 taken 86622 times.
✓ Branch 1 taken 78753 times.
✓ Branch 2 taken 1566 times.
✓ Branch 3 taken 85056 times.
✓ Branch 4 taken 810 times.
✓ Branch 5 taken 79563 times.
165375 else if (!stricmp(current_line, "endmacro") && numif==numtrue)
961 {
962
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1512 times.
1512 if (in_macro_def == 0) asar_throw_error(0, error_type_line, error_id_misplaced_endmacro);
963 else
964 {
965 1512 in_macro_def--;
966
1/2
✓ Branch 0 taken 756 times.
✗ Branch 1 not taken.
1512 macro_defs.remove(in_macro_def);
967
2/2
✓ Branch 0 taken 504 times.
✓ Branch 1 taken 1008 times.
1512 if (!pass)
968 {
969
3/4
✓ Branch 0 taken 414 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 414 times.
✗ Branch 3 not taken.
504 if (in_macro_def == 0) endmacro(true);
970
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 else tomacro(current_line);
971 }
972 }
973 }
974
2/2
✓ Branch 0 taken 6840 times.
✓ Branch 1 taken 157023 times.
163863 else if (in_macro_def > 0)
975 {
976
3/4
✓ Branch 0 taken 2280 times.
✓ Branch 1 taken 4560 times.
✓ Branch 2 taken 2280 times.
✗ Branch 3 not taken.
6840 if (!pass) tomacro(current_line);
977 }
978 else
979 {
980
2/2
✓ Branch 0 taken 133428 times.
✓ Branch 1 taken 23595 times.
157023 assembleline(filename, lineno, current_line, single_line_for_tracker);
981 }
982 190926 }
983
2/2
✓ Branch 0 taken 23601 times.
✓ Branch 1 taken 402 times.
24003 catch (errline&) {}
984
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 126972 times.
127152 return (numif != prevnumif || single_line_for_tracker == 3)
985
9/10
✓ Branch 0 taken 127152 times.
✓ Branch 1 taken 16572 times.
✓ Branch 2 taken 12939 times.
✓ Branch 3 taken 3813 times.
✓ Branch 4 taken 8005 times.
✓ Branch 5 taken 4934 times.
✓ Branch 6 taken 4563 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1121 times.
✓ Branch 9 taken 3442 times.
287538 && (whilestatus[numif].iswhile || whilestatus[numif].is_for);
986 }
987
988
989 493 void parse_std_includes(const char* textfile, autoarray<string>& outarray)
990 {
991 493 char* content = readfilenative(textfile);
992
993
1/2
✓ Branch 0 taken 493 times.
✗ Branch 1 not taken.
493 if (content != nullptr)
994 {
995 247 char* pos = content;
996
997
2/2
✓ Branch 0 taken 988 times.
✓ Branch 1 taken 493 times.
1481 while (pos[0] != '\0')
998 {
999 496 string stdinclude;
1000
1001 do
1002 {
1003
3/4
✓ Branch 0 taken 24384 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23889 times.
✓ Branch 3 taken 495 times.
24384 if (pos[0] != '\r' && pos[0] != '\n')
1004 {
1005
1/2
✓ Branch 0 taken 14295 times.
✗ Branch 1 not taken.
23889 stdinclude += pos[0];
1006 }
1007 24384 pos++;
1008
4/4
✓ Branch 0 taken 23891 times.
✓ Branch 1 taken 493 times.
✓ Branch 2 taken 23396 times.
✓ Branch 3 taken 495 times.
24384 } while (pos[0] != '\0' && pos[0] != '\n');
1009
1010
1/2
✓ Branch 0 taken 496 times.
✗ Branch 1 not taken.
988 strip_whitespace(stdinclude);
1011
1012
2/2
✓ Branch 0 taken 495 times.
✓ Branch 1 taken 493 times.
988 if (stdinclude != "")
1013 {
1014
3/4
✓ Branch 0 taken 495 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 494 times.
495 if (!path_is_absolute(stdinclude))
1015 {
1016
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 stdinclude = dir(textfile) + stdinclude;
1017 }
1018
2/4
✓ Branch 0 taken 495 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 249 times.
✗ Branch 3 not taken.
495 outarray.append(normalize_path(stdinclude));
1019 }
1020 988 }
1021
1022 493 free(content);
1023 }
1024 493 }
1025
1026 753 void parse_std_defines(const char* textfile)
1027 {
1028
1029 // RPG Hacker: add built-in defines.
1030 // (They're not really standard defines, but I was lazy and this was
1031 // one convenient place for doing it).
1032 753 builtindefines.create("assembler") = "asar";
1033
7/11
✓ Branch 0 taken 630 times.
✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 264 times.
✓ Branch 4 taken 123 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 264 times.
✓ Branch 7 taken 123 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 264 times.
✗ Branch 10 not taken.
753 builtindefines.create("assembler_ver") = dec(get_version_int());
1034
3/6
✓ Branch 0 taken 753 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 387 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 387 times.
✗ Branch 5 not taken.
753 builtindefines.create("assembler_time") = dec(time(nullptr));
1035
1036
2/2
✓ Branch 0 taken 386 times.
✓ Branch 1 taken 367 times.
753 if(textfile == nullptr) return;
1037
1038 493 char* content = readfilenative(textfile);
1039
1040
1/2
✓ Branch 0 taken 493 times.
✗ Branch 1 not taken.
493 if (content != nullptr)
1041 {
1042 247 char* pos = content;
1043
2/2
✓ Branch 0 taken 2957 times.
✓ Branch 1 taken 493 times.
3450 while (*pos != 0) {
1044 1481 string define_name;
1045 1481 string define_val;
1046
1047
4/4
✓ Branch 0 taken 29547 times.
✓ Branch 1 taken 1970 times.
✓ Branch 2 taken 28560 times.
✓ Branch 3 taken 987 times.
31517 while (*pos != '=' && *pos != '\n') {
1048
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28560 times.
28560 if(*pos == '\r') { pos++; continue; }
1049
1/2
✓ Branch 0 taken 14292 times.
✗ Branch 1 not taken.
28560 define_name += *pos;
1050 28560 pos++;
1051 }
1052
5/6
✓ Branch 0 taken 2465 times.
✓ Branch 1 taken 492 times.
✓ Branch 2 taken 1481 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 986 times.
✓ Branch 5 taken 495 times.
2957 if (*pos != 0 && *pos != '\r' && *pos != '\n') pos++; // skip =
1053
3/4
✓ Branch 0 taken 13302 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10345 times.
✓ Branch 3 taken 2957 times.
13302 while (*pos != 0 && *pos != '\n') {
1054
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10345 times.
10345 if(*pos == '\r') { pos++; continue; }
1055
1/2
✓ Branch 0 taken 5179 times.
✗ Branch 1 not taken.
10345 define_val += *pos;
1056 10345 pos++;
1057 }
1058
1/2
✓ Branch 0 taken 2957 times.
✗ Branch 1 not taken.
2957 if (*pos != 0)
1059 2957 pos++; // skip \n
1060 // clean define_name
1061
1/2
✓ Branch 0 taken 1481 times.
✗ Branch 1 not taken.
2957 strip_whitespace(define_name);
1062
1/2
✓ Branch 0 taken 1481 times.
✗ Branch 1 not taken.
2957 define_name.strip_prefix('!'); // remove leading ! if present
1063
1064
2/2
✓ Branch 0 taken 493 times.
✓ Branch 1 taken 2464 times.
2957 if (define_name == "")
1065 {
1066
1/2
✓ Branch 0 taken 493 times.
✗ Branch 1 not taken.
493 if (define_val == "")
1067 {
1068 493 continue;
1069 }
1070
1071 asar_throw_error(pass, error_type_null, error_id_stddefines_no_identifier);
1072 }
1073
1074
3/8
✓ Branch 0 taken 619 times.
✓ Branch 1 taken 1845 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 619 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2464 if (!validatedefinename(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_invalid, "stddefines.txt", define_name.data());
1075
1076 // clean define_val
1077 1234 const char* defval = define_val.data();
1078 1234 string cleaned_defval;
1079
1080
2/2
✓ Branch 0 taken 494 times.
✓ Branch 1 taken 1970 times.
2464 if (*defval == 0) {
1081 // no value
1082
3/6
✓ Branch 0 taken 248 times.
✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 248 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
494 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
1083
2/4
✓ Branch 0 taken 494 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 248 times.
✗ Branch 3 not taken.
494 clidefines.create(define_name) = "";
1084 494 continue;
1085 }
1086
1087
3/4
✓ Branch 0 taken 986 times.
✓ Branch 1 taken 1970 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1970 times.
2956 while (*defval == ' ' || *defval == '\t') defval++; // skip whitespace in beginning
1088
2/2
✓ Branch 0 taken 493 times.
✓ Branch 1 taken 1477 times.
1970 if (*defval == '"') {
1089 493 defval++; // skip opening quote
1090
3/4
✓ Branch 0 taken 6401 times.
✓ Branch 1 taken 493 times.
✓ Branch 2 taken 6401 times.
✗ Branch 3 not taken.
6894 while (*defval != '"' && *defval != 0)
1091
1/2
✓ Branch 0 taken 3203 times.
✗ Branch 1 not taken.
6401 cleaned_defval += *defval++;
1092
1093
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 493 times.
493 if (*defval == 0) {
1094 asar_throw_error(pass, error_type_null, error_id_mismatched_quotes);
1095 }
1096 493 defval++; // skip closing quote
1097
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 493 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 493 times.
493 while (*defval == ' ' || *defval == '\t') defval++; // skip whitespace
1098
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 493 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
493 if (*defval != 0 && *defval != '\n')
1099 asar_throw_error(pass, error_type_null, error_id_stddefine_after_closing_quote);
1100
1101
3/6
✓ Branch 0 taken 247 times.
✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 247 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
493 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
1102
2/4
✓ Branch 0 taken 493 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 247 times.
✗ Branch 3 not taken.
493 clidefines.create(define_name) = cleaned_defval;
1103 493 continue;
1104 }
1105 else
1106 {
1107 // slightly hacky way to remove trailing whitespace
1108 1477 const char* defval_end = strchr(defval, '\n'); // slightly hacky way to get end of string or newline
1109
1/2
✓ Branch 0 taken 1477 times.
✗ Branch 1 not taken.
1477 if (!defval_end) defval_end = strchr(defval, 0);
1110 1477 defval_end--;
1111
3/4
✓ Branch 0 taken 495 times.
✓ Branch 1 taken 1477 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1477 times.
1972 while (*defval_end == ' ' || *defval_end == '\t') defval_end--;
1112
3/4
✓ Branch 0 taken 739 times.
✓ Branch 1 taken 738 times.
✓ Branch 2 taken 739 times.
✗ Branch 3 not taken.
1477 cleaned_defval = string(defval, (int)(defval_end - defval + 1));
1113
1114
3/6
✓ Branch 0 taken 739 times.
✓ Branch 1 taken 738 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 739 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1477 if (clidefines.exists(define_name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Std define", define_name.data());
1115
2/4
✓ Branch 0 taken 1477 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 739 times.
✗ Branch 3 not taken.
1477 clidefines.create(define_name) = cleaned_defval;
1116 1477 continue;
1117 1477 }
1118
1119 2957 }
1120 493 free(content);
1121 }
1122 }
1123
1124 bool checksum_fix_enabled = true;
1125 bool force_checksum_fix = false;
1126
1127 #define cfree(x) free((void*)x)
1128 414 static void clearmacro(const string & key, macrodata* & macro)
1129 {
1130 (void)key;
1131 414 freemacro(macro);
1132 414 }
1133
1134 869 static void clearfile(const string & key, sourcefile& filecontent)
1135 {
1136 (void)key;
1137 869 cfree(filecontent.data);
1138 869 cfree(filecontent.contents);
1139 869 }
1140 #undef cfree
1141
1142
1/2
✓ Branch 0 taken 2328 times.
✗ Branch 1 not taken.
4719 static void adddefine(const string & key, string & value)
1143 {
1144
1/2
✓ Branch 0 taken 4719 times.
✗ Branch 1 not taken.
4719 if (!defines.exists(key)) defines.create(key) = value;
1145 4719 }
1146
1147 static string symbolfile;
1148
1149 360 static void printsymbol_wla(const string& key, snes_label& label)
1150 {
1151
7/14
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 180 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 180 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 180 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 180 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 180 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 180 times.
✗ Branch 13 not taken.
540 string line = hex((label.pos & 0xFF0000)>>16, 2)+":"+hex(label.pos & 0xFFFF, 4)+" "+key+"\n";
1152
1/2
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
360 symbolfile += line;
1153 360 }
1154
1155 static void printsymbol_nocash(const string& key, snes_label& label)
1156 {
1157 string line = hex(label.pos & 0xFFFFFF, 8)+" "+key+"\n";
1158 symbolfile += line;
1159 }
1160
1161 178 string create_symbols_file(string format, uint32_t romCrc){
1162 178 format = lower(format);
1163 89 symbolfile = "";
1164
1/2
✓ Branch 0 taken 178 times.
✗ Branch 1 not taken.
178 if(format == "wla")
1165 {
1166 89 symbolfile = "; wla symbolic information file\n";
1167 178 symbolfile += "; generated by asar\n";
1168
1169 178 symbolfile += "\n[labels]\n";
1170 178 labels.each(printsymbol_wla);
1171
1172 178 symbolfile += "\n[source files]\n";
1173 89 const autoarray<AddressToLineMapping::FileInfo>& addrToLineFileList = addressToLineMapping.getFileList();
1174
2/2
✓ Branch 0 taken 186 times.
✓ Branch 1 taken 178 times.
364 for (int i = 0; i < addrToLineFileList.count; ++i)
1175 {
1176 char addrToFileListStr[256];
1177 279 snprintf(addrToFileListStr, 256, "%.4x %.8x %s\n",
1178 i,
1179
1/2
✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
186 addrToLineFileList[i].fileCrc,
1180
1/2
✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
93 addrToLineFileList[i].filename.data()
1181 );
1182
1/2
✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
186 symbolfile += addrToFileListStr;
1183 }
1184
1185 178 symbolfile += "\n[rom checksum]\n";
1186 {
1187 char romCrcStr[32];
1188 178 snprintf(romCrcStr, 32, "%.8x\n",
1189 romCrc
1190 );
1191
1/2
✓ Branch 0 taken 89 times.
✗ Branch 1 not taken.
178 symbolfile += romCrcStr;
1192 }
1193
1194 178 symbolfile += "\n[addr-to-line mapping]\n";
1195 89 const autoarray<AddressToLineMapping::AddrToLineInfo>& addrToLineInfo = addressToLineMapping.getAddrToLineInfo();
1196
2/2
✓ Branch 0 taken 5416 times.
✓ Branch 1 taken 178 times.
5594 for (int i = 0; i < addrToLineInfo.count; ++i)
1197 {
1198 char addrToLineStr[32];
1199 13540 snprintf(addrToLineStr, 32, "%.2x:%.4x %.4x:%.8x\n",
1200 8124 (addrToLineInfo[i].addr & 0xFF0000) >> 16,
1201
1/2
✓ Branch 0 taken 2708 times.
✗ Branch 1 not taken.
5416 addrToLineInfo[i].addr & 0xFFFF,
1202
1/2
✓ Branch 0 taken 2708 times.
✗ Branch 1 not taken.
5416 addrToLineInfo[i].fileIdx & 0xFFFF,
1203
2/4
✓ Branch 0 taken 2708 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2708 times.
✗ Branch 3 not taken.
5416 addrToLineInfo[i].line & 0xFFFFFFFF
1204 );
1205
1/2
✓ Branch 0 taken 2708 times.
✗ Branch 1 not taken.
5416 symbolfile += addrToLineStr;
1206 }
1207
1208 }
1209 else if (format == "nocash")
1210 {
1211 symbolfile = ";no$sns symbolic information file\n";
1212 symbolfile += ";generated by asar\n";
1213 symbolfile += "\n";
1214 labels.each(printsymbol_nocash);
1215 }
1216 178 return symbolfile;
1217 }
1218
1219
1220 6 bool in_top_level_file()
1221 {
1222 3 int num_files = 0;
1223
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 6 times.
30 for (int i = callstack.count-1; i >= 0; --i)
1224 {
1225
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 18 times.
24 if (callstack[i].type == callstack_entry_type::FILE)
1226 {
1227 6 num_files++;
1228
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (num_files > 1) break;
1229 }
1230 }
1231 6 return (num_files <= 1);
1232 }
1233
1234 43859 const char* get_current_file_name()
1235 {
1236
2/2
✓ Branch 0 taken 165492 times.
✓ Branch 1 taken 2200 times.
167692 for (int i = callstack.count-1; i >= 0; --i)
1237 {
1238
2/2
✓ Branch 0 taken 41659 times.
✓ Branch 1 taken 123833 times.
165492 if (callstack[i].type == callstack_entry_type::FILE)
1239 41659 return callstack[i].content.raw();
1240 }
1241 1132 return nullptr;
1242 }
1243
1244 26825 int get_current_line()
1245 {
1246
2/2
✓ Branch 0 taken 79364 times.
✓ Branch 1 taken 21 times.
79385 for (int i = callstack.count-1; i >= 0; --i)
1247 {
1248
2/2
✓ Branch 0 taken 26804 times.
✓ Branch 1 taken 52560 times.
92755 if (callstack[i].type == callstack_entry_type::LINE) return callstack[i].lineno;
1249 }
1250 11 return -1;
1251 }
1252
1253 694 const char* get_current_block()
1254 {
1255
2/2
✓ Branch 0 taken 699 times.
✓ Branch 1 taken 31 times.
730 for (int i = callstack.count-1; i >= 0; --i)
1256 {
1257
6/6
✓ Branch 0 taken 531 times.
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 495 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 333 times.
✓ Branch 5 taken 18 times.
1293 if (callstack[i].type == callstack_entry_type::LINE || callstack[i].type == callstack_entry_type::BLOCK) return callstack[i].content.raw();
1258 }
1259 16 return nullptr;
1260 }
1261
1262
1263 758 void reseteverything()
1264 {
1265 390 string str;
1266 758 labels.reset();
1267 758 defines.reset();
1268
1/2
✓ Branch 0 taken 758 times.
✗ Branch 1 not taken.
758 builtindefines.each(adddefine);
1269
1/2
✓ Branch 0 taken 758 times.
✗ Branch 1 not taken.
758 clidefines.each(adddefine);
1270 758 structs.reset();
1271
1272
1/2
✓ Branch 0 taken 758 times.
✗ Branch 1 not taken.
758 macros.each(clearmacro);
1273 758 macros.reset();
1274
1275
1/2
✓ Branch 0 taken 758 times.
✗ Branch 1 not taken.
758 filecontents.each(clearfile);
1276 758 filecontents.reset();
1277
1278 758 writtenblocks.reset();
1279
1280 758 optimizeforbank=-1;
1281 758 optimize_dp = optimize_dp_flag::ALWAYS;
1282 758 dp_base = 0;
1283 758 optimize_address = optimize_address_flag::MIRRORS;
1284
1285
1/2
✓ Branch 0 taken 758 times.
✗ Branch 1 not taken.
758 closecachedfiles();
1286
1287 758 incsrcdepth=0;
1288 758 label_counter = 0;
1289 758 errored = false;
1290 758 checksum_fix_enabled = true;
1291 758 force_checksum_fix = false;
1292
1293 758 in_macro_def = 0;
1294
1295 #ifndef ASAR_SHARED
1296 246 free(const_cast<unsigned char*>(romdata_r));
1297 #endif
1298
1299
1/2
✓ Branch 0 taken 390 times.
✗ Branch 1 not taken.
758 callstack.reset();
1300 758 simple_callstacks = true;
1301 #undef free
1302 758 }
1303