asar coverage - build #298


src/asar/
File: src/asar/assembleblock.cpp
Date: 2025-03-14 15:27:49
Lines:
1300/1414
91.9%
Functions:
130/135
96.3%
Branches:
1941/3222
60.2%

Line Branch Exec Source
1 #include "addr2line.h"
2 #include "asar.h"
3 #include "assembleblock.h"
4 #include "asar_math.h"
5 #include "macro.h"
6 #include "table.h"
7 #include "unicode.h"
8 #include "frozen/string.h"
9 #include "frozen/unordered_map.h"
10
11 #include "interface-shared.h"
12 #include "arch-shared.h"
13
14 int arch=arch_65816;
15
16 bool snespos_valid = false;
17 int snespos;
18 int realsnespos;
19 int startpos;
20 int realstartpos;
21
22 static bool mapper_set = false;
23 int label_counter = 0;
24
25 static int old_snespos;
26 static int old_startpos;
27 static int old_optimizeforbank;
28 static bool old_snespos_valid;
29 static int struct_base;
30 static string struct_name;
31 static string struct_parent;
32 static bool in_struct = false;
33 static bool in_sub_struct = false;
34 static bool static_struct = false;
35 static bool in_spcblock = false;
36
37 assocarr<snes_struct> structs;
38
39 static bool movinglabelspossible = false;
40
41 static bool disable_bank_cross_errors = false;
42 static bool check_half_banks_crossed = false;
43
44 int bytes;
45 static int freespaceuse=0;
46
47 static enum {
48 ratsmeta_ban,
49 ratsmeta_allow,
50 ratsmeta_used,
51 } ratsmetastate=ratsmeta_ban;
52
53 enum spcblock_type{
54 spcblock_nspc,
55 spcblock_custom
56 };
57
58 static struct spcblock_data{
59 unsigned int destination;
60 spcblock_type type;
61 string macro_name;
62
63 unsigned int size_address;
64 mapper_t old_mapper;
65 }spcblock;
66
67 437921 static inline void verifysnespos()
68 {
69
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 437921 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 219064 times.
437921 if (!snespos_valid)
70 {
71 throw_err_block(0, err_missing_org);
72 snespos=0x008000;
73 realsnespos=0x008000;
74 startpos=0x008000;
75 realstartpos=0x008000;
76 snespos_valid = true;
77 }
78 437921 }
79
80 552 static int fixsnespos(int inaddr, int step)
81 {
82 // randomdude999: turns out it wasn't very reliable at all.
83 /* // RPG Hacker: No idea how reliable this is.
84 // Might not work with some of the more exotic mappers.
85 return pctosnes(snestopc(inaddr) + step); */
86
4/4
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 504 times.
✓ Branch 2 taken 48 times.
✓ Branch 3 taken 228 times.
552 if (mapper == lorom) {
87
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 84 times.
96 if ((inaddr&0xFFFF)+step > 0xFFFF) {
88 // bank crossed
89 12 return inaddr+step+0x8000;
90 }
91 84 return inaddr+step;
92
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 228 times.
456 } else if (mapper == hirom) {
93 if ((inaddr&0x400000) == 0 && freespaceid == 0) {
94 // we shouldn't get here in pass 2 inside a freespace anyways i think
95 // system pages, need to account for low pages and stuff
96 if ((inaddr&0xFFFF)+step > 0xFFFF) {
97 return inaddr+step+0x8000;
98 }
99 }
100 return inaddr+step;
101
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 228 times.
456 } else if (mapper == exlorom) {
102 // exlorom has no mirroring so this should work fine
103 return pctosnes(snestopc(inaddr)+step);
104
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 228 times.
456 } else if (mapper == exhirom) {
105 // apparently exhirom is pretty similar to hirom after all
106 if ((inaddr&0x400000) == 0) {
107 // system pages, need to account for low pages and stuff
108 if ((inaddr&0xFFFF)+step > 0xFFFF) {
109 return inaddr+step+0x8000;
110 }
111 }
112 return inaddr+step;
113
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 228 times.
456 } else if (mapper == sa1rom) {
114 if((inaddr&0x400000) == 0) {
115 // lorom area
116 if ((inaddr&0xFFFF)+step > 0xFFFF) {
117 return inaddr+step+0x8000;
118 }
119 return inaddr+step;
120 } else {
121 // hirom area
122 return inaddr+step;
123 }
124
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 228 times.
456 } else if (mapper == sfxrom) {
125 if ((inaddr&0x400000) == 0) {
126 // lorom area
127 if ((inaddr&0xFFFF)+step > 0xFFFF) {
128 return inaddr+step+0x8000;
129 }
130 } else {
131 // hirom area
132 return inaddr+step;
133 }
134
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 228 times.
456 } else if (mapper == bigsa1rom) {
135 // no mirrors here, so this should work
136 return pctosnes(snestopc(inaddr)+step);
137
3/4
✓ Branch 0 taken 228 times.
✓ Branch 1 taken 228 times.
✓ Branch 2 taken 228 times.
✗ Branch 3 not taken.
456 } else if (mapper == norom) {
138 456 return inaddr+step;
139 }
140 return -1;
141 }
142
143 437444 static inline void step(int num)
144 {
145
4/4
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 437306 times.
✓ Branch 2 taken 138 times.
✓ Branch 3 taken 218674 times.
437444 if (disable_bank_cross_errors)
146 {
147 276 snespos = fixsnespos(snespos, num);
148 276 realsnespos = fixsnespos(realsnespos, num);
149
150 // RPG Hacker: Not adjusting startpos here will eventually throw
151 // an error in checkbankcross() if we set warn bankcross on again.
152 // As far as I can tell, those are pretty much just used for
153 // checking bank crossing, anyways, so it's hopefully save to just
154 // adjust them here.
155 276 startpos = snespos;
156 276 realstartpos = realsnespos;
157 }
158 else
159 {
160 437168 snespos += num;
161 437168 realsnespos += num;
162 }
163 437444 bytes+=num;
164 437444 }
165
166 436826 void write1(unsigned int num)
167 {
168 436826 verifysnespos();
169
2/2
✓ Branch 0 taken 145580 times.
✓ Branch 1 taken 291246 times.
436826 if (pass==2)
170 {
171 145580 int pcpos=snestopc(realsnespos&0xFFFFFF);
172
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 145580 times.
145580 if (pcpos<0)
173 {
174 movinglabelspossible=true;
175 throw_err_block(2, err_snes_address_doesnt_map_to_rom, hex((unsigned int)realsnespos, 6).data());
176 }
177 145580 writeromdata_byte(pcpos, (unsigned char)num, freespaceid != 0);
178
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 145578 times.
145580 if (pcpos>=romlen) {
179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if(pcpos - romlen > 0) writeromdata_bytes(romlen, freespacebyte, pcpos - romlen, false);
180 2 romlen=pcpos+1;
181 }
182 }
183
4/4
✓ Branch 0 taken 145622 times.
✓ Branch 1 taken 291204 times.
✓ Branch 2 taken 9168 times.
✓ Branch 3 taken 136454 times.
436826 if(pass == 1 && freespaceid == 0) {
184 9168 int pcpos = snestopc(realsnespos & 0xFFFFFF);
185
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9168 times.
9168 if(pcpos < 0)
186 {
187 movinglabelspossible=true;
188 throw_err_block(2, err_snes_address_doesnt_map_to_rom, hex((unsigned int)realsnespos, 6).data());
189 }
190 9168 addromwrite(pcpos, 1);
191
2/2
✓ Branch 0 taken 8751 times.
✓ Branch 1 taken 417 times.
9168 if (pcpos>=romlen) {
192
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 8663 times.
8751 if(pcpos - romlen > 0) writeromdata_bytes(romlen, freespacebyte, pcpos - romlen, false);
193 8751 romlen=pcpos+1;
194 }
195 }
196 436826 step(1);
197 436826 ratsmetastate=ratsmeta_ban;
198 436826 }
199
200 31907 static bool asblock_pick(const string& firstword, const char* par)
201 {
202
6/6
✓ Branch 0 taken 29561 times.
✓ Branch 1 taken 2346 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 29546 times.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 14905 times.
31907 if (arch==arch_spc700 || in_spcblock) {
203 // TODO
204
2/3
✓ Branch 0 taken 1188 times.
✓ Branch 1 taken 1188 times.
✗ Branch 2 not taken.
2376 string dup(firstword);
205
2/3
✓ Branch 0 taken 1188 times.
✓ Branch 1 taken 1188 times.
✗ Branch 2 not taken.
2376 string duppar(par);
206 2376 char* words[] = { dup.raw(), duppar.raw() };
207
4/6
✓ Branch 0 taken 1128 times.
✓ Branch 1 taken 1188 times.
✓ Branch 2 taken 1248 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1188 times.
✗ Branch 5 not taken.
2376 return asblock_spc700(words, *par ? 2 : 1);
208 2376 }
209
2/2
✓ Branch 0 taken 25877 times.
✓ Branch 1 taken 3654 times.
29531 if (arch==arch_65816) {
210 25877 return asblock_65816(firstword, par);
211 }
212
1/2
✓ Branch 0 taken 3654 times.
✗ Branch 1 not taken.
3654 if (arch==arch_superfx) {
213
2/3
✓ Branch 0 taken 1827 times.
✓ Branch 1 taken 1827 times.
✗ Branch 2 not taken.
3654 string dup(firstword);
214
2/3
✓ Branch 0 taken 1827 times.
✓ Branch 1 taken 1827 times.
✗ Branch 2 not taken.
3654 string duppar(par);
215 3654 char* words[] = { dup.raw(), duppar.raw() };
216
4/6
✓ Branch 0 taken 1722 times.
✓ Branch 1 taken 1827 times.
✓ Branch 2 taken 1932 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1827 times.
✗ Branch 5 not taken.
3654 return asblock_superfx(words, *par ? 2 : 1);
217 3654 }
218 return true;
219 }
220
221 11539 const char * safedequote(char * str)
222 {
223 11539 const char * tmp=dequote(str);
224
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11539 times.
11539 if (!tmp) throw_err_block(0, err_garbage_near_quoted_string);
225 11539 return tmp;
226 }
227
228 1855 void write2(unsigned int num)
229 {
230 1855 write1(num);
231 1855 write1(num/256);
232 1855 }
233
234 1210 void write3(unsigned int num)
235 {
236 1210 write1(num);
237 1210 write1(num/256);
238 1210 write1(num/65536);
239 1210 }
240
241 114 void write4(unsigned int num)
242 {
243 114 write1(num);
244 114 write1(num/256);
245 114 write1(num/65536);
246 114 write1(num/16777216);
247 114 }
248
249 //these are NOT used by the math parser - see asar_math.cpp for that
250 22 static int read2(int insnespos)
251 {
252 22 int addr=snestopc(insnespos);
253
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
22 if (addr<0 || addr+2>romlen_r) return -1;
254 return
255 22 romdata_r[addr ] |
256
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
33 (romdata_r[addr+1]<< 8);
257 }
258
259 54 static int read3(int insnespos)
260 {
261 54 int addr=snestopc(insnespos);
262
2/4
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
54 if (addr<0 || addr+3>romlen_r) return -1;
263 return
264 54 romdata_r[addr ] |
265 81 (romdata_r[addr+1]<< 8)|
266
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
81 (romdata_r[addr+2]<<16);
267 }
268
269 1452 int getlenfromchar(char c)
270 {
271 1452 c=(char)to_lower(c);
272
2/2
✓ Branch 0 taken 660 times.
✓ Branch 1 taken 792 times.
1452 if (c=='b') return 1;
273
2/2
✓ Branch 0 taken 690 times.
✓ Branch 1 taken 102 times.
792 if (c=='w') return 2;
274
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 6 times.
102 if (c=='l') return 3;
275 6 throw_err_block(0, err_invalid_opcode_length);
276 }
277
278 assocarr<snes_label> labels;
279 static autoarray<int> poslabels;
280 static autoarray<int> neglabels;
281
282 autoarray<int>* macroposlabels;
283 autoarray<int>* macroneglabels;
284
285 autoarray<string> sublabels;
286 autoarray<string>* macrosublabels;
287
288 // randomdude999: ns is still the string to prefix to all labels, it's calculated whenever namespace_list is changed
289 string ns;
290 static string ns_backup;
291 autoarray<string> namespace_list;
292
293 autoarray<string> includeonce;
294
295 autoarray<freespace_data> freespaces;
296
297 // id of the next unused freespace.
298 static int freespaceidnext;
299 // id of the current freespace, or 0 if not in freespace.
300 int freespaceid;
301 // start address of the current freespace, used for computing the length of the
302 // current freespace.
303 static int freespacestart;
304 static freespace_data default_freespace_settings;
305
306 1220 bool confirmname(const char * name)
307 {
308
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 599 times.
✓ Branch 2 taken 621 times.
1220 if (!name[0]) return false;
309
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 599 times.
✓ Branch 2 taken 621 times.
1220 if (is_digit(name[0])) return false;
310
4/4
✓ Branch 0 taken 5988 times.
✓ Branch 1 taken 599 times.
✓ Branch 2 taken 6022 times.
✓ Branch 3 taken 621 times.
13230 for (int i=0;name[i];i++)
311 {
312
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 5988 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6022 times.
12010 if (!is_ualnum(name[i])) return false;
313 }
314 1220 return true;
315 }
316
317 53744 string posneglabelname(const char ** input, bool define)
318 {
319 53744 const char* label = *input;
320
321 53744 string output;
322
323 53744 int depth = 0;
324 53744 bool ismacro = false;
325
326
3/3
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 26634 times.
✓ Branch 2 taken 27087 times.
53744 if (label[0] == '?')
327 {
328 46 ismacro = true;
329 46 label++;
330 }
331
6/6
✓ Branch 0 taken 26603 times.
✓ Branch 1 taken 27104 times.
✓ Branch 2 taken 103 times.
✓ Branch 3 taken 26537 times.
✓ Branch 4 taken 72 times.
✓ Branch 5 taken 27001 times.
53744 if (label[0] == '-' || label[0] == '+')
332 {
333 206 char first = label[0];
334
6/6
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 62 times.
✓ Branch 2 taken 241 times.
✓ Branch 3 taken 109 times.
✓ Branch 4 taken 109 times.
✓ Branch 5 taken 35 times.
412 for (depth = 0; label[0] && label[0] == first; depth++) label++;
335
336
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 16 times.
206 if (!ismacro)
337 {
338
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 60 times.
190 if (first == '+')
339 {
340 130 *input = label;
341
12/22
✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 130 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 62 times.
✓ Branch 5 taken 68 times.
✓ Branch 6 taken 62 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 62 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 130 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 62 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 68 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 68 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 68 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 68 times.
✗ Branch 21 not taken.
130 output = STR":pos_" + dec(depth) + "_" + dec(poslabels[depth]);
342
3/4
✓ Branch 0 taken 105 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 105 times.
✗ Branch 3 not taken.
130 if (define) poslabels[depth]++;
343 }
344 else
345 {
346 60 *input = label;
347
3/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 51 times.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
60 if (define) neglabels[depth]++;
348
12/22
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
✓ Branch 5 taken 33 times.
✓ Branch 6 taken 27 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 27 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 60 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 27 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 33 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 33 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 33 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 33 times.
✗ Branch 21 not taken.
60 output = STR":neg_" + dec(depth) + "_" + dec(neglabels[depth]);
349 }
350 }
351 else
352 {
353
3/6
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16 times.
16 if (macrorecursion == 0 || macroposlabels == nullptr || macroneglabels == nullptr)
354 {
355 if (!macrorecursion) throw_err_block(0, err_macro_label_outside_of_macro);
356 }
357 else
358 {
359
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 if (first == '+')
360 {
361 8 *input = label;
362
16/32
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 8 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 4 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 4 times.
✓ Branch 19 taken 4 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 4 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 4 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 4 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 4 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 4 times.
✗ Branch 31 not taken.
8 output = STR":macro_" + dec(calledmacros) + "_pos_" + dec(depth) + "_" + dec((*macroposlabels)[depth]);
363
4/5
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
8 if (define) (*macroposlabels)[depth]++;
364 }
365 else
366 {
367 8 *input = label;
368
4/5
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
8 if (define) (*macroneglabels)[depth]++;
369
16/32
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 8 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 4 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 4 times.
✓ Branch 19 taken 4 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 4 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 4 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 4 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 4 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 4 times.
✗ Branch 31 not taken.
8 output = STR":macro_" + dec(calledmacros) + "_neg_" + dec(depth) + "_" + dec((*macroneglabels)[depth]);
370 }
371 }
372 }
373 }
374
375 53744 return output;
376 }
377
378 2351 string labelname(const char ** rawname, bool define, bool is_addlabel)
379 {
380 #define deref_rawname (*rawname)
381 2351 autoarray<string>* sublabellist = &sublabels;
382
383 2351 bool ismacro = (deref_rawname[0] == '?');
384 2351 bool issublabel = false;
385
386
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 2327 times.
2351 if (ismacro)
387 {
388 24 deref_rawname++;
389 24 sublabellist = macrosublabels;
390 }
391
392 2351 string name;
393 2351 int i=-1;
394
395
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 1161 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1190 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
2351 if (is_digit(*deref_rawname)) throw_err_block(2, err_invalid_label_name);
396
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1161 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1190 times.
2351 if (*deref_rawname ==':')
397 {
398 deref_rawname++;
399 name=":";
400 }
401
7/8
✓ Branch 0 taken 1044 times.
✓ Branch 1 taken 1307 times.
✓ Branch 2 taken 2105 times.
✓ Branch 3 taken 129 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1073 times.
✓ Branch 6 taken 1061 times.
✓ Branch 7 taken 12 times.
2351 else if (!in_struct && !in_sub_struct)
402 {
403
4/4
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 1032 times.
✓ Branch 2 taken 53 times.
✓ Branch 3 taken 1061 times.
2193 for (i=0;(*deref_rawname =='.');i++) deref_rawname++;
404
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 1032 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1061 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
2093 if (!is_ualnum(*deref_rawname)) throw_err_block(2, err_invalid_label_name);
405
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 1999 times.
2093 if (i)
406 {
407
7/14
✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 50 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 44 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 44 times.
✓ Branch 8 taken 50 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 50 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
94 if (!sublabellist || !(*sublabellist)[i - 1]) throw_err_block(2, err_label_missing_parent);
408
7/12
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 94 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 44 times.
✓ Branch 5 taken 50 times.
✓ Branch 6 taken 44 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 50 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 50 times.
✗ Branch 11 not taken.
94 name+=STR(*sublabellist)[i-1]+"_";
409 94 issublabel = true;
410 }
411 }
412
413
4/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 2327 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 8 times.
2351 if (ismacro && !issublabel)
414 {
415 // RPG Hacker: Don't add the prefix for sublabels, because they already inherit it from
416 // their parents' names.
417
4/6
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
16 if (!macrorecursion || macrosublabels == nullptr) throw_err_block(2, err_macro_label_outside_of_macro);
418
7/14
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 10 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 5 times.
✗ Branch 13 not taken.
10 name = STR":macro_" + dec(calledmacros) + "_" + name;
419 }
420
421
422
7/8
✓ Branch 0 taken 1041 times.
✓ Branch 1 taken 1304 times.
✓ Branch 2 taken 1082 times.
✓ Branch 3 taken 1146 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1070 times.
✓ Branch 6 taken 12 times.
✓ Branch 7 taken 1058 times.
2345 if (in_struct || in_sub_struct)
423 {
424
7/9
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 114 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 114 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 6 times.
✗ Branch 8 not taken.
258 if(is_addlabel && *deref_rawname != '.') throw_err_block(2, err_invalid_label_name); //probably should be a better error. TODO!!!
425
4/4
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 120 times.
✓ Branch 3 taken 3 times.
246 if(*deref_rawname == '.') {
426 240 deref_rawname++;
427
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 228 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 108 times.
240 if(in_sub_struct)
428 {
429
4/7
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
24 name += struct_parent + ".";
430 }
431
1/2
✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
240 name += struct_name;
432
1/2
✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
240 name += '.';
433 }
434 }
435
436
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 1152 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1181 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
2333 if (!is_ualnum(*deref_rawname)) throw_err_block(2, err_invalid_label_name);
437
438
10/10
✓ Branch 0 taken 1248 times.
✓ Branch 1 taken 7625 times.
✓ Branch 2 taken 1373 times.
✓ Branch 3 taken 8889 times.
✓ Branch 4 taken 7721 times.
✓ Branch 5 taken 1152 times.
✓ Branch 6 taken 96 times.
✓ Branch 7 taken 1181 times.
✓ Branch 8 taken 7833 times.
✓ Branch 9 taken 1181 times.
17887 while (is_ualnum(*deref_rawname) || *deref_rawname == '.')
439 {
440
2/4
✓ Branch 0 taken 7721 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7833 times.
✗ Branch 3 not taken.
15554 name+=*(deref_rawname++);
441 }
442
443
4/4
✓ Branch 0 taken 969 times.
✓ Branch 1 taken 1364 times.
✓ Branch 2 taken 741 times.
✓ Branch 3 taken 228 times.
2333 if (define && i>=0)
444 {
445 741 (*sublabellist).reset(i);
446
4/7
✓ Branch 0 taken 360 times.
✓ Branch 1 taken 381 times.
✓ Branch 2 taken 360 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 381 times.
✗ Branch 6 not taken.
741 (*sublabellist)[i]=name;
447 }
448 2333 return name;
449 #undef deref_rawname
450 18 }
451
452 194 static inline bool labelvalcore(const char ** rawname, snes_label * rval, bool define, bool shouldthrow)
453 {
454
2/3
✓ Branch 0 taken 95 times.
✓ Branch 1 taken 99 times.
✗ Branch 2 not taken.
194 string name=labelname(rawname, define);
455
11/30
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 192 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 95 times.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 97 times.
✓ Branch 12 taken 97 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 2 times.
✓ Branch 15 taken 97 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 99 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
194 if (ns && labels.exists(ns+name)) {*rval = labels.find(ns+name);}
456
4/6
✓ Branch 0 taken 194 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 170 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 170 times.
✗ Branch 5 not taken.
194 else if (labels.exists(name)) {*rval = labels.find(name);}
457 else
458 {
459
3/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 22 times.
24 if (shouldthrow && pass)
460 {
461
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 throw_err_block(2, err_label_not_found, name.data());
462 }
463 22 rval->pos = (unsigned int)-1;
464 22 rval->freespace_id = 0;
465 22 rval->is_static = false;
466 22 return false;
467 }
468 170 return true;
469 194 }
470
471 172 snes_label labelval(const char ** rawname, bool define)
472 {
473 172 snes_label rval;
474
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 2 times.
172 labelvalcore(rawname, &rval, define, true);
475 170 return rval;
476 }
477
478 22 snes_label labelval(string name, bool define)
479 {
480 22 const char * rawname=name;
481 22 snes_label rval;
482
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 labelvalcore(&rawname, &rval, define, true);
483 44 return rval;
484 }
485
486 bool labelval(const char ** rawname, snes_label * rval, bool define)
487 {
488 return labelvalcore(rawname, rval, define, false);
489 }
490
491 bool labelval(string name, snes_label * rval, bool define)
492 {
493 const char * str=name;
494 return labelvalcore(&str, rval, define, false);
495 }
496
497 1330 static void setlabel(string name, int loc=-1, bool is_static=false)
498 {
499 1330 int lbl_fs_id = 0;
500
2/2
✓ Branch 0 taken 1089 times.
✓ Branch 1 taken 241 times.
1330 if (loc==-1)
501 {
502
1/2
✓ Branch 0 taken 1089 times.
✗ Branch 1 not taken.
1089 verifysnespos();
503 1089 loc = snespos;
504 // if base is not active:
505
2/2
✓ Branch 0 taken 837 times.
✓ Branch 1 taken 252 times.
1089 if(snespos == realsnespos) lbl_fs_id = freespaceid;
506 // if base is active, always treat the label as freespace 0, i.e. not freespace.
507 }
508
509 1330 snes_label label_data;
510 1330 label_data.pos = (unsigned int)loc;
511 1330 label_data.is_static = is_static;
512 1330 label_data.freespace_id = lbl_fs_id;
513
514 unsigned int labelpos;
515
2/2
✓ Branch 0 taken 442 times.
✓ Branch 1 taken 888 times.
1330 if (pass==0)
516 {
517
3/4
✓ Branch 0 taken 442 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 440 times.
442 if (labels.exists(name))
518 {
519 2 movinglabelspossible=true;
520
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 throw_err_block(0, err_label_redefined, name.data());
521 }
522
1/2
✓ Branch 0 taken 440 times.
✗ Branch 1 not taken.
440 labels.create(name) = label_data;
523 }
524
2/2
✓ Branch 0 taken 444 times.
✓ Branch 1 taken 444 times.
888 else if (pass==1)
525 {
526
1/2
✓ Branch 0 taken 444 times.
✗ Branch 1 not taken.
444 labels.create(name) = label_data;
527 }
528
1/2
✓ Branch 0 taken 444 times.
✗ Branch 1 not taken.
444 else if (pass==2)
529 {
530 //all label locations are known at this point, add a sanity check
531
2/6
✓ Branch 0 taken 444 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 444 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
444 if (!labels.exists(name)) throw_err_block(2, err_internal_error, "label created on 3rd pass");
532
1/2
✓ Branch 0 taken 444 times.
✗ Branch 1 not taken.
444 labelpos = labels.find(name).pos;
533
5/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 438 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
444 if ((int)labelpos != loc && !movinglabelspossible)
534 {
535
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
6 if((unsigned int)loc>>16 != labelpos>>16) throw_err_block(2, err_label_ambiguous, name.data());
536
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
6 else if(labelpos == (dp_base + 0xFFu)) throw_err_block(2, err_label_ambiguous, name.data());
537
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 else if(errored) return;
538 else throw_err_block(2, err_internal_error, "moving label");
539 }
540 }
541 }
542
543 table thetable;
544 static autoarray<table> tablestack;
545
546 844 static void cleartable()
547 {
548
4/7
✓ Branch 0 taken 374 times.
✓ Branch 1 taken 470 times.
✓ Branch 2 taken 374 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 470 times.
✗ Branch 6 not taken.
844 thetable = table();
549 844 }
550
551 struct pushable {
552 int arch;
553 int snespos;
554 int snesstart;
555 int snesposreal;
556 int snesstartreal;
557 int freeid;
558 int freest;
559 int arch1;
560 int arch2;
561 int arch3;
562 int arch4;
563 };
564 static autoarray<pushable> pushpc;
565 static int pushpcnum;
566
567 static autoarray<int> basestack;
568 static int basestacknum;
569
570 struct ns_pushable {
571 string ns;
572 autoarray<string> namespace_list;
573 bool nested_namespaces;
574 };
575
576 static autoarray<ns_pushable> pushns;
577 static int pushnsnum;
578
579
580 static unsigned char fillbyte[12];
581 static unsigned char padbyte[12];
582
583 static bool nested_namespaces = false;
584
585 48394 void checkbankcross()
586 {
587
4/4
✓ Branch 0 taken 4618 times.
✓ Branch 1 taken 43776 times.
✓ Branch 2 taken 4693 times.
✓ Branch 3 taken 19684 times.
48394 if (!snespos_valid) return;
588
4/4
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 38894 times.
✓ Branch 2 taken 189 times.
✓ Branch 3 taken 19495 times.
39083 if (disable_bank_cross_errors) return;
589
4/4
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 38559 times.
✓ Branch 2 taken 146 times.
✓ Branch 3 taken 19349 times.
38705 unsigned int mask = 0x7FFF0000 | (check_half_banks_crossed ? 0x8000 : 0);
590
4/4
✓ Branch 0 taken 591 times.
✓ Branch 1 taken 38114 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 587 times.
38705 if (((snespos^startpos) & mask) && (((snespos - 1) ^ startpos) & mask))
591 {
592 4 throw_err_fatal(pass, err_bank_border_crossed, snespos);
593 }
594 // don't verify realsnespos when using norom. this allows making custom mappers where the file layout doesn't follow bank borders
595
7/8
✓ Branch 0 taken 19067 times.
✓ Branch 1 taken 19634 times.
✓ Branch 2 taken 19599 times.
✓ Branch 3 taken 18961 times.
✓ Branch 4 taken 301 times.
✓ Branch 5 taken 19298 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 301 times.
38701 else if (mapper != norom && ((realsnespos^realstartpos) & mask) && (((realsnespos - 1) ^ realstartpos) & mask))
596 {
597 throw_err_fatal(pass, err_bank_border_crossed, realsnespos);
598 }
599 }
600
601 3309 static void freespaceend()
602 {
603
2/2
✓ Branch 0 taken 1572 times.
✓ Branch 1 taken 1737 times.
3309 if (freespaceid > 0)
604 {
605 1572 freespaces[freespaceid].len = realsnespos-freespacestart;
606 1572 snespos=(int)0xFFFFFFFF;
607 1572 snespos_valid = false;
608 }
609 3309 freespaceid = 0;
610 3309 }
611
612 2544 static void adddefine(const string & key, string & value)
613 {
614
2/4
✓ Branch 0 taken 1113 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1431 times.
✗ Branch 3 not taken.
2544 if (!defines.exists(key)) defines.create(key) = value;
615 2544 }
616
617 838 void initstuff()
618 {
619
2/2
✓ Branch 0 taken 286 times.
✓ Branch 1 taken 552 times.
838 if (pass==0)
620 {
621 286 freespaces.reset();
622 286 movinglabelspossible = false;
623 286 found_rats_tags_initialized = false;
624 286 found_rats_tags.clear();
625 }
626 838 arch=arch_65816;
627 838 mapper=lorom;
628 838 mapper_set = false;
629 838 calledmacros = 0;
630 838 reallycalledmacros = 0;
631 838 macrorecursion = 0;
632 838 defines.reset();
633 838 builtindefines.each(adddefine);
634 838 clidefines.each(adddefine);
635 838 ns="";
636 838 namespace_list.reset();
637 838 sublabels.reset();
638 838 poslabels.reset();
639 838 neglabels.reset();
640 838 macroposlabels = nullptr;
641 838 macroneglabels = nullptr;
642 838 macrosublabels = nullptr;
643 838 cleartable();
644 838 pushpc.reset();
645 838 pushpcnum=0;
646 838 pushns.reset();
647 838 pushnsnum = 0;
648 838 bytes=0;
649 838 freespaceuse=0;
650
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 467 times.
838 memset(fillbyte, 0, sizeof(fillbyte));
651
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 467 times.
838 memset(padbyte, 0, sizeof(padbyte));
652 838 snespos_valid = false;
653 838 snespos=(int)0xFFFFFFFF;
654 838 realsnespos= (int)0xFFFFFFFF;
655 838 startpos= (int)0xFFFFFFFF;
656 838 realstartpos= (int)0xFFFFFFFF;
657 838 freespaceidnext=1;
658 838 freespaceid=0;
659 838 freespacebyte=0x00;
660 838 incsrcdepth = 0;
661
662 838 optimizeforbank = -1;
663 838 optimize_dp = optimize_dp_flag::ALWAYS;
664 838 dp_base = 0;
665 838 optimize_address = optimize_address_flag::MIRRORS;
666
667 838 in_struct = false;
668 838 in_sub_struct = false;
669 838 in_spcblock = false;
670
671 838 disable_bank_cross_errors = false;
672 838 check_half_banks_crossed = false;
673 838 nested_namespaces = false;
674
675 838 includeonce.reset();
676
677 extern AddressToLineMapping addressToLineMapping;
678 838 addressToLineMapping.reset();
679
680 838 push_warnings(false);
681
682 838 initmathcore();
683
684 1305 default_freespace_settings = {};
685 838 default_freespace_settings.bank = -3;
686 838 default_freespace_settings.search_start = -1;
687 838 default_freespace_settings.write_rats = true;
688 // rest are initialized to false/0/empty string
689
690 838 callstack.clear();
691 #if defined(_WIN32) || !defined(NO_USE_THREADS)
692 838 init_stack_use_check();
693 #endif
694 838 }
695
696 1572 static void parse_freespace_arguments(freespace_data& thisfs, string& arguments) {
697
3/3
✓ Branch 0 taken 105 times.
✓ Branch 1 taken 786 times.
✓ Branch 2 taken 681 times.
1572 if(arguments == "") return;
698
2/4
✓ Branch 0 taken 681 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 681 times.
✗ Branch 3 not taken.
1362 autoptr<char**> pars=qpsplit(arguments.temp_raw(), ',');
699
700
4/4
✓ Branch 0 taken 690 times.
✓ Branch 1 taken 681 times.
✓ Branch 2 taken 690 times.
✓ Branch 3 taken 681 times.
2742 for (int i=0;pars[i];i++)
701 {
702
3/6
✓ Branch 0 taken 690 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1380 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 690 times.
1380 if (!stricmp(pars[i], "ram")) { thisfs.bank = -2; }
703
5/6
✓ Branch 0 taken 690 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1377 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 687 times.
1380 else if (!stricmp(pars[i], "noram")) { thisfs.bank = -1; }
704
5/6
✓ Branch 0 taken 687 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1368 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 681 times.
1374 else if (!stricmp(pars[i], "static")) { thisfs.is_static = true; }
705
3/6
✓ Branch 0 taken 681 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1362 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 681 times.
1362 else if (!stricmp(pars[i], "nostatic")) { thisfs.is_static = false; }
706
5/6
✓ Branch 0 taken 681 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1356 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 675 times.
1362 else if (!stricmp(pars[i], "align")) { thisfs.flag_align = true; }
707
3/6
✓ Branch 0 taken 675 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1350 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 675 times.
1350 else if (!stricmp(pars[i], "noalign")) { thisfs.flag_align = false; }
708
5/6
✓ Branch 0 taken 675 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 636 times.
✓ Branch 3 taken 714 times.
✓ Branch 4 taken 636 times.
✓ Branch 5 taken 39 times.
1350 else if (!stricmp(pars[i], "cleaned")) { thisfs.flag_cleaned = true; }
709
3/6
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 39 times.
78 else if (!stricmp(pars[i], "nocleaned")) { thisfs.flag_cleaned = false; }
710
3/6
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 39 times.
78 else if (!stricmp(pars[i], "rats")) { thisfs.write_rats = true; }
711
3/6
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 39 times.
78 else if (!stricmp(pars[i], "norats")) { thisfs.write_rats = false; }
712
3/6
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 39 times.
78 else if (!stricmp(pars[i], "bankcross")) { thisfs.allow_bankcross = true; }
713
3/6
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 39 times.
78 else if (!stricmp(pars[i], "nobankcross")) { thisfs.allow_bankcross = false; }
714
4/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 24 times.
78 else if (stribegin(pars[i], "bank="))
715 {
716
6/11
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 15 times.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 15 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 15 times.
✗ Branch 10 not taken.
30 thisfs.bank = parse_math_expr(pars[i] + 5)->evaluate_static().get_integer();
717 }
718
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 12 times.
48 else if (stribegin(pars[i], "start="))
719 {
720
6/11
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 12 times.
✗ Branch 10 not taken.
24 thisfs.search_start = parse_math_expr(pars[i] + 6)->evaluate_static().get_integer();
721 }
722
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
24 else if (stribegin(pars[i], "pin="))
723 {
724 // TODO: should we handle posneg labels here too?
725
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
24 string pin_to = pars[i] + 4;
726 24 const char* pin_to_c = pin_to.data();
727
2/3
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
24 thisfs.pin_target = labelname(&pin_to_c);
728
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
24 if(*pin_to_c) throw_err_block(0, err_invalid_label_name);
729 // this is to throw an "undefined label" error with the proper callstack
730
6/8
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
24 if(pass) labelval(pin_to);
731
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
24 thisfs.pin_target_ns = ns;
732 24 }
733 else throw_err_block(0, err_invalid_freespace_request);
734 }
735 1362 }
736
737 530 static int get_freespace_pin_target(int target_id) {
738 // union-find algorithm
739
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 265 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 265 times.
534 while(freespaces[target_id].pin_target_id != target_id) {
740 // i love programming
741 6 freespaces[target_id].pin_target_id =
742 4 freespaces[freespaces[target_id].pin_target_id].pin_target_id;
743 4 target_id = freespaces[target_id].pin_target_id;
744 }
745 530 return target_id;
746 }
747
748 276 static void resolve_pinned_freespaces() {
749
2/2
✓ Branch 0 taken 522 times.
✓ Branch 1 taken 276 times.
798 for(int i = 1; i < freespaces.count; i++)
750 // default to everyone being in a separate component
751 522 freespaces[i].pin_target_id = i;
752
2/2
✓ Branch 0 taken 522 times.
✓ Branch 1 taken 276 times.
798 for(int i = 1; i < freespaces.count; i++) {
753
1/2
✓ Branch 0 taken 522 times.
✗ Branch 1 not taken.
522 freespace_data& fs = freespaces[i];
754
4/4
✓ Branch 0 taken 257 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 257 times.
✓ Branch 3 taken 4 times.
522 if(fs.pin_target == "") continue;
755 8 snes_label value;
756
7/29
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ 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.
✗ Branch 8 not taken.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 4 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 20 taken 4 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 4 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 4 times.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
8 if(fs.pin_target_ns && labels.exists(fs.pin_target_ns + fs.pin_target))
757 value = labels.find(fs.pin_target_ns + fs.pin_target);
758
4/7
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
8 else if(labels.exists(fs.pin_target))
759
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
8 value = labels.find(fs.pin_target);
760 else continue; // the error for this is thrown in the freespace command during pass 2
761
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 fs.pin_target_id = get_freespace_pin_target(value.freespace_id);
762 8 fs.len = 0;
763 }
764 276 }
765
766 276 static void allocate_freespaces() {
767 // compute real size of all pinned freespace blocks
768
2/2
✓ Branch 0 taken 522 times.
✓ Branch 1 taken 276 times.
798 for(int i = 1; i < freespaces.count; i++) {
769 522 freespace_data& fs = freespaces[i];
770 // just in case the pin target changed again or something
771 522 fs.pin_target_id = get_freespace_pin_target(fs.pin_target_id);
772 522 freespace_data& target = freespaces[fs.pin_target_id];
773 522 target.total_len += fs.len;
774 522 target.search_start = std::max(fs.search_start, target.search_start);
775 }
776
777
2/2
✓ Branch 0 taken 522 times.
✓ Branch 1 taken 276 times.
798 for(int i = 1; i < freespaces.count; i++) {
778 522 freespace_data& fs = freespaces[i];
779
7/7
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 259 times.
✓ Branch 2 taken 262 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 259 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
522 if(fs.is_static && fs.orgpos > 0) {
780 2 fs.pos = fs.orgpos;
781 2 continue;
782 }
783 // if this freespace is pinned to another one, set it later
784
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 257 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 257 times.
520 if(fs.pin_target_id != i) continue;
785 // TODO: possibly fancier align
786
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 257 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 257 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 257 times.
514 fs.pos = getsnesfreespace(fs.total_len, fs.bank, true, !fs.allow_bankcross, fs.flag_align, fs.write_rats, fs.search_start);
787 514 fs.used_len = fs.len;
788 }
789 // set pos for all pinned freespaces
790
2/2
✓ Branch 0 taken 522 times.
✓ Branch 1 taken 276 times.
798 for(int i = 1; i < freespaces.count; i++) {
791 522 freespace_data& fs = freespaces[i];
792
4/4
✓ Branch 0 taken 258 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 258 times.
✓ Branch 3 taken 3 times.
522 if(fs.pin_target_id == i) continue;
793 6 freespace_data& tgt = freespaces[fs.pin_target_id];
794 6 fs.pos = tgt.pos + tgt.used_len;
795 6 tgt.used_len += fs.len;
796 }
797
798 // relocate all labels that were in freespace to point them to their real location
799 276 labels.each([](const char * key, snes_label & val) {
800
4/4
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 171 times.
✓ Branch 2 taken 45 times.
✓ Branch 3 taken 181 times.
442 if(val.freespace_id != 0) {
801 90 val.pos += freespaces[val.freespace_id].pos;
802 }
803 442 });
804 276 }
805
806 828 void finishpass()
807 {
808 828 verify_warnings();
809 828 pull_warnings(false);
810
811
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 828 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 462 times.
828 if(in_spcblock) throw_err_block(0, err_missing_endspcblock);
812
6/8
✓ Branch 0 taken 366 times.
✓ Branch 1 taken 462 times.
✓ Branch 2 taken 462 times.
✓ Branch 3 taken 366 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 462 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 462 times.
828 if (in_struct || in_sub_struct) throw_err_null(0, err_struct_without_endstruct);
813
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 828 times.
828 else if (pushpcnum) throw_err_null(0, err_pushpc_without_pullpc);
814
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 828 times.
828 else if (pushnsnum) throw_err_null(0, err_pushns_without_pullns);
815 828 freespaceend();
816
817 828 deinitmathcore();
818
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 552 times.
828 if(pass == 0) {
819 276 resolve_pinned_freespaces();
820
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 276 times.
552 } else if(pass == 1) {
821 276 allocate_freespaces();
822 276 handle_cleared_rats_tags();
823 }
824 #if defined(_WIN32) || !defined(NO_USE_THREADS)
825 828 deinit_stack_use_check();
826 #endif
827 828 }
828
829 32519 static bool addlabel(const char * label, int pos=-1, bool global_label = false)
830 {
831
4/6
✓ Branch 0 taken 16108 times.
✓ Branch 1 taken 16411 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16108 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 16411 times.
32519 if (!label[0] || label[0]==':') return false;//colons are reserved for special labels
832
833 32519 const char* posneglabel = label;
834
2/3
✓ Branch 0 taken 16108 times.
✓ Branch 1 taken 16411 times.
✗ Branch 2 not taken.
32519 string posnegname = posneglabelname(&posneglabel, true);
835
836
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 32393 times.
32519 if (posnegname.length() > 0)
837 {
838
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 if (global_label) return false;
839
5/9
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 54 times.
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
126 if (*posneglabel != '\0' && *posneglabel != ':') throw_err_block(0, err_broken_label_definition);
840
4/6
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 66 times.
✗ Branch 5 not taken.
126 setlabel(posnegname, pos);
841 126 return true;
842 }
843
11/13
✓ Branch 0 taken 15577 times.
✓ Branch 1 taken 16816 times.
✓ Branch 2 taken 15547 times.
✓ Branch 3 taken 30 times.
✓ Branch 4 taken 31400 times.
✓ Branch 5 taken 492 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 31367 times.
✓ Branch 8 taken 33 times.
✓ Branch 9 taken 15820 times.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 15820 times.
32393 if (label[strlen(label)-1]==':' || label[0]=='.' || label[0]=='?' || label[0] == '#')
844 {
845
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 498 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 519 times.
1029 if (!label[1]) return false;
846
10/12
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 975 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 39 times.
✓ Branch 8 taken 21 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✓ Branch 11 taken 18 times.
1017 if(global_label && (in_struct || in_sub_struct || label[0]=='?')) return false;
847
848 1011 bool define = true;
849
850
3/3
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 495 times.
✓ Branch 2 taken 504 times.
1011 if (label[0] == '#')
851 {
852 24 define = false;
853 24 label++;
854 }
855
856 // RPG Hacker: Also checking label[1] now, since it might be a macro sublabel.
857 // Also, apparently this here doesn't account for main labels. I guess because
858 // we don't even get here in the first place if they don't include a colon?
859
13/15
✓ Branch 0 taken 342 times.
✓ Branch 1 taken 510 times.
✓ Branch 2 taken 498 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 333 times.
✓ Branch 5 taken 360 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 333 times.
✓ Branch 8 taken 354 times.
✓ Branch 9 taken 348 times.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 348 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 348 times.
1011 bool requirecolon = (label[0] != '.' && label[1] != '.') && (in_struct || in_sub_struct);
860
3/3
✓ Branch 0 taken 486 times.
✓ Branch 1 taken 516 times.
✓ Branch 2 taken 9 times.
1011 string name=labelname(&label, define, true);
861
3/3
✓ Branch 0 taken 453 times.
✓ Branch 1 taken 504 times.
✓ Branch 2 taken 36 times.
993 if (label[0]==':') label++;
862
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
69 else if (requirecolon) throw_err_block(0, err_broken_label_definition);
863
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 63 times.
69 else if (global_label) return false;
864
4/6
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 483 times.
✓ Branch 2 taken 504 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
987 if (label[0]) throw_err_block(0, err_broken_label_definition);
865
8/9
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 852 times.
✓ Branch 2 taken 99 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 99 times.
✓ Branch 5 taken 864 times.
✓ Branch 6 taken 48 times.
✓ Branch 7 taken 51 times.
✗ Branch 8 not taken.
963 if (ns && !global_label) name=ns+name;
866
15/16
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 591 times.
✓ Branch 2 taken 405 times.
✓ Branch 3 taken 459 times.
✓ Branch 4 taken 81 times.
✓ Branch 5 taken 423 times.
✓ Branch 6 taken 483 times.
✓ Branch 7 taken 381 times.
✓ Branch 8 taken 469 times.
✓ Branch 9 taken 113 times.
✓ Branch 10 taken 81 times.
✓ Branch 11 taken 30 times.
✓ Branch 12 taken 492 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 490 times.
✓ Branch 15 taken 2 times.
967 setlabel(name, pos, ((in_struct || in_sub_struct) && static_struct));
867 959 return true;
868 993 }
869 31364 return false;
870 32519 }
871
872 15589 static void add_addr_to_line(int pos)
873 {
874
2/2
✓ Branch 0 taken 5501 times.
✓ Branch 1 taken 10088 times.
15589 if (pass == 2)
875 5501 addressToLineMapping.includeMapping(get_current_file_name(), get_current_line() + 1, pos);
876 15589 }
877
878 static autoarray<bool> elsestatus;
879 int numtrue=0;//if 1 -> increase both
880 int numif = 0; //if 0 or inside if 0 -> increase only numif
881
882 autoarray<whiletracker> whilestatus;
883
884
885 112 static void push_pc()
886 {
887 112 pushpc[pushpcnum].arch=arch;
888 112 pushpc[pushpcnum].snespos=snespos;
889 112 pushpc[pushpcnum].snesstart=startpos;
890 112 pushpc[pushpcnum].snesposreal=realsnespos;
891 112 pushpc[pushpcnum].snesstartreal=realstartpos;
892 112 pushpc[pushpcnum].freeid=freespaceid;
893 112 pushpc[pushpcnum].freest=freespacestart;
894 112 pushpcnum++;
895 112 }
896
897 112 static void pop_pc()
898 {
899 112 pushpcnum--;
900 112 snespos=pushpc[pushpcnum].snespos;
901 112 startpos=pushpc[pushpcnum].snesstart;
902 112 realsnespos=pushpc[pushpcnum].snesposreal;
903 112 realstartpos=pushpc[pushpcnum].snesstartreal;
904 112 freespaceid=pushpc[pushpcnum].freeid;
905 112 freespacestart=pushpc[pushpcnum].freest;
906 112 }
907
908
909 378 static string handle_print(const char* input)
910 {
911 // evaluating this math can be unsafe in pass 0
912
3/4
✓ Branch 0 taken 248 times.
✓ Branch 1 taken 130 times.
✓ Branch 2 taken 248 times.
✗ Branch 3 not taken.
378 if(pass != 2) return "";
913 130 string out;
914
2/3
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
130 string buf = input;
915
2/3
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
130 autoptr<char**> pars = qpsplit(buf.raw(), ',');
916
1/2
✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
130 verify_paren(pars);
917
4/4
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 58 times.
✓ Branch 2 taken 110 times.
✓ Branch 3 taken 64 times.
333 for (int i = 0; pars[i]; i++)
918 {
919 if (0);
920 // leaving these here is kinda hacky, but whatever...
921
8/12
✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 209 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 108 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
211 else if (!stricmp(pars[i], "bytes")) out += dec(bytes);
922
8/12
✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 206 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 107 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
207 else if (!stricmp(pars[i], "freespaceuse")) out += dec(freespaceuse);
923
3/12
✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 205 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 107 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
205 else if (!stricmp(pars[i], "pc")) out += hex((unsigned int)(snespos & 0xFFFFFF), 6);
924 else {
925
5/6
✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 201 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 103 times.
✓ Branch 5 taken 4 times.
430 math_val value = parse_math_expr(pars[i])->evaluate();
926
2/4
✓ Branch 0 taken 197 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 197 times.
✗ Branch 3 not taken.
197 out += value.get_str();
927 197 }
928 }
929 122 return out;
930 351 }
931
932 114 void handle_autoclean(string& arg, int checkbyte, int write_pos)
933 {
934
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
114 if(freespaceid > 0) throw_err_block(0, err_autoclean_in_freespace);
935
936 114 const char* labeltest = arg.data();
937
1/2
✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
114 snes_label lblval = labelval(&labeltest);
938
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 57 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
114 if (*labeltest) throw_err_block(0, err_label_not_found, arg.data());
939 114 int num = lblval.pos;
940
1/2
✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
114 auto& targetfs = freespaces[lblval.freespace_id];
941
942
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 60 times.
114 if (pass == 1) {
943 54 targetfs.leaked = false;
944
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 6 times.
54 int orig_pos = read3(checkbyte != -1 ? write_pos+1 : write_pos);
945 54 int write_pos_pc = snestopc(write_pos);
946 54 targetfs.orgpos = targetfs.orglen = -1;
947
8/10
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 48 times.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 11 times.
✓ Branch 7 taken 13 times.
✓ Branch 8 taken 11 times.
✓ Branch 9 taken 13 times.
54 if(write_pos_pc >= 0 && write_pos_pc < romlen_r && (checkbyte == -1 || romdata_r[write_pos_pc] == checkbyte)) {
948
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 int rats_loc = ratsstart(orig_pos);
949
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 6 times.
28 if(rats_loc != -1) {
950 22 targetfs.orgpos = rats_loc + 8;
951 22 targetfs.orglen = read2(rats_loc + 4) + 1;
952
6/7
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
22 if(!targetfs.is_static) removerats(rats_loc + 8, freespacebyte);
953 }
954 }
955
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 6 times.
60 } else if(pass == 2) {
956
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 27 times.
54 if(targetfs.pos < 0) {
957 // this freespace failed to allocate.
958 // ratsstart is obviously not going to find a nonexistent freespace,
959 // and would error too, we don't need 2 errors about the same thing.
960 // especially if one of them is as weird as this one.
961 return;
962 }
963
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 int start = ratsstart(num);
964
2/6
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
54 if(start >= num || start < 0) throw_err_block(2, err_autoclean_label_at_freespace_end);
965 }
966 }
967
968 namespace {
969
970 template<void (*do_write)(unsigned int)>
971 9672 void cmd_write_data(const char* par) {
972 9672 int addrToLinePos = realsnespos & 0xFFFFFF;
973
2/3
✓ Branch 0 taken 2376 times.
✓ Branch 1 taken 2460 times.
✗ Branch 2 not taken.
9672 string line = par;
974
2/3
✓ Branch 0 taken 2376 times.
✓ Branch 1 taken 2460 times.
✗ Branch 2 not taken.
9672 autoptr<char**> pars=qpsplit(line.temp_raw(), ',');
975
1/2
✓ Branch 0 taken 4836 times.
✗ Branch 1 not taken.
9672 verify_paren(pars);
976
977
4/4
✓ Branch 0 taken 2782 times.
✓ Branch 1 taken 2363 times.
✓ Branch 2 taken 2908 times.
✓ Branch 3 taken 2447 times.
21000 for (int i=0;pars[i];i++)
978 {
979
4/4
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 2671 times.
✓ Branch 2 taken 114 times.
✓ Branch 3 taken 2794 times.
11380 if (pars[i][0]=='"') {
980
2/4
✓ Branch 0 taken 111 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 114 times.
✗ Branch 3 not taken.
450 const char * str = safedequote(pars[i]);
981 450 int codepoint = 0u;
982
1/2
✓ Branch 0 taken 225 times.
✗ Branch 1 not taken.
450 str += utf8_val(&codepoint, str);
983
3/4
✓ Branch 0 taken 918 times.
✓ Branch 1 taken 225 times.
✓ Branch 2 taken 918 times.
✗ Branch 3 not taken.
2286 while ( codepoint != 0 && codepoint != -1 )
984 {
985
2/4
✓ Branch 0 taken 918 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 918 times.
✗ Branch 3 not taken.
1836 do_write(thetable.get_val(codepoint));
986
1/2
✓ Branch 0 taken 918 times.
✗ Branch 1 not taken.
1836 str += utf8_val(&codepoint, str);
987 }
988
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 225 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
450 if (codepoint == -1) throw_err_block(0, err_invalid_utf8);
989 } else {
990
38/46
✓ Branch 0 taken 1817 times.
✓ Branch 1 taken 3648 times.
✓ Branch 2 taken 880 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 1796 times.
✓ Branch 5 taken 13 times.
✓ Branch 6 taken 875 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2658 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 875 times.
✓ Branch 11 taken 2699 times.
✓ Branch 12 taken 880 times.
✓ Branch 13 taken 1783 times.
✓ Branch 14 taken 875 times.
✓ Branch 15 taken 2699 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 13 times.
✓ Branch 18 taken 2786 times.
✓ Branch 19 taken 8 times.
✓ Branch 20 taken 921 times.
✓ Branch 21 taken 1873 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 916 times.
✓ Branch 24 taken 1865 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 916 times.
✓ Branch 27 taken 1865 times.
✓ Branch 28 taken 916 times.
✓ Branch 29 taken 1865 times.
✓ Branch 30 taken 916 times.
✓ Branch 31 taken 1865 times.
✓ Branch 32 taken 916 times.
✓ Branch 33 taken 1865 times.
✗ Branch 34 not taken.
✓ Branch 35 taken 13 times.
✓ Branch 36 taken 13 times.
✗ Branch 37 not taken.
✓ Branch 38 taken 5 times.
✓ Branch 39 taken 8 times.
✓ Branch 40 taken 5 times.
✓ Branch 41 taken 8 times.
✓ Branch 42 taken 5 times.
✓ Branch 43 taken 8 times.
✓ Branch 44 taken 13 times.
✗ Branch 45 not taken.
14740 do_write((pass==2) ? parse_math_expr(pars[i])->evaluate().get_integer() : 0);
991 }
992 }
993
1/2
✓ Branch 0 taken 4810 times.
✗ Branch 1 not taken.
9620 add_addr_to_line(addrToLinePos);
994 18220 }
995
996 336 void cmd_assert(const char* par) {
997
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 165 times.
✓ Branch 2 taken 171 times.
336 if(!*par) {
998 throw_err_block(0, err_broken_command, "assert", "Missing condition.");
999 }
1000 // todo optimize after adding some math helpers
1001 336 const char* message_start = strqpchr(par, ',');
1002
1003 bool cond;
1004
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 306 times.
336 if(message_start) {
1005
2/3
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
30 string cond_str(par, message_start - par);
1006
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 cond = getnum(cond_str);
1007 30 message_start++; // eat the comma
1008 30 } else {
1009 306 cond = getnum(par);
1010 }
1011
1012
4/4
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 172 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 74 times.
258 if (pass == 2 && !cond)
1013 {
1014
9/15
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 3 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
✗ Branch 14 not taken.
36 if (message_start) throw_err_block(2, err_assertion_failed, (string(": ") + handle_print(message_start)).data());
1015 6 else throw_err_block(2, err_assertion_failed, ".");
1016 }
1017 246 }
1018
1019 120 void cmd_undef(const char* par) {
1020
2/3
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
120 string temp = par;
1021
4/6
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 60 times.
✗ Branch 5 not taken.
120 string def = safedequote(temp.raw());
1022
4/5
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
✓ Branch 4 taken 60 times.
120 if (builtindefines.exists(def)) {
1023 throw_err_line(0, err_overriding_builtin_define, def.data());
1024 }
1025
1026
5/5
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 57 times.
✓ Branch 3 taken 60 times.
✓ Branch 4 taken 3 times.
120 if (defines.exists(def)) {
1027
2/3
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
114 defines.remove(def);
1028 } else {
1029
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 throw_err_block(0, err_define_not_found, def.data());
1030 }
1031 183 }
1032
1033 21 void cmd_error(const char* par) {
1034
3/3
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 9 times.
21 if(!*par)
1035
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 throw_err_block(0, err_error_command, ".");
1036
2/3
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
15 string out = handle_print(par);
1037
5/11
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 9 times.
✗ Branch 10 not taken.
54 throw_err_block(2, err_error_command, (string(": ") + out).data());
1038 15 }
1039
1040 39 void cmd_warn(const char* par) {
1041
3/3
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 21 times.
39 if(!*par) {
1042
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 throw_warning(0, warn_warn_command, ".");
1043 6 return;
1044 }
1045
2/3
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
33 string out = handle_print(par);
1046
5/11
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 21 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 21 times.
✗ Branch 10 not taken.
33 throw_warning(2, warn_warn_command, (string(": ") + out).data());
1047 33 }
1048
1049 132 void cmd_warnings(char** words, int numwords) {
1050
7/7
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 84 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 66 times.
✓ Branch 6 taken 54 times.
132 if(numwords == 1 && !stricmpwithlower(words[0], "push")) {
1051 24 push_warnings();
1052
7/7
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 84 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 54 times.
✓ Branch 6 taken 42 times.
108 } else if(numwords == 1 && !stricmpwithlower(words[0], "pull")) {
1053 24 pull_warnings();
1054
6/7
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 42 times.
✓ Branch 4 taken 42 times.
✓ Branch 5 taken 42 times.
✓ Branch 6 taken 33 times.
84 } else if(numwords == 2 && !stricmpwithlower(words[0], "enable")) {
1055 18 asar_warning_id warnid = parse_warning_id_from_string(words[1]);
1056
1057
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
18 if (warnid != warning_id_end) {
1058 12 set_warning_enabled(warnid, true);
1059 } else {
1060 6 throw_warning(0, warn_invalid_warning_id, words[1], "warnings enable");
1061 }
1062
5/7
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 33 times.
✓ Branch 4 taken 33 times.
✓ Branch 5 taken 33 times.
✗ Branch 6 not taken.
66 } else if(numwords == 2 && !stricmpwithlower(words[0], "disable")) {
1063 66 asar_warning_id warnid = parse_warning_id_from_string(words[1]);
1064
1065
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 12 times.
66 if (warnid != warning_id_end) {
1066 54 set_warning_enabled(warnid, false);
1067 } else {
1068 12 throw_warning(0, warn_invalid_warning_id, words[1], "warnings disable");
1069 }
1070 } else {
1071 throw_err_block(0, err_broken_command, "warnings", "Unknown parameter");
1072 }
1073 126 }
1074
1075 42 void cmd_global(const char* par) {
1076
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 30 times.
42 if(!addlabel(par, -1, true)) {
1077 12 throw_err_block(1, err_invalid_global_label, par);
1078 }
1079 30 }
1080
1081 70 void cmd_check(char** words, int numwords) {
1082
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 if(numwords != 2) throw_err_block(0, err_invalid_check);
1083
1084
3/3
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 35 times.
✓ Branch 2 taken 32 times.
70 if(!stricmpwithlower(words[0], "title")) {
1085 // RPG Hacker: Removed trimming for now - I think requiring an exact match is probably
1086 // better here (not sure, though, it's worth discussing)
1087
3/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
6 string expected_title = safedequote(words[1]);
1088 // in hirom the rom needs to be an entire bank for it to have a title, other modes only need 0x8000 bytes
1089
7/10
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
6 if (romlen < ((mapper == hirom || mapper == exhirom) ? 0x10000 : 0x8000)) // too short
1090 {
1091 if (!ignoretitleerrors) // title errors shouldn't be ignored
1092 throw_err_block(0, err_rom_too_short, expected_title.data());
1093 else // title errors should be ignored, throw a warning anyways
1094 throw_warning(0, warn_rom_too_short, expected_title.data());
1095 } else {
1096 6 string actual_title;
1097 6 string actual_display_title;
1098
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 6 times.
132 for (int i = 0;i < 21;i++)
1099 {
1100 126 unsigned char c = romdata[snestopc(0x00FFC0 + i)];
1101
1/2
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
126 actual_title += (char)c;
1102 // the replacements are from interface-cli.cpp
1103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 if (c == 7) c = 14;
1104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 if (c == 8) c = 27;
1105
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 if (c == 9) c = 26;
1106
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 if (c == '\r') c = 17;
1107
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 if (c == '\n') c = 25;
1108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 if (c == '\0') c = 155;
1109
1/2
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
126 actual_display_title += (char)c;
1110 }
1111
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
6 if (strncmp(expected_title, actual_title, 21) != 0)
1112 {
1113 if (!ignoretitleerrors) // title errors shouldn't be ignored
1114 throw_err_block(0, err_rom_title_incorrect, expected_title.data(), actual_display_title.data());
1115 else // title errors should be ignored, throw a warning anyways
1116 throw_warning(0, warn_rom_title_incorrect, expected_title.data(), actual_display_title.data());
1117 }
1118 6 }
1119
2/3
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
70 } else if(!stricmpwithlower(words[0], "bankcross")) {
1120
4/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 17 times.
64 if(!stricmpwithlower(words[1], "off")) {
1121 30 disable_bank_cross_errors = true;
1122
4/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 1 times.
34 } else if(!stricmpwithlower(words[1], "half")) {
1123 32 disable_bank_cross_errors = false;
1124 32 check_half_banks_crossed = true;
1125
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 } else if(!stricmpwithlower(words[1], "full")) {
1126 2 disable_bank_cross_errors = false;
1127 2 check_half_banks_crossed = false;
1128 } else {
1129 throw_err_block(0, err_invalid_check);
1130 }
1131 } else {
1132 throw_err_block(0, err_invalid_check);
1133 }
1134 70 }
1135
1136 36 void cmd_asar(const char* par) {
1137
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
36 if(!asarverallowed) throw_err_block(0, err_start_of_file);
1138
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 18 times.
51 if(!*par) return;
1139 36 int dots = 0;
1140 36 int dig = 0;
1141
4/4
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 75 times.
✓ Branch 3 taken 18 times.
186 for (int i=0;par[i];i++)
1142 {
1143
4/4
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 54 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 54 times.
150 if (par[i]=='.')
1144 {
1145
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
42 if (!dig) throw_err_block(0, err_invalid_version_number);
1146 42 dig=0;
1147 42 dots++;
1148 }
1149
2/4
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
108 else if (is_digit(par[i])) dig++;
1150 else throw_err_block(0, err_invalid_version_number);
1151 }
1152
3/8
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 36 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
36 if (!dig || !dots || dots>2) throw_err_block(0, err_invalid_version_number);
1153
2/3
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
36 string vers_buf = par;
1154
2/3
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
36 autoptr<char**> vers = split(vers_buf.raw(), '.');
1155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
36 int vermaj=atoi(vers[0]);
1156
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
36 if (vermaj > asarver_maj) throw_err_fatal(pass, err_asar_too_old);
1157
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 6 times.
36 if (vermaj < asarver_maj) return;
1158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (dots==1) {
1159 // todo: probably want to allow some more stuff here (it bans "asar 2.0" right now)
1160 if (strlen(vers[1])!=2) throw_err_block(0, err_invalid_version_number);
1161 int verminbug=atoi(vers[1]);
1162 int tmpver=asarver_bug;
1163 if (tmpver>9) tmpver=9;
1164 if (asarver_min*10+tmpver<verminbug) throw_err_fatal(pass, err_asar_too_old);
1165 } else {
1166
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
6 int vermin = atoi(vers[1]);
1167
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
6 if (vermin > asarver_min) throw_err_fatal(pass, err_asar_too_old);
1168
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
6 int verbug = atoi(vers[2]);
1169
2/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
6 if (vermin == asarver_min && verbug > asarver_bug) throw_err_fatal(pass, err_asar_too_old);
1170 }
1171
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 30 times.
66 }
1172
1173 2 void cmd_include(const char* par) {
1174
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
2 if(!asarverallowed) throw_err_block(0, err_start_of_file);
1175
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
2 if(*par) throw_err_block(0, err_broken_command, "include", "");
1176
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(in_top_level_file()) throw_err_fatal(pass, err_cant_be_main_file, "");
1177 }
1178
1179 6 void cmd_includefrom(const char* par) {
1180
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 if(!asarverallowed) throw_err_block(0, err_start_of_file);
1181 if(!*par) throw_err_block(0, err_broken_command, "include", "");
1182 if(in_top_level_file()) throw_err_fatal(pass, err_cant_be_main_file, (string(" The main file is '") + par + "'.").data());
1183 }
1184
1185 30 void cmd_includeonce(const char* par) {
1186
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
30 if(*par) throw_err_block(0, err_broken_command, "includeonce", "");
1187
1188 30 const char* current_file = get_current_file_name();
1189
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 if (!file_included_once(current_file))
1190 {
1191
4/7
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
30 includeonce.append(current_file);
1192 }
1193 30 }
1194
1195 909 void cmd_org(const char* par) {
1196
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 909 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 495 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
909 if(in_spcblock) throw_err_block(0, err_feature_unavaliable_in_spcblock);
1197
1/2
✓ Branch 0 taken 909 times.
✗ Branch 1 not taken.
909 freespaceend();
1198
2/3
✓ Branch 0 taken 414 times.
✓ Branch 1 taken 495 times.
✗ Branch 2 not taken.
909 auto math_expr = parse_math_expr(par);
1199
4/7
✓ Branch 0 taken 413 times.
✓ Branch 1 taken 495 times.
✓ Branch 2 taken 414 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 494 times.
✗ Branch 6 not taken.
909 int64_t num = math_expr->evaluate_non_forward().get_integer();
1200
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 907 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.
✗ Branch 8 not taken.
907 if (num&~0xFFFFFF) throw_err_block(1, err_snes_address_out_of_bounds, hex(num, 6).data());
1201
8/14
✓ Branch 0 taken 135 times.
✓ Branch 1 taken 772 times.
✓ Branch 2 taken 150 times.
✓ Branch 3 taken 479 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 428 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 144 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 350 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
907 if ((mapper==lorom || mapper==exlorom) && (num&0x408000)==0x400000 && (num&0x700000)!=0x700000) throw_warning(0, warn_set_middle_byte);
1202 907 snespos=(int)num;
1203 907 realsnespos=(int)num;
1204 907 startpos=(int)num;
1205 907 realstartpos=(int)num;
1206 907 snespos_valid = true;
1207 1403 }
1208
1209 114 void cmd_struct(char** words, int numwords) {
1210 //verifysnespos();
1211
6/8
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 57 times.
✓ Branch 3 taken 57 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 57 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 57 times.
114 if (in_struct || in_sub_struct) throw_err_block(0, err_nested_struct);
1212
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 114 times.
114 if (numwords < 1) throw_err_block(0, err_missing_struct_params);
1213
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 114 times.
114 if (numwords > 3) throw_err_block(0, err_too_many_struct_params);
1214
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 57 times.
114 if (!confirmname(words[0])) throw_err_block(0, err_invalid_struct_name);
1215
1216
7/7
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 27 times.
✓ Branch 5 taken 57 times.
✓ Branch 6 taken 57 times.
114 if (structs.exists(words[0]) && pass == 0) throw_err_block(0, err_struct_redefined, words[0]);
1217
1218 114 static_struct = false;
1219 114 old_snespos = snespos;
1220 114 old_startpos = startpos;
1221 114 old_optimizeforbank = optimizeforbank;
1222
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
114 old_snespos_valid = snespos_valid;
1223 114 unsigned int base = 0;
1224
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 66 times.
114 if (numwords == 2)
1225 {
1226 48 static_struct = true;
1227
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
48 auto base_expr = parse_math_expr(words[1]);
1228
4/7
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 23 times.
✗ Branch 6 not taken.
48 base = base_expr->evaluate_non_forward().get_integer();
1229
1230
4/8
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23 times.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 23 times.
46 if (base_expr->has_label() > 1) static_struct = false;
1231
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 14 times.
46 if (pass > 0) {
1232 // foundlabel_static isn't accurate anymore
1233
8/13
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 15 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 15 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 15 times.
32 if(structs.exists(words[0])) static_struct &= structs.find(words[0]).is_static;
1234 }
1235 48 }
1236
1237
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
112 bool old_in_struct = in_struct;
1238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
112 bool old_in_sub_struct = in_sub_struct;
1239
4/4
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 46 times.
✓ Branch 3 taken 30 times.
112 in_struct = numwords == 1 || numwords == 2;
1240 112 in_sub_struct = numwords == 3;
1241
1242 #define cleanup() (in_struct = old_in_struct, in_sub_struct = old_in_sub_struct)
1243
1244
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 66 times.
112 if (numwords == 2)
1245 {
1246
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 46 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.
✗ Branch 8 not taken.
46 if (base&~0xFFFFFF) cleanup(), throw_err_block(0, err_snes_address_out_of_bounds, hex((unsigned int)base, 6).data());
1247 46 snespos = (int)base;
1248 46 startpos = (int)base;
1249 }
1250
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 36 times.
66 else if (numwords == 3)
1251 {
1252
3/8
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
30 if (strcasecmp(words[1], "extends")) cleanup(), throw_err_block(0, err_missing_extends);
1253
3/9
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
30 if (!confirmname(words[2])) cleanup(), throw_err_block(0, err_struct_invalid_parent_name);
1254
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
30 string tmp_struct_parent = words[2];
1255
1256
2/6
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
30 if (!structs.exists(tmp_struct_parent)) cleanup(), throw_err_block(0, err_struct_not_found, tmp_struct_parent.data());
1257
4/7
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
30 snes_struct structure = structs.find(tmp_struct_parent);
1258
1259
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
30 static_struct = structure.is_static;
1260
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 struct_parent = tmp_struct_parent;
1261 30 snespos = structure.base_end;
1262 30 startpos = structure.base_end;
1263 30 }
1264
1265 112 push_pc();
1266
1267 112 optimizeforbank = -1;
1268
1269 112 struct_name = words[0];
1270 112 struct_base = snespos;
1271 112 realsnespos = 0;
1272 112 realstartpos = 0;
1273 112 snespos_valid = true;
1274
1275
4/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 97 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 41 times.
112 if(in_sub_struct) {
1276
3/7
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
30 string labelname = struct_parent + "." + struct_name;
1277
5/8
✓ 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.
✓ Branch 6 taken 15 times.
✗ Branch 7 not taken.
30 setlabel(ns + labelname, snespos, static_struct);
1278 30 } else {
1279
5/8
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 41 times.
✓ Branch 2 taken 41 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 41 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 41 times.
✗ Branch 7 not taken.
82 setlabel(ns + struct_name, snespos, static_struct);
1280 }
1281
1282 #undef cleanup
1283 112 }
1284
1285 114 void cmd_endstruct(char** words, int numwords) {
1286
3/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
114 if (numwords != 0 && numwords != 2) throw_err_block(0, err_invalid_endstruct_count);
1287
6/10
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 57 times.
✓ Branch 6 taken 57 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
114 if (numwords == 2 && stricmpwithlower(words[0], "align")) throw_err_block(0, err_expected_align);
1288
9/10
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 98 times.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 56 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 16 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 15 times.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
114 if (!in_struct && !in_sub_struct) throw_err_block(0, err_endstruct_without_struct);
1289
1290
4/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 106 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
112 int alignment = numwords == 2 ? (int)getnum(words[1]) : 1;
1291
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
112 if (alignment < 1) throw_err_block(0, err_alignment_too_small);
1292
1293 112 snes_struct structure;
1294 112 structure.base_end = snespos;
1295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
112 structure.struct_size = alignment * ((snespos - struct_base + alignment - 1) / alignment);
1296 112 structure.object_size = structure.struct_size;
1297
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
112 structure.is_static = static_struct;
1298
1299
4/4
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 71 times.
✓ Branch 2 taken 41 times.
✓ Branch 3 taken 15 times.
112 if (in_struct)
1300 {
1301
3/5
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 41 times.
✓ Branch 3 taken 41 times.
✗ Branch 4 not taken.
82 structs.create(struct_name) = structure;
1302 }
1303
3/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
30 else if (in_sub_struct)
1304 {
1305 30 snes_struct parent;
1306
3/5
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 15 times.
✗ Branch 4 not taken.
30 parent = structs.find(struct_parent);
1307
1308
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 6 times.
30 if (parent.object_size < parent.struct_size + structure.struct_size) {
1309 24 parent.object_size = parent.struct_size + structure.struct_size;
1310 }
1311
1312
7/13
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 15 times.
✓ Branch 6 taken 15 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 15 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 15 times.
✗ Branch 12 not taken.
30 structs.create(struct_parent + "." + struct_name) = structure;
1313
3/5
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 15 times.
✗ Branch 4 not taken.
30 structs.create(struct_parent) = parent;
1314 30 }
1315
1316
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 pop_pc();
1317 112 in_struct = false;
1318 112 in_sub_struct = false;
1319 112 snespos = old_snespos;
1320 112 startpos = old_startpos;
1321 112 optimizeforbank = old_optimizeforbank;
1322
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
112 snespos_valid = old_snespos_valid;
1323 112 static_struct = false;
1324 168 }
1325
1326 12 void cmd_spcblock(char** words, int num_words) {
1327 12 int addrToLinePos = realsnespos & 0xFFFFFF;
1328 //banned features when active: org, freespace(and variants), arch, mapper,namespace,pushns
1329
6/8
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 6 times.
12 if(in_struct || in_sub_struct) throw_err_block(0, err_spcblock_inside_struct);
1330
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if(num_words < 1) throw_err_block(0, err_spcblock_too_few_args);
1331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if(num_words > 3) throw_err_block(0, err_spcblock_too_many_args);
1332
1333 12 spcblock.destination = getnum(words[0]);
1334 12 spcblock.type = spcblock_nspc;
1335 12 spcblock.macro_name = "";
1336
1337
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 12 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.
✗ Branch 8 not taken.
12 if (spcblock.destination&~0xFFFF) throw_err_block(0, err_snes_address_out_of_bounds, hex(spcblock.destination, 6).data());
1338
1339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if(num_words == 2)
1340 {
1341 if(!stricmp(words[1], "nspc")) spcblock.type = spcblock_nspc;
1342 else if(!stricmp(words[1], "custom")) throw_err_block(0, err_custom_spcblock_missing_macro);
1343 else throw_err_block(0, err_unknown_spcblock_type);
1344 }
1345
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 else if(num_words == 3)
1346 {
1347 if(!stricmp(words[1], "custom")) spcblock.type = spcblock_custom;
1348 else throw_err_block(0, err_extra_spcblock_arg_for_type);
1349
1350 if(macros.exists(words[2]))
1351 {
1352 macrodata *macro = macros.find(words[2]);
1353 if(!macro->variadic) throw_err_block(0, err_spcblock_macro_must_be_varadic);
1354 if(macro->numargs != 3) throw_err_block(0, err_spcblock_macro_invalid_static_args);
1355 spcblock.macro_name = words[2];
1356 }
1357 else throw_err_block(0, err_spcblock_macro_doesnt_exist);
1358 }
1359
1360
3/5
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
12 switch(spcblock.type)
1361 {
1362 12 case spcblock_nspc:
1363 12 spcblock.size_address=realsnespos;
1364 12 write2(0x0000);
1365 12 write2(spcblock.destination);
1366 12 snespos=(int)spcblock.destination;
1367 12 startpos=(int)spcblock.destination;
1368 12 add_addr_to_line(addrToLinePos);
1369 12 break;
1370 case spcblock_custom:
1371 //this is a todo that probably won't be ready for 1.9
1372 //mostly so we can leverage some cleanups we make in 2.0 for practicality
1373 throw_err_block(0, err_spcblock_custom_types_incomplete);
1374 push_pc();
1375 spcblock.old_mapper = mapper;
1376 mapper = norom;
1377 break;
1378 default:
1379 throw_err_fatal(0, err_internal_error, "invalid spcblock type");
1380 }
1381
1382 12 ns_backup = ns;
1383
3/7
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
12 ns = STR":SPCBLOCK:_" + ns_backup;
1384 12 in_spcblock = true;
1385 12 }
1386
1387 12 void cmd_endspcblock(char** words, int num_words) {
1388
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
12 if(!in_spcblock) throw_err_block(0, err_endspcblock_without_spcblock);
1389
1390
3/5
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
12 switch(spcblock.type)
1391 {
1392 12 case spcblock_nspc:
1393
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
12 if (pass==2)
1394 {
1395 4 int pcpos=snestopc(spcblock.size_address&0xFFFFFF);
1396
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 4 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.
✗ Branch 8 not taken.
4 if (pcpos<0) throw_err_block(2, err_snes_address_doesnt_map_to_rom, hex((unsigned int)realsnespos, 6).data());
1397 // compute number of bytes written;
1398 // offset by 4 for the spcblock header itself
1399 4 int num = realsnespos - ((int)spcblock.size_address + 4);
1400 4 writeromdata_byte(pcpos, (unsigned char)num);
1401 4 writeromdata_byte(pcpos+1, (unsigned char)(num >> 8));
1402 }
1403
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (num_words == 2)
1404 {
1405 // todo allow spaces here
1406
3/5
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
6 if (strcmp(words[0], "execute")) throw_err_null(0, err_invalid_endspcblock_arg, words[0]);
1407 else
1408 {
1409 6 write2(0x0000);
1410
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 write2(pass == 2 ? (unsigned int)getnum(words[1]) : 0);
1411 }
1412 }
1413
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 else if (num_words != 0)
1414 {
1415 throw_err_null(0, err_unknown_endspcblock_format);
1416 }
1417 12 break;
1418 case spcblock_custom:
1419 mapper = spcblock.old_mapper;
1420 pop_pc();
1421 break;
1422 default:
1423 throw_err_fatal(0, err_internal_error, "invalid spcblock type");
1424 }
1425 12 ns = ns_backup;
1426 12 in_spcblock = false;
1427 12 snespos=realsnespos;
1428 12 startpos=realstartpos;
1429 12 }
1430
1431 102 void cmd_base(const char* par) {
1432
4/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 87 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 36 times.
102 if (!stricmp(par, "off"))
1433 {
1434 30 snespos=realsnespos;
1435 30 startpos=realstartpos;
1436 30 snespos_valid = realsnespos >= 0;
1437 30 return;
1438 }
1439
5/10
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 72 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 36 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 36 times.
✗ Branch 9 not taken.
72 unsigned int num=parse_math_expr(par)->evaluate_non_forward().get_integer();
1440
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 72 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.
✗ Branch 8 not taken.
72 if (num&~0xFFFFFF) throw_err_block(1, err_snes_address_out_of_bounds, hex((unsigned int)num).data());
1441 72 snespos=(int)num;
1442 72 startpos=(int)num;
1443 72 optimizeforbank=-1;
1444 72 snespos_valid = realsnespos >= 0;
1445 }
1446
1447 12 void cmd_dpbase(const char* par) {
1448
5/10
✓ Branch 0 taken 6 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.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
12 unsigned int num=parse_math_expr(par)->evaluate_non_forward().get_integer();
1449
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 12 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.
✗ Branch 8 not taken.
12 if (num&~0xFF00) throw_err_block(1, err_bad_dp_base, hex((unsigned int)num, 6).data());
1450 12 dp_base = (int)num;
1451 12 }
1452
1453 102 void cmd_optimize(char** words, int num_words) {
1454
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
102 if(num_words != 2) throw_err_block(1, err_bad_optimize, "");
1455
1456
5/5
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 51 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 30 times.
102 if (!stricmp(words[0], "dp"))
1457 {
1458
5/6
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 9 times.
42 if (!stricmp(words[1], "none"))
1459 {
1460 24 optimize_dp = optimize_dp_flag::NONE;
1461 24 return;
1462 }
1463
5/6
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 6 times.
18 if (!stricmp(words[1], "ram"))
1464 {
1465 6 optimize_dp = optimize_dp_flag::RAM;
1466 6 return;
1467 }
1468
3/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
12 if (!stricmp(words[1], "always"))
1469 {
1470 12 optimize_dp = optimize_dp_flag::ALWAYS;
1471 12 return;
1472 }
1473 throw_err_block(1, err_bad_dp_optimize, words[1]);
1474 }
1475
3/5
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 30 times.
✗ Branch 4 not taken.
60 if (!stricmp(words[0], "address"))
1476 {
1477
5/6
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 30 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 18 times.
60 if (!stricmp(words[1], "default"))
1478 {
1479 24 optimize_address = optimize_address_flag::DEFAULT;
1480 24 return;
1481 }
1482
5/6
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 9 times.
36 if (!stricmp(words[1], "ram"))
1483 {
1484 18 optimize_address = optimize_address_flag::RAM;
1485 18 return;
1486 }
1487
3/6
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
18 if (!stricmp(words[1], "mirrors"))
1488 {
1489 18 optimize_address = optimize_address_flag::MIRRORS;
1490 18 return;
1491 }
1492 throw_err_block(1, err_bad_address_optimize, words[1]);
1493 }
1494 throw_err_block(1, err_bad_optimize, words[0]);
1495 }
1496
1497 18 void cmd_bank(const char* par) {
1498
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 6 times.
18 if (!stricmp(par, "auto"))
1499 {
1500 6 optimizeforbank=-1;
1501 6 return;
1502 }
1503
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
12 if (!stricmp(par, "noassume"))
1504 {
1505 6 optimizeforbank=0x140;
1506 6 return;
1507 }
1508 6 unsigned int num=getnum(par);
1509 //if (forwardlabel) error(0, "bank Label is not valid");
1510 //if (foundlabel) num>>=16;
1511
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 6 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.
✗ Branch 8 not taken.
6 if (num&~0x0000FF) throw_err_block(1, err_snes_address_out_of_bounds, hex((unsigned int)num, 6).data());
1512 6 optimizeforbank=(int)num;
1513 }
1514
1515 enum class freespace_cmds {
1516 freespace,
1517 freecode,
1518 freedata,
1519 segment,
1520 };
1521
1522 template<freespace_cmds the_cmd>
1523 3132 void cmd_freespace(const char* par) {
1524
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 1566 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 783 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
3132 if(in_spcblock) throw_err_block(0, err_feature_unavaliable_in_spcblock);
1525
1526
2/3
✓ Branch 0 taken 783 times.
✓ Branch 1 taken 783 times.
✗ Branch 2 not taken.
3132 freespace_data this_fs_settings = default_freespace_settings;
1527 2244 if (the_cmd == freespace_cmds::freecode) this_fs_settings.bank = -2;
1528 672 if (the_cmd == freespace_cmds::freedata) this_fs_settings.bank = -1;
1529 204 if (the_cmd == freespace_cmds::segment) this_fs_settings.write_rats = false;
1530
1531
2/3
✓ Branch 0 taken 783 times.
✓ Branch 1 taken 783 times.
✗ Branch 2 not taken.
3132 string parstr = par;
1532
1/2
✓ Branch 0 taken 1566 times.
✗ Branch 1 not taken.
3132 parse_freespace_arguments(this_fs_settings, parstr);
1533
1534
5/6
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 1500 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 33 times.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
3132 if(this_fs_settings.bank == -3 && !this_fs_settings.write_rats) this_fs_settings.bank = -1;
1535
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1566 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3132 if(this_fs_settings.bank == -3) throw_err_block(0, err_invalid_freespace_request);
1536 // no point specifying anything about cleaning when not writing a rats tag
1537
4/4
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 1515 times.
✓ Branch 2 taken 51 times.
✓ Branch 3 taken 732 times.
3132 if(!this_fs_settings.write_rats &&
1538
6/8
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 51 times.
✓ Branch 2 taken 51 times.
✓ Branch 3 taken 51 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 51 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 51 times.
204 (this_fs_settings.flag_cleaned || this_fs_settings.is_static))
1539 throw_err_block(0, err_invalid_freespace_request);
1540
4/4
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 1515 times.
✓ Branch 2 taken 51 times.
✓ Branch 3 taken 732 times.
3132 if(!this_fs_settings.write_rats) this_fs_settings.flag_cleaned = true;
1541
1/2
✓ Branch 0 taken 1566 times.
✗ Branch 1 not taken.
3132 freespaceend();
1542 3132 freespaceid = freespaceidnext++;
1543
1/2
✓ Branch 0 taken 1566 times.
✗ Branch 1 not taken.
3132 freespace_data& thisfs = freespaces[freespaceid];
1544
1545
2/2
✓ Branch 0 taken 522 times.
✓ Branch 1 taken 1044 times.
3132 if (pass==0) {
1546
2/3
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 261 times.
✗ Branch 2 not taken.
1044 thisfs = this_fs_settings;
1547 1044 thisfs.pos = -1;
1548 1044 thisfs.leaked = true;
1549 1044 thisfs.orgpos = -2;
1550 1044 thisfs.orglen = -1;
1551 1044 snespos=0;
1552 }
1553
2/2
✓ Branch 0 taken 522 times.
✓ Branch 1 taken 1044 times.
3132 if (pass==1)
1554 {
1555
6/7
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 259 times.
✓ Branch 2 taken 261 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 259 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
1044 if (thisfs.is_static && thisfs.orgpos == -2)
1556 {
1557 thisfs.pos = 0;
1558 thisfs.leaked = false;//mute some other errors
1559 throw_err_block(1, err_static_freespace_autoclean);
1560 }
1561 1044 snespos = 0;
1562 }
1563
2/2
✓ Branch 0 taken 522 times.
✓ Branch 1 taken 1044 times.
3132 if (pass==2)
1564 {
1565
6/7
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 259 times.
✓ Branch 2 taken 261 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 259 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
1044 if (thisfs.is_static && thisfs.orgpos == -2) return;//to kill some errors (supposedly????)
1566 1044 snespos=thisfs.pos;
1567
7/12
✓ Branch 0 taken 228 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 261 times.
✓ Branch 3 taken 456 times.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 228 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 228 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
1044 if (thisfs.leaked && !thisfs.flag_cleaned) throw_warning(2, warn_freespace_leaked);
1568
5/5
✓ Branch 0 taken 244 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 261 times.
✓ Branch 3 taken 244 times.
✓ Branch 4 taken 17 times.
1044 freespaceuse += (thisfs.write_rats ? 8 : 0) + thisfs.len;
1569
1570 // add a mapping for the start of the rats tag
1571
6/7
✓ Branch 0 taken 244 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 505 times.
✓ Branch 3 taken 244 times.
✓ Branch 4 taken 17 times.
✓ Branch 5 taken 244 times.
✗ Branch 6 not taken.
1044 if (thisfs.write_rats) add_addr_to_line(snespos-8);
1572 }
1573
1/12
✗ Branch 0 not taken.
✓ Branch 1 taken 1566 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.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
3132 if (snespos < 0 && mapper == sa1rom) throw_err_fatal(pass, err_no_freespace_in_mapped_banks, dec(thisfs.len).data());
1574
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 1566 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.
✗ Branch 8 not taken.
3132 if (snespos < 0) throw_err_fatal(pass, err_no_freespace, dec(thisfs.len).data());
1575
5/5
✓ Branch 0 taken 732 times.
✓ Branch 1 taken 51 times.
✓ Branch 2 taken 783 times.
✓ Branch 3 taken 732 times.
✓ Branch 4 taken 51 times.
3132 bytes+=thisfs.write_rats ? 8 : 0;
1576 3132 freespacestart=snespos;
1577 3132 startpos=snespos;
1578 3132 realstartpos=snespos;
1579 3132 realsnespos=snespos;
1580 3132 optimizeforbank=-1;
1581
5/5
✓ Branch 0 taken 732 times.
✓ Branch 1 taken 51 times.
✓ Branch 2 taken 783 times.
✓ Branch 3 taken 732 times.
✓ Branch 4 taken 51 times.
3132 ratsmetastate=thisfs.write_rats ? ratsmeta_allow : ratsmeta_ban;
1582 3132 snespos_valid = true;
1583 // check this at the very end so that snespos gets set properly, to
1584 // prevent spurious errors later
1585 //...i guess this can still cause bankcross errors if the old freespace
1586 //happened to be very close to the end of a bank or something, but
1587 //whatever
1588
10/12
✓ Branch 0 taken 522 times.
✓ Branch 1 taken 1044 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 259 times.
✓ Branch 4 taken 262 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 260 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
3132 if (pass == 2 && thisfs.is_static && thisfs.orgpos > 0 && thisfs.len > thisfs.orglen)
1589
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
4 throw_err_block(2, err_static_freespace_growing);
1590
2/4
✓ Branch 0 taken 1564 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1564 times.
✗ Branch 3 not taken.
3136 }
1591
1592 6 void cmd_freespace_settings(const char* par) {
1593
2/3
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 string arg = par;
1594
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 parse_freespace_arguments(default_freespace_settings, arg);
1595 9 }
1596
1597 42 void cmd_prot(const char* par) {
1598 42 int addrToLinePos = realsnespos & 0xFFFFFF;
1599
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
42 if(in_spcblock) throw_err_block(0, err_feature_unavaliable_in_spcblock);
1600
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
42 if (!ratsmetastate) throw_err_block(2, err_prot_not_at_freespace_start);
1601
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 15 times.
42 if (ratsmetastate==ratsmeta_used) step(-5);
1602 21 int num;
1603
2/3
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
42 string parbuf = par;
1604
2/3
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
42 autoptr<char**> pars=qpsplit(parbuf.raw(), ',', &num);
1605
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 verify_paren(pars);
1606
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 write1('P');
1607
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 write1('R');
1608
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 write1('O');
1609
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 write1('T');
1610
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
42 if (num * 3 > 255) throw_err_block(0, err_prot_too_many_entries);
1611
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 write1((unsigned int)(num*3));
1612
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 42 times.
96 for (int i=0;i<num;i++)
1613 {
1614 54 const char * labeltest=pars[i];
1615
2/3
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
54 string testlabel = labeltest;
1616
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 snes_label lblval = labelval(&labeltest);
1617
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
54 if (*labeltest) throw_err_block(0, err_label_not_found, testlabel.data());
1618
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 write3(lblval.pos);
1619
3/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
54 if (pass==1) freespaces[lblval.freespace_id].leaked = false;
1620 54 }
1621
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 write1('S');
1622
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 write1('T');
1623
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 write1('O');
1624
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 write1('P');
1625
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 write1(0);
1626 42 ratsmetastate=ratsmeta_used;
1627
1628
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 add_addr_to_line(addrToLinePos);
1629 63 }
1630
1631 18 void cmd_autoclean(char** words, int num_words) {
1632
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
18 if(in_spcblock) throw_err_block(0, err_feature_unavaliable_in_spcblock);
1633
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 if (num_words==2)
1634 {
1635 18 const char * labeltest = words[1];
1636
2/3
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
18 string testlabel = labeltest;
1637
2/3
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
18 if(!stricmpwithlower(words[0], "dl")) {
1638
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 handle_autoclean(testlabel, -1, snespos);
1639
1640
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 add_addr_to_line(realsnespos & 0xFFFFFF);
1641
12/20
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✓ Branch 9 taken 15 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 3 times.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✓ Branch 15 taken 6 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
18 write3(pass==2 ? labelval(testlabel).pos : 0);
1642 } else {
1643 // other ones are handled in arch-65816
1644 throw_err_block(0, err_broken_autoclean);
1645 }
1646 18 }
1647 else if (num_words == 1) {
1648 if(pass==0) removerats(parse_math_expr(words[0])->evaluate_static().get_integer(), freespacebyte);
1649 } else {
1650 throw_err_block(0, err_broken_autoclean);
1651 }
1652 18 }
1653
1654 6 void cmd_freespacebyte(const char* par) {
1655
5/10
✓ Branch 0 taken 3 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 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
6 freespacebyte = parse_math_expr(par)->evaluate_static().get_integer();
1656 6 }
1657
1658 6 void cmd_pushpc(const char* par) {
1659
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if(*par) throw_err_block(0, err_broken_command, "pushpc", "");
1660 6 verifysnespos();
1661 6 pushpc[pushpcnum].arch=arch;
1662 6 pushpc[pushpcnum].snespos=snespos;
1663 6 pushpc[pushpcnum].snesstart=startpos;
1664 6 pushpc[pushpcnum].snesposreal=realsnespos;
1665 6 pushpc[pushpcnum].snesstartreal=realstartpos;
1666 6 pushpc[pushpcnum].freeid=freespaceid;
1667 6 pushpc[pushpcnum].freest=freespacestart;
1668 6 pushpcnum++;
1669 6 snespos=(int)0xFFFFFFFF;
1670 6 startpos= (int)0xFFFFFFFF;
1671 6 realsnespos= (int)0xFFFFFFFF;
1672 6 realstartpos= (int)0xFFFFFFFF;
1673 6 snespos_valid = false;
1674 6 }
1675
1676 6 void cmd_pullpc(const char* par) {
1677
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if(*par) throw_err_block(0, err_broken_command, "pullpc", "");
1678
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!pushpcnum) throw_err_block(0, err_pullpc_without_pushpc);
1679 6 pushpcnum--;
1680 6 freespaceend();
1681
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if (arch != pushpc[pushpcnum].arch) throw_err_block(0, err_pullpc_different_arch);
1682 6 snespos=pushpc[pushpcnum].snespos;
1683 6 startpos=pushpc[pushpcnum].snesstart;
1684 6 realsnespos=pushpc[pushpcnum].snesposreal;
1685 6 realstartpos=pushpc[pushpcnum].snesstartreal;
1686 6 freespaceid=pushpc[pushpcnum].freeid;
1687 6 freespacestart=pushpc[pushpcnum].freest;
1688 6 snespos_valid = true;
1689 6 }
1690
1691 6 void cmd_pushbase(const char* par) {
1692
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if(*par) throw_err_block(0, err_broken_command, "pushbase", "");
1693 6 basestack[basestacknum] = snespos;
1694 6 basestacknum++;
1695 6 }
1696
1697 6 void cmd_pullbase(const char* par) {
1698
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if(*par) throw_err_block(0, err_broken_command, "pullbase", "");
1699
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!basestacknum) throw_err_block(0, err_pullbase_without_pushbase);
1700 6 basestacknum--;
1701 6 snespos = basestack[basestacknum];
1702 6 startpos = basestack[basestacknum];
1703
1704
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (snespos != realstartpos)
1705 {
1706 6 optimizeforbank = -1;
1707 }
1708 6 }
1709
1710 12 void cmd_pushns(const char* par) {
1711
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
12 if(*par) throw_err_block(0, err_broken_command, "pushns", "");
1712
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
12 if(in_spcblock) throw_err_block(0, err_feature_unavaliable_in_spcblock);
1713 12 pushns[pushnsnum].ns = ns;
1714
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for(int i = 0; i < namespace_list.count; i++)
1715 {
1716 12 pushns[pushnsnum].namespace_list.append(namespace_list[i]);
1717 }
1718
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
12 pushns[pushnsnum].nested_namespaces = nested_namespaces;
1719 12 pushnsnum++;
1720
1721 12 namespace_list.reset();
1722 12 ns = "";
1723 12 nested_namespaces = false;
1724 12 }
1725
1726 12 void cmd_pullns(const char* par) {
1727
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
12 if(*par) throw_err_block(0, err_broken_command, "pullns", "");
1728
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
12 if(in_spcblock) throw_err_block(0, err_feature_unavaliable_in_spcblock);
1729
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!pushnsnum) throw_err_block(0, err_pullns_without_pushns);
1730 12 pushnsnum--;
1731 12 ns = pushns[pushnsnum].ns;
1732
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
12 nested_namespaces = pushns[pushnsnum].nested_namespaces;
1733 12 namespace_list.reset();
1734
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 6 times.
36 for(int i = 0; i < pushns[pushnsnum].namespace_list.count; i++)
1735 {
1736 24 namespace_list.append(pushns[pushnsnum].namespace_list[i]);
1737 }
1738 12 }
1739
1740 165 void cmd_namespace(char** words, int num_words) {
1741
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 165 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 84 times.
165 if(in_spcblock) throw_err_block(0, err_feature_unavaliable_in_spcblock);
1742 165 bool leave = false;
1743
1/2
✓ Branch 0 taken 165 times.
✗ Branch 1 not taken.
165 if (num_words >= 1)
1744 {
1745
5/5
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 84 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 60 times.
165 if (!stricmp(words[0], "off"))
1746 {
1747
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 if (num_words != 1) throw_err_block(0, err_invalid_namespace_use);
1748 48 leave = true;
1749 }
1750
5/5
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 42 times.
117 else if (!stricmp(words[0], "nested"))
1751 {
1752
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 if (num_words != 2) throw_err_block(0, err_invalid_namespace_use);
1753
5/6
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 9 times.
36 else if (!stricmp(words[1], "on")) nested_namespaces = true;
1754
3/6
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
18 else if (!stricmp(words[1], "off")) nested_namespaces = false;
1755 }
1756 else
1757 {
1758
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 81 times.
81 if (num_words != 1) throw_err_block(0, err_invalid_namespace_use);
1759 81 const char * tmpstr= safedequote(words[0]);
1760
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 81 times.
81 if (!confirmname(tmpstr)) throw_err_block(0, err_invalid_namespace_name);
1761
4/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 24 times.
81 if (!nested_namespaces)
1762 {
1763 33 namespace_list.reset();
1764 }
1765
4/7
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 42 times.
✗ Branch 6 not taken.
81 namespace_list.append(tmpstr);
1766 }
1767 }
1768 else
1769 {
1770 throw_err_block(0, err_invalid_namespace_use);
1771 //leave = true;
1772 }
1773
1774
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 117 times.
165 if (leave)
1775 {
1776
4/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 6 times.
48 if (nested_namespaces)
1777 {
1778 36 namespace_list.remove(namespace_list.count - 1);
1779 }
1780 else
1781 {
1782 12 namespace_list.reset();
1783 }
1784 }
1785
1786 // recompute ns
1787 165 ns = "";
1788
2/2
✓ Branch 0 taken 195 times.
✓ Branch 1 taken 165 times.
360 for (int i = 0; i < namespace_list.count; i++)
1789 {
1790 195 ns += namespace_list[i];
1791 195 ns += "_";
1792 }
1793 165 }
1794
1795 10171 void cmd_incsrc(const char* par) {
1796 // RPG Hacker: Should this also throw on absolute paths?
1797 // E.g., on something starting with C:/ or whatever.
1798
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10168 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 5093 times.
10171 if (strchr(par, '\\'))
1799 {
1800
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 throw_err_block(0, err_platform_paths);
1801 }
1802
2/3
✓ Branch 0 taken 5072 times.
✓ Branch 1 taken 5093 times.
✗ Branch 2 not taken.
10165 string temp = par;
1803
1/2
✓ Branch 0 taken 10165 times.
✗ Branch 1 not taken.
10165 const char* name = safedequote(temp.raw());
1804
2/2
✓ Branch 0 taken 159 times.
✓ Branch 1 taken 10006 times.
10165 assemblefile(name);
1805 10255 }
1806
1807 60 void cmd_incbin(const char* par) {
1808 60 int addrToLinePos = realsnespos & 0xFFFFFF;
1809 30 int len;
1810 60 int start=0;
1811 60 int end=0;
1812
2/3
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
60 string temp = par;
1813 60 const char* lengths = strqchr(temp, ':');
1814
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 30 times.
60 if (lengths)
1815 {
1816 30 lengths++;
1817
1818
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 const char* split = strqpstr(lengths, "..");
1819
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
30 if(!split) throw_err_block(0, err_broken_incbin);
1820
2/3
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
24 string start_str(lengths, split-lengths);
1821
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
24 if(start_str == "") throw_err_block(0, err_broken_incbin);
1822
5/10
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 12 times.
✗ Branch 9 not taken.
24 start = parse_math_expr(start_str)->evaluate_non_forward().get_integer();
1823
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
24 string end_str(split+2);
1824
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
24 if(end_str == "") throw_err_block(0, err_broken_incbin);
1825
5/10
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 12 times.
✗ Branch 9 not taken.
24 end = parse_math_expr(end_str)->evaluate_non_forward().get_integer();
1826 // make temp just the filename without the lengths
1827
2/3
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
24 temp.truncate(lengths-1 - temp.data());
1828 24 }
1829
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 const char* current_file = get_current_file_name();
1830 // RPG Hacker: Should this also throw on absolute paths?
1831 // E.g., on something starting with C:/ or whatever.
1832
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 51 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 24 times.
54 if (strchr(par, '\\'))
1833 {
1834
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 throw_err_block(0, err_platform_paths);
1835 }
1836
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 const char* name = safedequote(temp.raw());
1837
1838 24 char * data;//I couldn't find a way to get this into an autoptr
1839
5/8
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
48 if (!readfile(name, current_file, &data, &len)) throw_vfile_error(0, asar_get_last_io_error(), name);
1840 36 autoptr<char*> datacopy=data;
1841
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 24 times.
36 if (!end) end=len;
1842
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 36 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.
✗ Branch 8 not taken.
36 if(start < 0) throw_err_block(1, err_file_offset_out_of_bounds, dec(start).data(), name);
1843
3/13
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 36 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
36 if (end < start || end > len || end < 0) throw_err_block(1, err_file_offset_out_of_bounds, dec(end).data(), name);
1844
1845
5/6
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 66 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 33 times.
✓ Branch 5 taken 18 times.
102 for (int i=start;i<end;i++) write1((unsigned int)data[i]);
1846
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 add_addr_to_line(addrToLinePos);
1847 78 }
1848
1849 template<bool is_fill>
1850 1344 void cmd_skip_fill(char** words, int num_words) {
1851 1344 const char* cmdname = is_fill ? "fill" : "skip";
1852
4/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 666 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
1344 if(num_words != 1 && num_words != 2 && num_words != 4) throw_err_block(0, err_broken_command, cmdname, "");
1853
6/7
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 666 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 336 times.
✓ Branch 6 taken 3 times.
1344 if(num_words > 1 && stricmp(words[0], "align")) throw_err_block(0, err_broken_command, cmdname, "expected \"align\"");
1854
5/8
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 666 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 339 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
1344 if(num_words == 4 && stricmp(words[2], "offset")) throw_err_block(0, err_broken_command, cmdname, "expected \"offset\"");
1855 int amount;
1856
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 666 times.
1344 if(num_words > 1)
1857 {
1858
5/10
✓ Branch 0 taken 3 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 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
12 int alignment = parse_math_expr(words[1])->evaluate_static().get_integer();
1859 12 int offset = 0;
1860
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 if(num_words==4)
1861 {
1862
5/10
✓ Branch 0 taken 3 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 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
12 offset = parse_math_expr(words[3])->evaluate_static().get_integer();
1863 }
1864
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
12 if(alignment > 0x800000) throw_err_block(0, err_alignment_too_big);
1865
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
12 if(alignment < 1) throw_err_block(0, err_alignment_too_small);
1866
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
12 if(alignment & (alignment-1)) throw_err_block(0, err_invalid_alignment);
1867 // i just guessed this formula but it seems to work
1868 12 amount = (alignment - ((snespos - offset) & (alignment-1))) & (alignment-1);
1869 // TODO: set current freespace align to at least alignment
1870 }
1871 else
1872 {
1873
5/10
✓ Branch 0 taken 333 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 666 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 333 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 333 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 333 times.
✗ Branch 9 not taken.
1332 amount = parse_math_expr(words[0])->evaluate_non_forward().get_integer();
1874 }
1875 1212 if(!is_fill) step(amount);
1876 else
1877 {
1878 132 add_addr_to_line(realsnespos & 0xFFFFFF);
1879
4/4
✓ Branch 0 taken 203535 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 203535 times.
✓ Branch 3 taken 33 times.
814272 for(int i=0; i < amount; i++) write1(fillbyte[i%12]);
1880 }
1881 1344 }
1882
1883 6 void cmd_cleartable(const char* par) {
1884
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if(*par) throw_err_block(0, err_broken_command, "cleartable", "");
1885 6 cleartable();
1886 6 }
1887
1888 6 void cmd_pushtable(const char* par) {
1889
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if(*par) throw_err_block(0, err_broken_command, "pushtable", "");
1890 6 tablestack.append(thetable);
1891 6 }
1892
1893 6 void cmd_pulltable(const char* par) {
1894
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if(*par) throw_err_block(0, err_broken_command, "pulltable", "");
1895
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (tablestack.count <= 0) throw_err_block(0, err_pulltable_without_table);
1896 6 thetable=tablestack[tablestack.count-1];
1897 6 tablestack.remove(tablestack.count-1);
1898 6 }
1899
1900 48 void cmd_function(const char* par) {
1901
2/3
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
48 string parbuf = par;
1902
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 parbuf.qnormalize(); // todo what's the point of doing this here in particular???
1903 48 char* name_and_args = parbuf.raw();
1904
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
48 char* fn_body = strchr(name_and_args, '=');
1905
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
48 if(!fn_body) throw_err_block(0, err_broken_function_declaration);
1906 48 *fn_body = 0;
1907 48 fn_body++;
1908
2/6
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 48 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
48 if(!confirmqpar(name_and_args)) throw_err_block(0, err_broken_function_declaration);
1909 48 char* startpar = strqchr(name_and_args, '(');
1910
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
48 if (!startpar) throw_err_block(0, err_broken_function_declaration);
1911 48 *startpar = 0;
1912 48 startpar++;
1913
3/7
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
48 if(!confirmname(name_and_args)) throw_err_block(0, err_invalid_function_name);
1914 48 char* endpar = strqchr(startpar, ')');
1915 48 *endpar = 0;
1916 48 endpar++;
1917 // it's legal for there to be spaces between ) and =
1918
4/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 24 times.
96 while(*endpar == ' ') endpar++;
1919
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
48 if(*endpar) throw_err_block(0, err_broken_function_declaration);
1920
1921
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 createuserfunc(name_and_args, startpar, fn_body);
1922 72 }
1923
1924 324 void cmd_print(const char* par) {
1925
3/3
✓ Branch 0 taken 155 times.
✓ Branch 1 taken 165 times.
✓ Branch 2 taken 4 times.
324 string out = handle_print(par);
1926
3/4
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 216 times.
✓ Branch 2 taken 100 times.
✗ Branch 3 not taken.
316 if(pass == 2) print(out);
1927 477 }
1928
1929 6 void cmd_reset(const char* par) {
1930 if(0);
1931
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 else if (!stricmp(par, "bytes")) bytes=0;
1932 else if (!stricmp(par, "freespaceuse")) freespaceuse=0;
1933 else throw_err_block(2, err_unknown_variable);
1934 6 }
1935
1936 template<int width, bool is_fill>
1937 108 void cmd_padbytes(const char* par) {
1938
5/10
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 27 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 27 times.
✗ Branch 9 not taken.
108 unsigned int val = parse_math_expr(par)->evaluate_static().get_integer();
1939
2/2
✓ Branch 0 taken 510 times.
✓ Branch 1 taken 54 times.
1128 for (int i=0;i<12;i+=width)
1940 {
1941 1020 unsigned int tmpval=val;
1942
2/2
✓ Branch 0 taken 648 times.
✓ Branch 1 taken 510 times.
2316 for (int j=0;j<width;j++)
1943 {
1944 1296 (is_fill ? fillbyte : padbyte)[i+j] = (unsigned char)tmpval;
1945 1296 tmpval>>=8;
1946 }
1947 }
1948 108 }
1949
1950 12 void cmd_pad(const char* par) {
1951
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (freespaceid > 0) throw_err_block(0, err_pad_in_freespace);
1952
5/10
✓ Branch 0 taken 6 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.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
12 int num = parse_math_expr(par)->evaluate_non_forward().get_integer();
1953
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 12 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.
✗ Branch 8 not taken.
12 if ((unsigned int)num & 0xFF000000) throw_err_block(0, err_snes_address_doesnt_map_to_rom, hex((unsigned int)num, 6).data());
1954
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (num>realsnespos)
1955 {
1956 12 int end=snestopc(num);
1957 12 int start=snestopc(realsnespos);
1958 12 int len=end-start;
1959 12 add_addr_to_line(realsnespos & 0xFFFFFF);
1960
4/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 6 times.
72 for (int i=0;i<len;i++) write1(padbyte[i%12]);
1961 }
1962 12 }
1963
1964 90 void cmd_arch(const char* par) {
1965
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 45 times.
90 if(in_spcblock) throw_err_block(0, err_feature_unavaliable_in_spcblock);
1966
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 78 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 33 times.
90 if (!stricmp(par, "65816")) { arch=arch_65816; return; }
1967
4/4
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 12 times.
66 if (!stricmp(par, "spc700")) { arch=arch_spc700; return; }
1968
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
24 if (!stricmp(par, "superfx")) { arch=arch_superfx; return; }
1969 throw_err_block(0, err_broken_command, "arch", "Invalid architecture, expected one of 65816, spc700, superfx");
1970 }
1971
1972 72 void cmd_braces(const char* par) {
1973
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 36 times.
72 if(*par) throw_err_block(0, err_broken_command, "{ / }", "");
1974 72 }
1975
1976 template<void (*F)(const char*)>
1977 518 void wrap_mapper(const char* par) {
1978
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 259 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 146 times.
518 if(in_spcblock) throw_err_block(0, err_feature_unavaliable_in_spcblock);
1979
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 146 times.
518 mapper_t previous_mapper = mapper;
1980 518 F(par);
1981
4/4
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 191 times.
✓ Branch 2 taken 101 times.
✓ Branch 3 taken 45 times.
518 if(!mapper_set){
1982 338 mapper_set = true;
1983
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 51 times.
✓ Branch 2 taken 39 times.
✓ Branch 3 taken 6 times.
180 }else if(previous_mapper != mapper){
1984 156 throw_warning(1, warn_mapper_already_set);
1985 }
1986 518 }
1987
1988 template<mapper_t the_mapper>
1989 374 void mapper_simple(const char* par) {
1990
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
✓ Branch 2 taken 104 times.
374 if(*par) throw_err_block(0, err_invalid_mapper);
1991 374 mapper = the_mapper;
1992 374 }
1993
1994 45 void mapper_norom(const char* par) {
1995
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 27 times.
45 if(*par) throw_err_block(0, err_invalid_mapper);
1996 //$000000 would be the best snespos for this, but I don't care
1997 45 mapper = norom;
1998
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 21 times.
45 if(!force_checksum_fix)
1999 6 checksum_fix_enabled = false;//we don't know where the header is, so don't set the checksum
2000 45 }
2001
2002 27 void mapper_sa1rom(const char* par) {
2003
3/3
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 3 times.
27 if (*par) {
2004 // todo why doesn't this allow math?
2005
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
42 if (!is_digit(par[0]) || par[1]!=',' ||
2006
3/6
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
21 !is_digit(par[2]) || par[3]!=',' ||
2007
3/6
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
21 !is_digit(par[4]) || par[5]!=',' ||
2008
7/12
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 12 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 12 times.
42 !is_digit(par[6]) || par[7]) throw_err_block(0, err_invalid_mapper);
2009 /*
2010 // this part is just useless ???
2011 int len;
2012 string parbuf = par;
2013 autoptr<char**> pars=qpsplit(parbuf.raw(), ',', &len);
2014 verify_paren(pars);
2015 if (len!=4) throw_err_block(0, err_invalid_mapper); */
2016
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
21 sa1banks[0]=(par[0]-'0')<<20;
2017
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
21 sa1banks[1]=(par[2]-'0')<<20;
2018
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
21 sa1banks[4]=(par[4]-'0')<<20;
2019
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
21 sa1banks[5]=(par[6]-'0')<<20;
2020 }
2021 else
2022 {
2023 6 sa1banks[0]=0<<20;
2024 6 sa1banks[1]=1<<20;
2025 6 sa1banks[4]=2<<20;
2026 6 sa1banks[5]=3<<20;
2027 }
2028 27 mapper=sa1rom;
2029 27 }
2030
2031 using command_fn_t = void(*)(const char*);
2032
2033 template<void (*F)(char**, int)>
2034 2822 void wrap_split(const char* par) {
2035
2/3
✓ Branch 0 taken 704 times.
✓ Branch 1 taken 707 times.
✗ Branch 2 not taken.
2822 string temp(par);
2036 1414 int num_words;
2037
2/3
✓ Branch 0 taken 704 times.
✓ Branch 1 taken 707 times.
✗ Branch 2 not taken.
2822 autoptr<char**> word = qsplit(temp.raw(), ' ', &num_words);
2038
8/8
✓ Branch 0 taken 1005 times.
✓ Branch 1 taken 406 times.
✓ Branch 2 taken 57 times.
✓ Branch 3 taken 444 times.
✓ Branch 4 taken 114 times.
✓ Branch 5 taken 1094 times.
✓ Branch 6 taken 57 times.
✓ Branch 7 taken 650 times.
2822 if(num_words == 1 && word[0][0] == 0) num_words--;
2039
2/2
✓ Branch 0 taken 1401 times.
✓ Branch 1 taken 10 times.
2822 F(word, num_words);
2040 4246 }
2041
2042 }
2043
2044 static constexpr auto normal_commands = frozen::make_unordered_map<frozen::string, command_fn_t>({
2045 { "db", cmd_write_data<write1> },
2046 { "dw", cmd_write_data<write2> },
2047 { "dl", cmd_write_data<write3> },
2048 { "dd", cmd_write_data<write4> },
2049 { "assert", cmd_assert },
2050 { "undef", cmd_undef },
2051 { "error", cmd_error },
2052 { "warn", cmd_warn },
2053 { "warnings", wrap_split<cmd_warnings> },
2054 { "global", cmd_global },
2055 { "check", wrap_split<cmd_check> },
2056 { "asar", cmd_asar },
2057 { "include", cmd_include },
2058 { "includefrom", cmd_includefrom },
2059 { "includeonce", cmd_includeonce },
2060 { "org", cmd_org },
2061 { "struct", wrap_split<cmd_struct> },
2062 { "endstruct", wrap_split<cmd_endstruct> },
2063 { "spcblock", wrap_split<cmd_spcblock> },
2064 { "endspcblock", wrap_split<cmd_endspcblock> },
2065 { "base", cmd_base },
2066 { "dpbase", cmd_dpbase },
2067 { "optimize", wrap_split<cmd_optimize> },
2068 { "bank", cmd_bank },
2069 { "freespace", cmd_freespace<freespace_cmds::freespace> },
2070 { "freecode", cmd_freespace<freespace_cmds::freecode> },
2071 { "freedata", cmd_freespace<freespace_cmds::freedata> },
2072 { "segment", cmd_freespace<freespace_cmds::segment> },
2073 { "freespace_settings", cmd_freespace_settings },
2074 { "prot", cmd_prot },
2075 { "autoclean", wrap_split<cmd_autoclean> },
2076 { "freespacebyte", cmd_freespacebyte },
2077 { "pushpc", cmd_pushpc },
2078 { "pullpc", cmd_pullpc },
2079 { "pushbase", cmd_pushbase },
2080 { "pullbase", cmd_pullbase },
2081 { "pushns", cmd_pushns },
2082 { "pullns", cmd_pullns },
2083 { "namespace", wrap_split<cmd_namespace> },
2084 { "incsrc", cmd_incsrc },
2085 { "incbin", cmd_incbin },
2086 { "skip", wrap_split<cmd_skip_fill<false>> },
2087 { "fill", wrap_split<cmd_skip_fill<true>> },
2088 { "cleartable", cmd_cleartable },
2089 { "pushtable", cmd_pushtable },
2090 { "pulltable", cmd_pulltable },
2091 { "function", cmd_function },
2092 { "print", cmd_print },
2093 { "reset", cmd_reset },
2094 { "padbyte", cmd_padbytes<1, false> },
2095 { "padword", cmd_padbytes<2, false> },
2096 { "padlong", cmd_padbytes<3, false> },
2097 { "paddword", cmd_padbytes<4, false> },
2098 { "fillbyte", cmd_padbytes<1, true> },
2099 { "fillword", cmd_padbytes<2, true> },
2100 { "filllong", cmd_padbytes<3, true> },
2101 { "filldword", cmd_padbytes<4, true> },
2102 { "pad", cmd_pad },
2103 { "arch", cmd_arch },
2104 { "{", cmd_braces },
2105 { "}", cmd_braces },
2106
2107 { "lorom", wrap_mapper<mapper_simple<lorom>> },
2108 { "hirom", wrap_mapper<mapper_simple<hirom>> },
2109 { "exlorom", wrap_mapper<mapper_simple<exlorom>> },
2110 { "exhirom", wrap_mapper<mapper_simple<exhirom>> },
2111 { "sfxrom", wrap_mapper<mapper_simple<sfxrom>> },
2112 { "norom", wrap_mapper<mapper_norom> },
2113 { "sa1rom", wrap_mapper<mapper_sa1rom> },
2114 { "fullsa1rom", wrap_mapper<mapper_simple<bigsa1rom>> },
2115 });
2116
2117 namespace control_flow {
2118
2119 enum cf_cmds {
2120 c_if,
2121 c_elseif,
2122 c_while,
2123 c_for,
2124 };
2125
2126 // todo possibly this would be cleaner if `for` was refactored out entirely?
2127 template<cf_cmds type>
2128 6264 void cf_start(const char* par, int& single_line_for_tracker) {
2129 6264 const char* typ_name =
2130 type == c_if ? "if" :
2131 type == c_elseif ? "elseif" :
2132 type == c_while ? "while" : "for";
2133 6264 whiletracker wstatus;
2134
1/2
✓ Branch 0 taken 3132 times.
✗ Branch 1 not taken.
6264 wstatus.startline = get_current_line();
2135 6264 wstatus.iswhile = type == c_while;
2136 6264 wstatus.cond = false;
2137 6264 wstatus.is_for = false;
2138 6264 wstatus.for_start = wstatus.for_end = wstatus.for_cur = 0;
2139 6264 wstatus.for_has_var_backup = false;
2140 696 if(type == c_for) wstatus.is_for = true;
2141
2142 6264 bool is_for_cont = false;
2143 // if this is a for loop and a whilestatus entry already exists at this level,
2144 // and the for loop isn't finished, this is a continuation of the for loop
2145 696 if ((type == c_for)
2146
6/7
✓ Branch 0 taken 348 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 166 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 174 times.
✓ Branch 5 taken 166 times.
✓ Branch 6 taken 8 times.
696 && whilestatus.count > numif && whilestatus[numif].is_for
2147
11/14
✓ Branch 0 taken 348 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 332 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 166 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 289 times.
✓ Branch 7 taken 43 times.
✓ Branch 8 taken 123 times.
✓ Branch 9 taken 51 times.
✓ Branch 10 taken 123 times.
✓ Branch 11 taken 43 times.
✓ Branch 12 taken 123 times.
✓ Branch 13 taken 51 times.
1392 && whilestatus[numif].for_cur < whilestatus[numif].for_end) {
2148 492 is_for_cont = true;
2149 }
2150
6/9
✓ Branch 0 taken 246 times.
✓ Branch 1 taken 2886 times.
✓ Branch 2 taken 246 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2886 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1443 times.
✓ Branch 7 taken 1443 times.
✗ Branch 8 not taken.
6264 whiletracker& addedwstatus = is_for_cont ? whilestatus[numif] : (whilestatus[numif] = wstatus);
2151 //handle nested if statements
2152
4/4
✓ Branch 0 taken 336 times.
✓ Branch 1 taken 2796 times.
✓ Branch 2 taken 48 times.
✓ Branch 3 taken 174 times.
6264 if (numtrue!=numif && !(type == c_elseif && numtrue+1==numif))
2153 {
2154 228 if (type != c_elseif) numif++;
2155 324 return;
2156 }
2157 5376 if (type != c_elseif) numif++;
2158
2159 bool cond;
2160 if(type != c_for)
2161 {
2162
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1320 times.
✓ Branch 2 taken 1320 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
5280 if(!*par) throw_err_block(0, err_broken_command, typ_name, "Missing condition.");
2163
7/10
✓ Branch 0 taken 1320 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2619 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 1299 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1299 times.
✓ Branch 7 taken 21 times.
✓ Branch 8 taken 1299 times.
✗ Branch 9 not taken.
5406 cond = parse_math_expr(par)->evaluate_static().get_integer();
2164 }
2165
2166 if (type == c_for)
2167 {
2168
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 165 times.
✓ Branch 2 taken 165 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
660 if(!*par) throw_err_block(0, err_broken_for_loop, "missing loop range");
2169
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 165 times.
✓ Branch 2 taken 165 times.
660 if(single_line_for_tracker != 1)
2170 {
2171 numif--;
2172 throw_err_line(0, err_bad_single_line_for);
2173 }
2174
2175
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 246 times.
660 if(!is_for_cont)
2176 {
2177
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
168 const char* past_eq = strchr(par, '=');
2178
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
168 if(!past_eq)
2179 throw_err_block(0, err_broken_for_loop, "missing loop range");
2180
2181
2/3
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
168 string varname(par, past_eq - par);
2182 168 past_eq += 1;
2183
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
168 strip_whitespace(varname);
2184
2/4
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84 times.
168 if(!validatedefinename(varname))
2185 throw_err_block(0, err_broken_for_loop, "invalid define name");
2186
2187
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
168 const char* range_sep = strqpstr(past_eq, "..");
2188
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
168 if(!range_sep)
2189 throw_err_block(0, err_broken_for_loop, "invalid loop range");
2190
2191
2/3
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
168 string for_start(past_eq, range_sep - past_eq);
2192
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
168 strip_whitespace(for_start);
2193
2/4
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
168 string for_end(range_sep+2);
2194
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
168 strip_whitespace(for_end);
2195
2196
5/10
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 42 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 42 times.
✗ Branch 9 not taken.
168 addedwstatus.for_start = parse_math_expr(for_start)->evaluate_static().get_integer();
2197
5/10
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 42 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 42 times.
✗ Branch 9 not taken.
168 addedwstatus.for_end = parse_math_expr(for_end)->evaluate_static().get_integer();
2198
2199
2/4
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
168 addedwstatus.for_variable = varname;
2200 168 addedwstatus.for_cur = addedwstatus.for_start;
2201 168 }
2202 492 else addedwstatus.for_cur++;
2203
2204 660 addedwstatus.cond = addedwstatus.for_cur < addedwstatus.for_end;
2205 660 single_line_for_tracker = 2;
2206
5/5
✓ Branch 0 taken 123 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 165 times.
✓ Branch 3 taken 123 times.
✓ Branch 4 taken 42 times.
660 if(addedwstatus.cond)
2207 {
2208 492 numtrue++;
2209
6/8
✓ Branch 0 taken 123 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 96 times.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 123 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 96 times.
✓ Branch 7 taken 27 times.
492 if(defines.exists(addedwstatus.for_variable))
2210 {
2211 384 addedwstatus.for_has_var_backup = true;
2212
4/7
✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 96 times.
✓ Branch 3 taken 96 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 96 times.
✗ Branch 6 not taken.
384 addedwstatus.for_var_backup = defines.find(addedwstatus.for_variable);
2213 }
2214
3/7
✓ Branch 0 taken 123 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 246 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 123 times.
✗ Branch 6 not taken.
492 defines.create(addedwstatus.for_variable) = ftostr(addedwstatus.for_cur);
2215 }
2216 }
2217 else if (type == c_if || type == c_while)
2218 {
2219 if(0);
2220
2/2
✓ Branch 0 taken 1884 times.
✓ Branch 1 taken 432 times.
4632 else if (cond)
2221 {
2222 3768 numtrue++;
2223
1/2
✓ Branch 0 taken 1884 times.
✗ Branch 1 not taken.
3768 elsestatus[numif]=true;
2224 }
2225
1/2
✓ Branch 0 taken 432 times.
✗ Branch 1 not taken.
864 else if (!cond)
2226 {
2227
1/2
✓ Branch 0 taken 432 times.
✗ Branch 1 not taken.
864 elsestatus[numif]=false;
2228 }
2229 4632 addedwstatus.cond = cond;
2230 }
2231 else if (type == c_elseif)
2232 {
2233
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 282 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
564 if (!numif) throw_err_block(1, err_misplaced_elseif);
2234
4/9
✓ Branch 0 taken 282 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 141 times.
✓ Branch 4 taken 141 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 141 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
564 if (whilestatus[numif - 1].iswhile) throw_err_block(1, err_elseif_in_while);
2235
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 174 times.
564 if (numif==numtrue) numtrue--;
2236
10/11
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 108 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 39 times.
✓ Branch 5 taken 15 times.
✓ Branch 6 taken 93 times.
✓ Branch 7 taken 141 times.
✓ Branch 8 taken 15 times.
✓ Branch 9 taken 39 times.
✓ Branch 10 taken 102 times.
564 if (cond && !elsestatus[numif])
2237 {
2238 156 numtrue++;
2239
1/2
✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
156 elsestatus[numif]=true;
2240 }
2241 }
2242
2/2
✓ Branch 0 taken 2928 times.
✓ Branch 1 taken 162 times.
6264 }
2243
2244 template<cf_cmds type>
2245 5604 void cf_end(const char* par, int& single_line_for_tracker) {
2246
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1401 times.
✓ Branch 2 taken 1401 times.
5604 if(*par) throw_err_block(0, err_broken_command, "end<...>", "");
2247
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2802 times.
5604 if (!numif)
2248 throw_err_block(1, err_misplaced_endif);
2249 5604 whiletracker& thisws = whilestatus[numif - 1];
2250
2251
7/9
✓ Branch 0 taken 963 times.
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 2100 times.
✓ Branch 3 taken 963 times.
✓ Branch 4 taken 174 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 963 times.
✓ Branch 7 taken 963 times.
✗ Branch 8 not taken.
5604 if((!thisws.is_for && !thisws.iswhile && type != c_if) ||
2252
5/5
✓ Branch 0 taken 264 times.
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 438 times.
✓ Branch 3 taken 264 times.
✓ Branch 4 taken 174 times.
5604 (thisws.iswhile && type != c_while) ||
2253
3/5
✗ Branch 0 not taken.
✓ Branch 1 taken 1227 times.
✓ Branch 2 taken 1227 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1227 times.
4908 (thisws.is_for && type != c_for))
2254 throw_err_block(1, err_misplaced_endif);
2255
2256
2/2
✓ Branch 0 taken 2088 times.
✓ Branch 1 taken 714 times.
5604 if (numif==numtrue) numtrue--;
2257 5604 numif--;
2258
2259
5/5
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 1227 times.
✓ Branch 2 taken 1401 times.
✓ Branch 3 taken 174 times.
✓ Branch 4 taken 1227 times.
5604 if(thisws.is_for)
2260 {
2261
3/3
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 144 times.
696 if(single_line_for_tracker == 2) single_line_for_tracker = 3;
2262
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 348 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 174 times.
696 if(moreonline)
2263 {
2264 // sabotage the whilestatus to prevent the loop running again
2265 // and spamming more of the same error
2266 thisws.for_cur = thisws.for_end;
2267 thisws.cond = false;
2268 throw_err_block(0, err_bad_single_line_for);
2269 }
2270
2271
5/5
✓ Branch 0 taken 123 times.
✓ Branch 1 taken 51 times.
✓ Branch 2 taken 174 times.
✓ Branch 3 taken 123 times.
✓ Branch 4 taken 51 times.
696 if(thisws.cond)
2272 {
2273
5/5
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 123 times.
✓ Branch 3 taken 96 times.
✓ Branch 4 taken 27 times.
492 if(thisws.for_has_var_backup)
2274 384 defines.create(thisws.for_variable) = thisws.for_var_backup;
2275 else
2276 108 defines.remove(thisws.for_variable);
2277 }
2278 }
2279 5604 }
2280
2281 234 void cf_else(const char* par, int& single_line_for_tracker) {
2282
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
✓ Branch 2 taken 117 times.
234 if(*par) throw_err_block(0, err_broken_command, "else", "");
2283
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
234 if (!numif) throw_err_block(1, err_misplaced_else);
2284
7/13
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 117 times.
✓ Branch 3 taken 234 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 117 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 117 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 117 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 117 times.
234 if (whilestatus[numif - 1].iswhile || whilestatus[numif - 1].is_for) throw_err_block(1, err_else_in_while_loop);
2285
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 162 times.
234 else if (numif==numtrue) numtrue--;
2286
9/9
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 45 times.
✓ Branch 4 taken 105 times.
✓ Branch 5 taken 81 times.
✓ Branch 6 taken 45 times.
✓ Branch 7 taken 30 times.
✓ Branch 8 taken 51 times.
162 else if (numif==numtrue+1 && !elsestatus[numif])
2287 {
2288 60 numtrue++;
2289 60 elsestatus[numif]=true;
2290 }
2291 234 }
2292
2293 }
2294
2295 static constexpr auto control_flow_commands = frozen::make_unordered_map<frozen::string, void(*)(const char*, int&)>({
2296 { "if", control_flow::cf_start<control_flow::c_if> },
2297 { "elseif", control_flow::cf_start<control_flow::c_elseif> },
2298 { "while", control_flow::cf_start<control_flow::c_while> },
2299 { "for", control_flow::cf_start<control_flow::c_for> },
2300 { "endif", control_flow::cf_end<control_flow::c_if> },
2301 { "endwhile", control_flow::cf_end<control_flow::c_while> },
2302 { "endfor", control_flow::cf_end<control_flow::c_for> },
2303 { "else", control_flow::cf_else },
2304 });
2305
2306 531 static void cmd_label_assign(const char* firstword, const char* params) {
2307
4/6
✓ Branch 0 taken 201 times.
✓ Branch 1 taken 264 times.
✓ Branch 2 taken 267 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 201 times.
✗ Branch 5 not taken.
531 if (firstword[0] == '\'' && firstword[1]) {
2308 201 int codepoint;
2309 402 const char* char_start = firstword + 1;
2310
1/2
✓ Branch 0 taken 402 times.
✗ Branch 1 not taken.
402 const char* after = char_start + utf8_val(&codepoint, char_start);
2311
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 402 times.
402 if (codepoint == -1)
2312 throw_err_block(0, err_invalid_utf8);
2313
4/6
✓ Branch 0 taken 201 times.
✓ Branch 1 taken 201 times.
✓ Branch 2 taken 201 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 201 times.
✗ Branch 5 not taken.
402 if (after[0] == '\'' && after[1] == '\0') {
2314
8/14
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 396 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 198 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 396 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 198 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 198 times.
✗ Branch 13 not taken.
405 thetable.set_val(codepoint, parse_math_expr(params + 2)->evaluate_static().get_integer());
2315 396 return;
2316 } else {
2317 throw_err_block(0, err_invalid_character);
2318 }
2319 }
2320
2/4
✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
129 auto expr = parse_math_expr(params + 2);
2321
4/7
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 66 times.
✗ Branch 6 not taken.
129 int num = expr->evaluate_non_forward().get_integer();
2322
2/4
✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
129 bool is_static = expr->has_label() <= 1;
2323
2324 129 const char* newlabelname = firstword;
2325 129 bool ismacro = false;
2326
2327
3/3
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 63 times.
✓ Branch 2 taken 63 times.
129 if (newlabelname[0] == '?') {
2328 6 ismacro = true;
2329 6 newlabelname++;
2330 }
2331
2332
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
129 if (ismacro && macrorecursion == 0) {
2333 throw_err_block(0, err_macro_label_outside_of_macro);
2334 }
2335
2336
3/4
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 63 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 66 times.
129 if (!confirmname(newlabelname))
2337 throw_err_block(0, err_invalid_label_name);
2338
2339 129 string completename;
2340
2341
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 123 times.
129 if (ismacro) {
2342
9/17
✓ Branch 0 taken 3 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 3 times.
✓ Branch 7 taken 3 times.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✗ Branch 16 not taken.
6 completename += STR ":macro_" + dec(calledmacros) + "_";
2343 }
2344
2345
1/2
✓ Branch 0 taken 129 times.
✗ Branch 1 not taken.
129 completename += newlabelname;
2346
2347
4/6
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 66 times.
✗ Branch 5 not taken.
129 setlabel(ns + completename, num, is_static);
2348 129 }
2349
2350 // single_line_for_tracker is:
2351 // 0 if not in first block of line, not in (single-line) for loop
2352 // 1 if first block of line
2353 // 2 if in single-line for loop
2354 // 3 if after endfor (of a single-line loop)
2355 58756 void assembleblock(const char *block, int &single_line_for_tracker) {
2356 // don't do this here; assembleline already did it for us
2357 // callstack_push cs_push(callstack_entry_type::BLOCK, block);
2358
3/3
✓ Branch 0 taken 9013 times.
✓ Branch 1 taken 29261 times.
✓ Branch 2 taken 20482 times.
58756 if (!*block) return;
2359
2360 // assumption: if the first word of a line contains quotes/spaces, it's going
2361 // to be invalid anyways. well, except for character assignment......
2362 40664 string firstword;
2363 40664 const char *params = block;
2364
1/2
✓ Branch 0 taken 40664 times.
✗ Branch 1 not taken.
40664 grab_until_space(firstword, params);
2365
2366 // when writing out the data for the addrToLine mapping,
2367 // we want to write out the snespos we had before writing opcodes
2368 40664 int addrToLinePos = realsnespos & 0xFFFFFF;
2369
2370
2/3
✓ Branch 0 taken 20182 times.
✓ Branch 1 taken 20482 times.
✗ Branch 2 not taken.
40664 string firstword_lower = firstword;
2371 40664 lower(firstword_lower);
2372
2373
5/7
✓ Branch 0 taken 20182 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23566 times.
✓ Branch 3 taken 17098 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3084 times.
✓ Branch 6 taken 17398 times.
40664 if (auto it = control_flow_commands.find(frozen::string(firstword_lower.data(), firstword_lower.length())); it != control_flow_commands.end()) {
2374
4/4
✓ Branch 0 taken 3063 times.
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 3063 times.
✓ Branch 3 taken 21 times.
6168 return it->second(params, single_line_for_tracker);
2375
2/2
✓ Branch 0 taken 1770 times.
✓ Branch 1 taken 32726 times.
34496 } else if (numif != numtrue) {
2376 1770 return;
2377 }
2378
2379 32726 bool addlabeled = false;
2380 // while first word is non-empty,
2381 // and rest {is empty or doesn't start with " = "},
2382 // try to run addlabel
2383 33008 while (firstword[0]
2384
8/8
✓ Branch 0 taken 14551 times.
✓ Branch 1 taken 16591 times.
✓ Branch 2 taken 15310 times.
✓ Branch 3 taken 1107 times.
✓ Branch 4 taken 26831 times.
✓ Branch 5 taken 1404 times.
✓ Branch 6 taken 13384 times.
✓ Branch 7 taken 267 times.
33008 && !(params[0] && params[1] && stribegin(params, "= "))
2385
7/8
✓ Branch 0 taken 33008 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32431 times.
✓ Branch 3 taken 46 times.
✓ Branch 4 taken 1055 times.
✓ Branch 5 taken 31376 times.
✓ Branch 6 taken 1055 times.
✓ Branch 7 taken 31907 times.
66016 && addlabel(firstword)) {
2386 // addlabel was ok, move to the next word
2387 1055 addlabeled = true;
2388 // if there's no next word, we're done here
2389
3/3
✓ Branch 0 taken 376 times.
✓ Branch 1 taken 535 times.
✓ Branch 2 taken 144 times.
1055 if (!*params) return;
2390 // otherwise pull next word into firstword
2391
1/2
✓ Branch 0 taken 282 times.
✗ Branch 1 not taken.
282 grab_until_space(firstword, params);
2392 }
2393
2394
1/2
✓ Branch 0 taken 31907 times.
✗ Branch 1 not taken.
31907 firstword_lower = firstword;
2395 31907 lower(firstword_lower);
2396
2397 // recheck for any of the conditionals tested above
2398
10/15
✓ Branch 0 taken 282 times.
✓ Branch 1 taken 31625 times.
✓ Branch 2 taken 138 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 144 times.
✓ Branch 5 taken 138 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 15814 times.
✓ Branch 8 taken 144 times.
✓ Branch 9 taken 144 times.
✓ Branch 10 taken 15949 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 16093 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
31907 if (addlabeled && control_flow_commands.find(frozen::string(firstword_lower.data(), firstword_lower.length())) != control_flow_commands.end()) {
2399 throw_err_block(0, err_label_before_if, firstword.data());
2400 }
2401
2402
4/4
✓ Branch 0 taken 31887 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 10105 times.
✓ Branch 3 taken 21782 times.
31907 if (asblock_pick(firstword_lower, params)) {
2403
1/2
✓ Branch 0 taken 10105 times.
✗ Branch 1 not taken.
10105 add_addr_to_line(addrToLinePos);
2404 10105 return;
2405 }
2406
2407
3/3
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 10771 times.
✓ Branch 2 taken 10750 times.
21782 if (firstword[0] == '%') {
2408 // imo using strchr here is jank, but it works i guess
2409 // (labels can't contain %)
2410
4/5
✓ Branch 0 taken 255 times.
✓ Branch 1 taken 279 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 267 times.
✓ Branch 4 taken 6 times.
534 return callmacro(strchr(block, '%') + 1);
2411 }
2412
2413
5/7
✓ Branch 0 taken 10498 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20978 times.
✓ Branch 3 taken 270 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 10474 times.
✓ Branch 6 taken 276 times.
21248 if (auto it = normal_commands.find(frozen::string(firstword_lower.data(), firstword_lower.length())); it != normal_commands.end()) {
2414
4/4
✓ Branch 0 taken 5119 times.
✓ Branch 1 taken 5109 times.
✓ Branch 2 taken 5362 times.
✓ Branch 3 taken 5112 times.
20702 return it->second(params);
2415 }
2416
2417
4/4
✓ Branch 0 taken 531 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 525 times.
✓ Branch 3 taken 6 times.
546 if (stribegin(params, "= ")) return cmd_label_assign(firstword, params);
2418
2419
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 throw_err_block(1, err_unknown_command);
2420 51026 }
2421