asar coverage - build #


src/asar/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
103 of 306, 0 excluded
33.7%
Functions:
2 of 9, 0 excluded
22.2%
Branches:
147 of 1358, 0 excluded
10.8%

interface-cli.cpp
Line Branch Exec Source
1 #include "asar.h"
2 #include "libcon.h"
3 #include "platform/file-helpers.h"
4 #include "virtualfile.h"
5 #include "interface-shared.h"
6 #include "assembleblock.h"
7 #include "asar_math.h"
8 #include "unicode.h"
9 #include "platform/thread-helpers.h"
10
11 #if defined(windows)
12 # define NOMINMAX
13 # include <windows.h>
14 # include <io.h>
15 # include <fcntl.h>
16 #endif
17
18 #ifdef TIMELIMIT
19 # if defined(linux)
20 # include <sys/resource.h>
21 # include <signal.h>
22 # elif defined(_WIN32)
23 //WARNING: The Windows equivalent of SIGXCPU, job limits, is very poorly suited for short-running
24 // tasks like this; it's only checked approximately every seven seconds on the machine I tested on,
25 // and it kills the process instantly once this happens. (Additionally, due to an implementation
26 // quirk, it'll bug up if you ask for anything above about seven minutes, so don't do that.)
27 # define NOMINMAX
28 # include <windows.h>
29 # else
30 # error Time limits not configured for this OS.
31 # endif
32 #endif
33
34 #if defined(linux)
35 # include <unistd.h>
36 #elif defined(_WIN32)
37 # include <windows.h>
38 # include <io.h>
39 #endif
40
41 void print(const char * str)
42 {
43 puts(str);
44 }
45
46 static FILE * errloc=stderr;
47 static int errnum=0;
48
49 enum class ansi_text_color {
50 BRIGHT_RED,
51 BRIGHT_YELLOW,
52 };
53
54 #if defined(_WIN32)
55 static bool has_windows_screen_info = false;
56 static DWORD windows_screen_attributes = 0u;
57 #endif
58
59 static void set_text_color(FILE* output_loc, string* in_out_str, ansi_text_color color)
60 {
61 #if defined(linux)
62 if (isatty(fileno(output_loc)))
63 {
64 switch (color)
65 {
66 case ansi_text_color::BRIGHT_RED:
67 *in_out_str = STR "\u001b[31;1m" + *in_out_str;
68 break;
69 case ansi_text_color::BRIGHT_YELLOW:
70 *in_out_str = STR "\u001b[33;1m" + *in_out_str;
71 break;
72 }
73 }
74 #elif defined(_WIN32)
75 // Currently using SetConsoleTextAttribute() approach over an ASCII escape character
76 // approach because it makes the output text easier to parse. Unfortunately, this
77 // also currently makes this a Windows-only solution.
78 CONSOLE_SCREEN_BUFFER_INFO screenInfo;
79 HANDLE win_handle = (HANDLE)_get_osfhandle(fileno(output_loc));
80 if (GetConsoleScreenBufferInfo(win_handle, &screenInfo) == TRUE)
81 {
82 DWORD wcolor = 0u;
83 switch (color)
84 {
85 case ansi_text_color::BRIGHT_RED:
86 wcolor = FOREGROUND_RED;
87 break;
88 case ansi_text_color::BRIGHT_YELLOW:
89 wcolor = FOREGROUND_RED | FOREGROUND_GREEN;
90 break;
91 }
92
93 windows_screen_attributes = screenInfo.wAttributes;
94 has_windows_screen_info = true;
95 SetConsoleTextAttribute(win_handle, (windows_screen_attributes & 0x00F0) | FOREGROUND_INTENSITY | wcolor);
96 }
97 #endif
98 }
99
100 static void reset_text_color(FILE* output_loc, string* in_out_str)
101 {
102 #if defined(linux)
103 if (isatty(fileno(output_loc)))
104 {
105 *in_out_str = STR "\u001b[0m" + *in_out_str;
106 }
107 #elif defined(_WIN32)
108 if (has_windows_screen_info)
109 {
110 HANDLE win_handle = (HANDLE)_get_osfhandle(fileno(output_loc));
111 SetConsoleTextAttribute(win_handle, windows_screen_attributes);
112 }
113 #endif
114 }
115
116 static int max_num_errors = 20;
117
118 void error_interface(const char* errid, int whichpass, const char * e_)
119 {
120 errored = true;
121 if (pass == whichpass)
122 {
123 errnum++;
124 const char* current_block = get_current_block();
125 // don't show current block if the error came from an error command or limit reached
126 bool show_block = (current_block && (strcmp(errid, "Eerror_command") != 0 && strcmp(errid, "Elimit_reached") != 0));
127 bool show_stack = strcmp(errid, "Elimit_reached") != 0;
128 string location;
129 string details;
130 get_current_line_details(&location, &details, !show_block);
131 string error_string = (show_stack ? location : STR "") + "error: (" + errid + "): " + e_;
132 string details_string = (show_stack ? details + get_callstack() : "") + "\n";
133 set_text_color(errloc, &error_string, ansi_text_color::BRIGHT_RED);
134 fputs(error_string, errloc);
135 reset_text_color(errloc, &details_string);
136 fputs(details_string, errloc);
137 if (errnum == max_num_errors + 1) throw_err_fatal(pass, err_limit_reached, max_num_errors);
138 }
139 }
140
141 static bool werror=false;
142 static bool warned=false;
143
144 void warn(int errid, const char * e_)
145 {
146 const char* current_block = get_current_block();
147 const char* warnname = get_warning_name((asar_warning_id)errid);
148 // don't show current block if the warning came from a warn command
149 bool show_block = (current_block && (strcmp(warnname, "Wwarn_command") != 0));
150 string location;
151 string details;
152 get_current_line_details(&location, &details, !show_block);
153 string warning_string = location+"warning: (" + warnname + "): " + e_;
154 string details_string = details + get_callstack() + "\n";
155 set_text_color(errloc, &warning_string, ansi_text_color::BRIGHT_YELLOW);
156 fputs(warning_string, errloc);
157 reset_text_color(errloc, &details_string);
158 fputs(details_string, errloc);
159 warned=true;
160 }
161
162 #ifdef TIMELIMIT
163 #if defined(linux)
164 void onsigxcpu(int ignored)
165 {
166 error<errnull>(pass, "Time limit exceeded.");
167 exit(1);
168 }
169 #elif defined(_WIN32)
170 //null
171 #endif
172 #endif
173
174 3 int main(int argc, const char * argv[])
175 {
176 #ifdef TIMELIMIT
177 #if defined(linux)
178 rlimit lim;
179 lim.rlim_cur=TIMELIMIT;
180 lim.rlim_max=RLIM_INFINITY;
181 setrlimit(RLIMIT_CPU, &lim);
182 signal(SIGXCPU, onsigxcpu);
183 #elif defined(_WIN32)
184 HANDLE hjob=CreateJobObject(NULL, nullptr);
185 AssignProcessToJobObject(hjob, GetCurrentProcess());
186 JOBOBJECT_BASIC_LIMIT_INFORMATION jbli;
187 jbli.LimitFlags=JOB_OBJECT_LIMIT_PROCESS_TIME;
188 jbli.PerProcessUserTimeLimit.LowPart=10*1000*1000*TIMELIMIT;
189 jbli.PerProcessUserTimeLimit.HighPart=0;
190 SetInformationJobObject(hjob, JobObjectBasicLimitInformation, &jbli, sizeof(jbli));
191 #endif
192 #endif
193
194 #define pause(sev) do { if (pause>=pause_##sev) libcon_pause(); } while(0)
195
196 enum {
197 pause_no,
198 pause_err,
199 pause_warn,
200 pause_yes,
201 3 } pause=pause_no;
202
203 enum cmdlparam
204 {
205 cmdlparam_none,
206
207 cmdlparam_addincludepath,
208 cmdlparam_adddefine,
209
210 cmdlparam_count
211 };
212
213 #if defined(windows)
214 // RPG Hacker: MinGW compatibility hack.
215 # if !defined(_O_U16TEXT)
216 # define _O_U16TEXT 0x20000
217 # endif
218
219 _setmode(_fileno(stdin), _O_U16TEXT);
220 // RPG Hacker: These would currently break Asar, because we're using narrow print functions everywhere.
221 //_setmode(_fileno(stdout), _O_U16TEXT);
222 //_setmode(_fileno(stderr), _O_U16TEXT);
223
224 SetConsoleOutputCP(CP_UTF8);
225 SetConsoleCP(CP_UTF8);
226
227
228 // RPG Hacker: Full Unicode support on Windows requires using a wchar_t command line.
229 // This means we have to convert our arguments from UTF-16 to UTF-8 here.
230 LPWSTR * argv_w = CommandLineToArgvW(GetCommandLineW(), &argc);
231
232 autoarray<string> u8_argv_arr;
233 autoarray<const char *> raw_argv_arr;
234
235 for (int i = 0; i < argc; ++i)
236 {
237 if (!utf16_to_utf8(&u8_argv_arr[i], argv_w[i]))
238 {
239 throw_err_null(pass, err_cmdl_utf16_to_utf8_failed, "Command line arguments on Windows must be valid UTF-16.");
240 pause(err);
241 return 1;
242 }
243
244 raw_argv_arr[i] = u8_argv_arr[i];
245 }
246
247 argv = (const char**)raw_argv_arr;
248 #endif
249
250 try
251 {
252 3 romdata_r = nullptr;
253
12/42
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 3 times.
✓ Branch 7 → 8 taken 3 times.
✗ Branch 7 → 9 not taken.
✓ Branch 12 → 13 taken 3 times.
✗ Branch 12 → 723 not taken.
✓ Branch 18 → 19 taken 3 times.
✗ Branch 18 → 715 not taken.
✓ Branch 24 → 25 taken 3 times.
✗ Branch 24 → 707 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 27 not taken.
✓ Branch 28 → 29 taken 3 times.
✗ Branch 28 → 532 not taken.
✗ Branch 28 → 703 not taken.
✓ Branch 29 → 30 taken 3 times.
✗ Branch 29 → 701 not taken.
✓ Branch 30 → 31 taken 3 times.
✗ Branch 30 → 527 not taken.
✗ Branch 30 → 699 not taken.
✓ Branch 31 → 32 taken 3 times.
✗ Branch 31 → 697 not taken.
✓ Branch 32 → 33 taken 3 times.
✗ Branch 32 → 522 not taken.
✗ Branch 32 → 695 not taken.
✓ Branch 33 → 34 taken 3 times.
✗ Branch 33 → 693 not taken.
✓ Branch 34 → 35 taken 3 times.
✗ Branch 34 → 519 not taken.
✗ Branch 34 → 691 not taken.
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 517 not taken.
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 515 not taken.
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 513 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 511 not taken.
✗ Branch 39 → 40 not taken.
✗ Branch 39 → 509 not taken.
✗ Branch 40 → 41 not taken.
✗ Branch 40 → 507 not taken.
9 string version=STR"Asar "+dec(asarver_maj)+"."+dec(asarver_min)+"."+dec(asarver_bug)+(asarver_beta?"pre":"")
254
1/4
✓ Branch 35 → 36 taken 3 times.
✗ Branch 35 → 689 not taken.
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 505 not taken.
12 +", originally developed by Alcaro, maintained by Asar devs.\n"+
255
1/4
✓ Branch 36 → 37 taken 3 times.
✗ Branch 36 → 687 not taken.
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 503 not taken.
6 "Source code: https://github.com/RPGHacker/asar\n";
256 3 const char * myname=argv[0];
257
3/8
✗ Branch 54 → 55 not taken.
✗ Branch 54 → 56 not taken.
✗ Branch 60 → 61 not taken.
✓ Branch 60 → 62 taken 3 times.
✓ Branch 62 → 63 taken 3 times.
✗ Branch 62 → 67 not taken.
✗ Branch 63 → 64 not taken.
✓ Branch 63 → 65 taken 3 times.
3 if (strrchr(myname, '/')) myname=strrchr(myname, '/')+1;
258 //char * dot=strrchr(myname, '.');
259 //if (dot) *dot='\0';
260 //if (dot) *dot='.';
261
1/4
✗ Branch 56 → 57 not taken.
✗ Branch 56 → 633 not taken.
✓ Branch 67 → 68 taken 3 times.
✗ Branch 67 → 857 not taken.
3 libcon_init(argc, argv,
262 "[options] asm_file [rom_file]\n\n"
263 "Supported options:\n\n"
264 " --version \n"
265 " Display version information.\n\n"
266 " -v, --verbose \n"
267 " Enable verbose mode.\n\n"
268 " --symbols=<none/wla/nocash>\n"
269 " Specifies the format of the symbols output file. (Default is none for no symbols file)\n\n"
270 " --symbols-path=<filename>\n"
271 " Override the default path to the symbols output file. The default is the ROM's base name with an\n"
272 " extension of '.sym'.\n\n"
273 " --no-title-check\n"
274 " Disable verifying ROM title. (Note that irresponsible use will likely corrupt your ROM)\n\n"
275 " --pause-mode=<never/on-error/on-warning/always>\n"
276 " Specify when Asar should pause the application. (Never, on error, on warning or always)\n\n"
277 " --fix-checksum=<on/off>\n"
278 " Override Asar's checksum generation, allowing you to manually enable/disable generating a checksum\n\n"
279 " -I<path> \n"
280 " --include <path> \n"
281 " Add an include search path to Asar.\n\n"
282 " -D<def>[=<val>] \n"
283 " --define <def>[=<val>]\n"
284 " Add a define (optionally with a value) to Asar.\n\n"
285 " -werror \n"
286 " Treat warnings as errors.\n\n"
287 " -w<name> \n"
288 " Enable a specific warning.\n\n"
289 " -wno<name> \n"
290 " Disable a specific warning.\n\n"
291 " --full-error-stack\n"
292 " Enables detailed call stack information for warnings and errors.\n\n"
293 " --error-limit=<N> \n"
294 " Stop after encountering this many errors, instead of the default 20\n\n"
295 );
296 3 ignoretitleerrors=false;
297 3 string par;
298
1/2
✗ Branch 70 → 71 not taken.
✓ Branch 70 → 72 taken 3 times.
3 bool verbose=libcon_interactive;
299
1/4
✗ Branch 58 → 59 not taken.
✗ Branch 58 → 631 not taken.
✓ Branch 73 → 74 taken 3 times.
✗ Branch 73 → 855 not taken.
3 string symbols="";
300
1/4
✗ Branch 59 → 60 not taken.
✗ Branch 59 → 629 not taken.
✓ Branch 75 → 76 taken 3 times.
✗ Branch 75 → 853 not taken.
3 string symfilename="";
301
302 3 autoarray<string> includepaths;
303 3 autoarray<const char*> includepath_cstrs;
304 // need to do this before option processing since the option parser already does set_warning_enabled
305
1/4
✗ Branch 62 → 63 not taken.
✗ Branch 62 → 623 not taken.
✓ Branch 80 → 81 taken 3 times.
✗ Branch 80 → 847 not taken.
3 reset_warnings_to_default();
306
307
4/12
✗ Branch 219 → 220 not taken.
✗ Branch 219 → 623 not taken.
✗ Branch 220 → 221 not taken.
✗ Branch 220 → 623 not taken.
✗ Branch 222 → 64 not taken.
✗ Branch 222 → 223 not taken.
✓ Branch 289 → 290 taken 6 times.
✗ Branch 289 → 847 not taken.
✓ Branch 290 → 291 taken 6 times.
✗ Branch 290 → 847 not taken.
✓ Branch 293 → 82 taken 3 times.
✓ Branch 293 → 294 taken 3 times.
6 while ((par=libcon_option()))
308 {
309 3 cmdlparam postprocess_param = cmdlparam_none;
310 3 const char* postprocess_arg = nullptr;
311
312 #define checkstartmatch(arg, stringliteral) (!strncmp(arg, stringliteral, strlen(stringliteral)))
313
314
1/4
✗ Branch 65 → 66 not taken.
✗ Branch 65 → 67 not taken.
✗ Branch 83 → 84 not taken.
✓ Branch 83 → 85 taken 3 times.
3 if (par=="--no-title-check") ignoretitleerrors=true;
315
3/12
✗ Branch 68 → 69 not taken.
✗ Branch 68 → 71 not taken.
✗ Branch 70 → 71 not taken.
✗ Branch 70 → 72 not taken.
✗ Branch 73 → 74 not taken.
✗ Branch 73 → 75 not taken.
✓ Branch 86 → 87 taken 3 times.
✗ Branch 86 → 89 not taken.
✗ Branch 88 → 89 not taken.
✓ Branch 88 → 90 taken 3 times.
✗ Branch 91 → 92 not taken.
✓ Branch 91 → 93 taken 3 times.
3 else if (par == "-v" || par=="--verbose") verbose=true;
316
2/6
✗ Branch 76 → 77 not taken.
✗ Branch 76 → 87 not taken.
✗ Branch 94 → 95 not taken.
✓ Branch 94 → 96 taken 3 times.
✗ Branch 96 → 97 not taken.
✓ Branch 96 → 107 taken 3 times.
3 else if (checkstartmatch(par, "--symbols="))
317 {
318 if (par == "--symbols=none") symbols = "";
319 else if (par=="--symbols=wla") symbols="wla";
320 else if (par=="--symbols=nocash") symbols="nocash";
321 else libcon_badusage();
322 }
323
2/6
✗ Branch 88 → 89 not taken.
✗ Branch 88 → 91 not taken.
✗ Branch 108 → 109 not taken.
✓ Branch 108 → 110 taken 3 times.
✗ Branch 110 → 111 not taken.
✓ Branch 110 → 114 taken 3 times.
3 else if (checkstartmatch(par, "--symbols-path=")) {
324 symfilename=((const char*)par) + strlen("--symbols-path=");
325 }
326
2/6
✗ Branch 92 → 93 not taken.
✗ Branch 92 → 96 not taken.
✗ Branch 115 → 116 not taken.
✓ Branch 115 → 117 taken 3 times.
✗ Branch 117 → 118 not taken.
✓ Branch 117 → 125 taken 3 times.
3 else if (checkstartmatch(par, "--error-limit="))
327 {
328 char* out;
329 long lim = strtol((const char*)par + strlen("--error-limit="), &out, 10);
330 max_num_errors = lim;
331 }
332
1/4
✗ Branch 97 → 98 not taken.
✗ Branch 97 → 101 not taken.
✗ Branch 126 → 127 not taken.
✓ Branch 126 → 132 taken 3 times.
3 else if (par=="--version")
333 {
334 puts(version);
335 return 0;
336 }
337
2/6
✗ Branch 102 → 103 not taken.
✗ Branch 102 → 116 not taken.
✗ Branch 133 → 134 not taken.
✓ Branch 133 → 135 taken 3 times.
✗ Branch 135 → 136 not taken.
✓ Branch 135 → 149 taken 3 times.
3 else if (checkstartmatch(par, "--pause-mode="))
338 {
339 if (par=="--pause-mode=never") pause=pause_no;
340 else if (par=="--pause-mode=on-error") pause=pause_err;
341 else if (par=="--pause-mode=on-warning") pause=pause_warn;
342 else if (par=="--pause-mode=always") pause=pause_yes;
343 else libcon_badusage();
344 }
345
2/6
✗ Branch 117 → 118 not taken.
✗ Branch 117 → 125 not taken.
✗ Branch 150 → 151 not taken.
✓ Branch 150 → 152 taken 3 times.
✗ Branch 152 → 153 not taken.
✓ Branch 152 → 160 taken 3 times.
3 else if(checkstartmatch(par, "--fix-checksum=")) {
346 if(par=="--fix-checksum=on") {
347 force_checksum_fix = true;
348 checksum_fix_enabled = true;
349 } else if(par=="--fix-checksum=off") {
350 force_checksum_fix = true;
351 checksum_fix_enabled = false;
352 } else libcon_badusage();
353 }
354
2/6
✗ Branch 126 → 127 not taken.
✗ Branch 126 → 129 not taken.
✗ Branch 161 → 162 not taken.
✓ Branch 161 → 163 taken 3 times.
✗ Branch 163 → 164 not taken.
✓ Branch 163 → 167 taken 3 times.
3 else if (checkstartmatch(par, "-I"))
355 {
356 postprocess_param = cmdlparam_addincludepath;
357 postprocess_arg = ((const char*)par) + strlen("-I");
358 }
359
3/6
✗ Branch 130 → 131 not taken.
✗ Branch 130 → 133 not taken.
✗ Branch 168 → 169 not taken.
✓ Branch 168 → 170 taken 3 times.
✓ Branch 170 → 171 taken 2 times.
✓ Branch 170 → 174 taken 1 time.
3 else if (checkstartmatch(par, "-D"))
360 {
361 2 postprocess_param = cmdlparam_adddefine;
362 2 postprocess_arg = ((const char*)par) + strlen("-D");
363 }
364
1/4
✗ Branch 134 → 135 not taken.
✗ Branch 134 → 138 not taken.
✗ Branch 175 → 176 not taken.
✓ Branch 175 → 179 taken 1 time.
1 else if (par == "--include")
365 {
366 postprocess_arg = libcon_option_value();
367 if (postprocess_arg != nullptr)
368 {
369 postprocess_param = cmdlparam_addincludepath;
370 }
371 }
372
1/4
✗ Branch 139 → 140 not taken.
✗ Branch 139 → 143 not taken.
✓ Branch 180 → 181 taken 1 time.
✗ Branch 180 → 184 not taken.
1 else if (par == "--define")
373 {
374
1/4
✗ Branch 140 → 141 not taken.
✗ Branch 140 → 623 not taken.
✓ Branch 181 → 182 taken 1 time.
✗ Branch 181 → 847 not taken.
1 postprocess_arg = libcon_option_value();
375
1/4
✗ Branch 141 → 142 not taken.
✗ Branch 141 → 161 not taken.
✓ Branch 182 → 183 taken 1 time.
✗ Branch 182 → 210 not taken.
1 if (postprocess_arg != nullptr)
376 {
377 1 postprocess_param = cmdlparam_adddefine;
378 }
379 }
380 else if (checkstartmatch(par, "-w"))
381 {
382 const char* w_param = ((const char*)par) + strlen("-w");
383
384 if (checkstartmatch(w_param, "error"))
385 {
386 werror = true;
387 }
388 else if (checkstartmatch(w_param, "no"))
389 {
390 const char* name_start = w_param + strlen("no");
391 asar_warning_id warnid = parse_warning_id_from_string(name_start);
392
393 if (warnid != warning_id_end)
394 {
395 set_warning_enabled(warnid, false);
396 }
397 else
398 {
399 throw_warning(pass, warn_invalid_warning_id, name_start, "-wno");
400 }
401 }
402 else
403 {
404 asar_warning_id warnid = parse_warning_id_from_string(w_param);
405
406 if (warnid != warning_id_end)
407 {
408 set_warning_enabled(warnid, true);
409 }
410 else
411 {
412 throw_warning(pass, warn_invalid_warning_id, w_param, "-w");
413 }
414 }
415
416 }
417 else if (par=="--full-error-stack") simple_callstacks=false;
418 else libcon_badusage();
419
420
1/4
✗ Branch 161 → 162 not taken.
✗ Branch 161 → 166 not taken.
✗ Branch 210 → 211 not taken.
✓ Branch 210 → 217 taken 3 times.
3 if (postprocess_param == cmdlparam_addincludepath)
421 {
422 includepaths.append(postprocess_arg);
423 }
424
1/4
✗ Branch 166 → 167 not taken.
✗ Branch 166 → 218 not taken.
✓ Branch 217 → 218 taken 3 times.
✗ Branch 217 → 288 not taken.
3 else if (postprocess_param == cmdlparam_adddefine)
425 {
426
3/6
✗ Branch 167 → 168 not taken.
✗ Branch 167 → 193 not taken.
✗ Branch 218 → 219 not taken.
✓ Branch 218 → 220 taken 3 times.
✓ Branch 220 → 221 taken 2 times.
✓ Branch 220 → 256 taken 1 time.
3 if (strchr(postprocess_arg, '=') != nullptr)
427 {
428 // argument contains value, not only name
429
1/2
✗ Branch 221 → 222 not taken.
✓ Branch 221 → 223 taken 2 times.
2 const char* eq_loc = strchr(postprocess_arg, '=');
430
1/4
✗ Branch 168 → 169 not taken.
✗ Branch 168 → 541 not taken.
✓ Branch 224 → 225 taken 2 times.
✗ Branch 224 → 737 not taken.
2 string name = string(postprocess_arg, (int)(eq_loc - postprocess_arg));
431
1/4
✗ Branch 169 → 170 not taken.
✗ Branch 169 → 539 not taken.
✓ Branch 225 → 226 taken 2 times.
✗ Branch 225 → 735 not taken.
2 strip_whitespace(name);
432
1/4
✗ Branch 170 → 171 not taken.
✗ Branch 170 → 539 not taken.
✓ Branch 226 → 227 taken 2 times.
✗ Branch 226 → 735 not taken.
2 name.strip_prefix('!'); // remove leading ! if present
433
434
2/12
✗ Branch 172 → 173 not taken.
✗ Branch 172 → 539 not taken.
✗ Branch 173 → 174 not taken.
✗ Branch 173 → 176 not taken.
✗ Branch 175 → 176 not taken.
✗ Branch 175 → 539 not taken.
✓ Branch 228 → 229 taken 2 times.
✗ Branch 228 → 735 not taken.
✗ Branch 229 → 230 not taken.
✓ Branch 229 → 232 taken 2 times.
✗ Branch 231 → 232 not taken.
✗ Branch 231 → 735 not taken.
2 if (!validatedefinename(name)) throw_err_null(pass, err_cmdl_define_invalid, "command line defines", name.data());
435
436
2/8
✗ Branch 177 → 178 not taken.
✗ Branch 177 → 539 not taken.
✗ Branch 178 → 179 not taken.
✗ Branch 178 → 184 not taken.
✓ Branch 234 → 235 taken 2 times.
✗ Branch 234 → 735 not taken.
✗ Branch 235 → 236 not taken.
✓ Branch 235 → 241 taken 2 times.
2 if (clidefines.exists(name)) {
437 throw_err_null(pass, err_cmdl_define_override, "Command line define", name.data());
438 pause(err);
439 return 1;
440 }
441
2/8
✗ Branch 185 → 186 not taken.
✗ Branch 185 → 539 not taken.
✗ Branch 186 → 187 not taken.
✗ Branch 186 → 539 not taken.
✓ Branch 244 → 245 taken 2 times.
✗ Branch 244 → 735 not taken.
✓ Branch 246 → 247 taken 2 times.
✗ Branch 246 → 735 not taken.
2 clidefines.create(name) = eq_loc + 1;
442
1/4
✗ Branch 189 → 190 not taken.
✗ Branch 189 → 192 not taken.
✓ Branch 249 → 250 taken 2 times.
✗ Branch 249 → 251 not taken.
2 }
443 else
444 {
445 // argument doesn't have a value, only name
446
1/4
✗ Branch 193 → 194 not taken.
✗ Branch 193 → 544 not taken.
✓ Branch 257 → 258 taken 1 time.
✗ Branch 257 → 741 not taken.
1 string name = postprocess_arg;
447
1/4
✗ Branch 194 → 195 not taken.
✗ Branch 194 → 542 not taken.
✓ Branch 258 → 259 taken 1 time.
✗ Branch 258 → 739 not taken.
1 strip_whitespace(name);
448
1/4
✗ Branch 195 → 196 not taken.
✗ Branch 195 → 542 not taken.
✓ Branch 259 → 260 taken 1 time.
✗ Branch 259 → 739 not taken.
1 name.strip_prefix('!'); // remove leading ! if present
449
450
2/12
✗ Branch 197 → 198 not taken.
✗ Branch 197 → 542 not taken.
✗ Branch 198 → 199 not taken.
✗ Branch 198 → 201 not taken.
✗ Branch 200 → 201 not taken.
✗ Branch 200 → 542 not taken.
✓ Branch 261 → 262 taken 1 time.
✗ Branch 261 → 739 not taken.
✗ Branch 262 → 263 not taken.
✓ Branch 262 → 265 taken 1 time.
✗ Branch 264 → 265 not taken.
✗ Branch 264 → 739 not taken.
1 if (!validatedefinename(name)) throw_err_null(pass, err_cmdl_define_invalid, "command line defines", name.data());
451
452
2/8
✗ Branch 202 → 203 not taken.
✗ Branch 202 → 542 not taken.
✗ Branch 203 → 204 not taken.
✗ Branch 203 → 209 not taken.
✓ Branch 267 → 268 taken 1 time.
✗ Branch 267 → 739 not taken.
✗ Branch 268 → 269 not taken.
✓ Branch 268 → 274 taken 1 time.
1 if (clidefines.exists(name)) {
453 throw_err_null(pass, err_cmdl_define_override, "Command line define", name.data());
454 pause(err);
455 return 1;
456 }
457
2/8
✗ Branch 210 → 211 not taken.
✗ Branch 210 → 542 not taken.
✗ Branch 211 → 212 not taken.
✗ Branch 211 → 542 not taken.
✓ Branch 276 → 277 taken 1 time.
✗ Branch 276 → 739 not taken.
✓ Branch 278 → 279 taken 1 time.
✗ Branch 278 → 739 not taken.
1 clidefines.create(name) = "";
458
1/4
✗ Branch 214 → 215 not taken.
✗ Branch 214 → 217 not taken.
✓ Branch 281 → 282 taken 1 time.
✗ Branch 281 → 283 not taken.
1 }
459 }
460 }
461
2/4
✗ Branch 223 → 224 not taken.
✗ Branch 223 → 226 not taken.
✓ Branch 294 → 295 taken 1 time.
✓ Branch 294 → 299 taken 2 times.
3 if (verbose)
462 {
463
2/6
✗ Branch 225 → 226 not taken.
✗ Branch 225 → 623 not taken.
✗ Branch 296 → 297 not taken.
✓ Branch 296 → 298 taken 1 time.
✓ Branch 298 → 299 taken 1 time.
✗ Branch 298 → 847 not taken.
1 puts(version);
464 }
465
2/8
✗ Branch 226 → 227 not taken.
✗ Branch 226 → 623 not taken.
✗ Branch 227 → 228 not taken.
✗ Branch 227 → 623 not taken.
✓ Branch 300 → 301 taken 3 times.
✗ Branch 300 → 847 not taken.
✓ Branch 301 → 302 taken 3 times.
✗ Branch 301 → 847 not taken.
3 string asmname=libcon_require_filename("Enter patch name:");
466
2/8
✗ Branch 228 → 229 not taken.
✗ Branch 228 → 621 not taken.
✗ Branch 229 → 230 not taken.
✗ Branch 229 → 621 not taken.
✓ Branch 303 → 304 taken 3 times.
✗ Branch 303 → 845 not taken.
✓ Branch 304 → 305 taken 3 times.
✗ Branch 304 → 845 not taken.
3 string romname=libcon_optional_filename("Enter ROM name:", nullptr);
467 //char * outname=libcon_optional_filename("Enter output ROM name:", nullptr);
468
1/4
✗ Branch 230 → 231 not taken.
✗ Branch 230 → 619 not taken.
✓ Branch 305 → 306 taken 3 times.
✗ Branch 305 → 843 not taken.
3 libcon_end();
469
3/22
✗ Branch 232 → 233 not taken.
✗ Branch 232 → 237 not taken.
✗ Branch 234 → 235 not taken.
✗ Branch 234 → 619 not taken.
✗ Branch 235 → 236 not taken.
✗ Branch 235 → 237 not taken.
✗ Branch 238 → 239 not taken.
✗ Branch 238 → 240 not taken.
✗ Branch 239 → 240 not taken.
✗ Branch 239 → 619 not taken.
✗ Branch 307 → 308 not taken.
✓ Branch 307 → 309 taken 3 times.
✗ Branch 309 → 310 not taken.
✓ Branch 309 → 314 taken 3 times.
✗ Branch 311 → 312 not taken.
✗ Branch 311 → 843 not taken.
✗ Branch 312 → 313 not taken.
✗ Branch 312 → 314 not taken.
✗ Branch 315 → 316 not taken.
✓ Branch 315 → 317 taken 3 times.
✗ Branch 316 → 317 not taken.
✗ Branch 316 → 843 not taken.
3 if (!strchr(asmname, '.') && !file_exists(asmname)) asmname+=".asm";
470
1/4
✗ Branch 241 → 242 not taken.
✗ Branch 241 → 268 not taken.
✗ Branch 318 → 319 not taken.
✓ Branch 318 → 358 taken 3 times.
3 if (!romname)
471 {
472 string romnametmp = get_base_name(asmname);
473 if (file_exists(romnametmp+".sfc")) romname=romnametmp+".sfc";
474 else if (file_exists(romnametmp+".smc")) romname=romnametmp+".smc";
475 else romname=romnametmp+".sfc";
476 }
477
3/18
✗ Branch 269 → 270 not taken.
✗ Branch 269 → 274 not taken.
✗ Branch 271 → 272 not taken.
✗ Branch 271 → 619 not taken.
✗ Branch 272 → 273 not taken.
✗ Branch 272 → 274 not taken.
✗ Branch 275 → 276 not taken.
✗ Branch 275 → 288 not taken.
✗ Branch 359 → 360 not taken.
✓ Branch 359 → 361 taken 3 times.
✗ Branch 361 → 362 not taken.
✓ Branch 361 → 366 taken 3 times.
✗ Branch 363 → 364 not taken.
✗ Branch 363 → 843 not taken.
✗ Branch 364 → 365 not taken.
✗ Branch 364 → 366 not taken.
✗ Branch 367 → 368 not taken.
✓ Branch 367 → 386 taken 3 times.
3 else if (!strchr(romname, '.') && !file_exists(romname))
478 {
479 if (file_exists(romname+".sfc")) romname+=".sfc";
480 else if (file_exists(romname+".smc")) romname+=".smc";
481 }
482
2/8
✗ Branch 289 → 290 not taken.
✗ Branch 289 → 619 not taken.
✗ Branch 290 → 291 not taken.
✗ Branch 290 → 298 not taken.
✓ Branch 387 → 388 taken 3 times.
✗ Branch 387 → 843 not taken.
✓ Branch 388 → 389 taken 3 times.
✗ Branch 388 → 396 not taken.
3 if (!file_exists(romname))
483 {
484
1/4
✗ Branch 292 → 293 not taken.
✗ Branch 292 → 619 not taken.
✓ Branch 390 → 391 taken 3 times.
✗ Branch 390 → 843 not taken.
3 FileHandleType f = open_file(romname, FileOpenMode_Write);
485
1/4
✗ Branch 293 → 294 not taken.
✗ Branch 293 → 297 not taken.
✗ Branch 391 → 392 not taken.
✓ Branch 391 → 395 taken 3 times.
3 if (f == InvalidFileHandle)
486 {
487 throw_err_fatal(pass, err_create_rom_failed);
488 }
489
1/4
✗ Branch 297 → 298 not taken.
✗ Branch 297 → 619 not taken.
✓ Branch 395 → 396 taken 3 times.
✗ Branch 395 → 843 not taken.
3 close_file(f);
490 }
491
2/8
✗ Branch 299 → 300 not taken.
✗ Branch 299 → 619 not taken.
✗ Branch 300 → 301 not taken.
✗ Branch 300 → 304 not taken.
✓ Branch 397 → 398 taken 3 times.
✗ Branch 397 → 843 not taken.
✗ Branch 398 → 399 not taken.
✓ Branch 398 → 402 taken 3 times.
3 if (!openrom(romname, false))
492 {
493 pause(err);
494 return 1;
495 }
496 //check if the ROM title and checksum looks sane
497
1/10
✗ Branch 304 → 305 not taken.
✗ Branch 304 → 357 not taken.
✗ Branch 305 → 306 not taken.
✗ Branch 305 → 357 not taken.
✗ Branch 402 → 403 not taken.
✓ Branch 402 → 481 taken 3 times.
✗ Branch 403 → 404 not taken.
✗ Branch 403 → 405 not taken.
✗ Branch 405 → 406 not taken.
✗ Branch 405 → 481 not taken.
3 if (romlen>=32768 && !ignoretitleerrors)
498 {
499 bool validtitle=setmapper();
500 if (!validtitle)
501 {
502 string title;
503 for (int i=0;i<21;i++)
504 {
505 unsigned char c=romdata[snestopc(0x00FFC0+i)];
506 if (c==7) c=14;
507 if (c==8) c=27;//to not generate more hard-to-print characters than needed
508 if (c==9) c=26;//random characters are picked in accordance with the charset Windows-1252, but they should be garbage in all charsets
509 if (c=='\r') c=17;
510 if (c=='\n') c=25;
511 if (c=='\0') c=155;
512 title+=(char)c;
513 }
514 if (libcon_interactive)
515 {
516 if (!libcon_question_bool(STR"Warning: The ROM title appears to be \""+title+"\", which looks like garbage. "
517 "Is this your ROM title? (Note that improperly answering \"yes\" will crash your ROM.)", false))
518 {
519 puts("Assembling aborted. snespurify should be able to fix your ROM.");
520 return 1;
521 }
522 }
523 else
524 {
525 puts(STR"Error: The ROM title appears to be \""+title+"\", which looks like garbage. "
526 "If this is the ROM title, add --no-title-check to the command line options. If the ROM title is something else, use snespurify on your ROM.");
527 pause(err);
528 return 1;
529 }
530 }
531 }
532
533
2/8
✗ Branch 357 → 358 not taken.
✗ Branch 357 → 586 not taken.
✗ Branch 358 → 359 not taken.
✗ Branch 358 → 584 not taken.
✓ Branch 484 → 485 taken 3 times.
✗ Branch 484 → 799 not taken.
✓ Branch 485 → 486 taken 3 times.
✗ Branch 485 → 797 not taken.
3 string stdincludespath = STR dir(argv[0]) + "stdincludes.txt";
534
1/4
✗ Branch 361 → 362 not taken.
✗ Branch 361 → 617 not taken.
✓ Branch 489 → 490 taken 3 times.
✗ Branch 489 → 841 not taken.
3 parse_std_includes(stdincludespath, includepaths);
535
536
1/4
✗ Branch 367 → 363 not taken.
✗ Branch 367 → 368 not taken.
✗ Branch 499 → 491 not taken.
✓ Branch 499 → 500 taken 3 times.
3 for (int i = 0; i < includepaths.count; ++i)
537 {
538 includepath_cstrs.append((const char*)includepaths[i]);
539 }
540
541 3 size_t includepath_count = (size_t)includepath_cstrs.count;
542
1/4
✗ Branch 368 → 369 not taken.
✗ Branch 368 → 617 not taken.
✓ Branch 501 → 502 taken 3 times.
✗ Branch 501 → 841 not taken.
3 virtual_filesystem new_filesystem;
543
2/8
✗ Branch 369 → 370 not taken.
✗ Branch 369 → 615 not taken.
✗ Branch 370 → 371 not taken.
✗ Branch 370 → 615 not taken.
✓ Branch 502 → 503 taken 3 times.
✗ Branch 502 → 839 not taken.
✓ Branch 503 → 504 taken 3 times.
✗ Branch 503 → 839 not taken.
3 new_filesystem.initialize(&includepath_cstrs[0], includepath_count);
544 3 filesystem = &new_filesystem;
545
546
2/8
✗ Branch 371 → 372 not taken.
✗ Branch 371 → 590 not taken.
✗ Branch 372 → 373 not taken.
✗ Branch 372 → 588 not taken.
✓ Branch 507 → 508 taken 3 times.
✗ Branch 507 → 805 not taken.
✓ Branch 508 → 509 taken 3 times.
✗ Branch 508 → 803 not taken.
3 string stddefinespath = STR dir(argv[0]) + "stddefines.txt";
547
1/4
✗ Branch 375 → 376 not taken.
✗ Branch 375 → 613 not taken.
✓ Branch 512 → 513 taken 3 times.
✗ Branch 512 → 837 not taken.
3 parse_std_defines(stddefinespath);
548
549 3 auto execute_patch = [&]()
550 {
551 try {
552
2/4
✗ Branch 14 → 3 not taken.
✗ Branch 14 → 15 not taken.
✓ Branch 22 → 3 taken 9 times.
✓ Branch 22 → 23 taken 3 times.
12 for (pass=0;pass<3;pass++)
553 {
554 //pass 1: find which bank all labels are in, for label optimizations
555 // freespaces are listed as above 0xFFFFFF, to find if it's in the ROM or if it's dynamic
556 //pass 2: find where exactly all labels are
557 //pass 3: assemble it all
558
1/3
✓ Branch 3 → 4 taken 9 times.
✗ Branch 3 → 21 not taken.
✗ Branch 3 → 29 not taken.
9 initstuff();
559
1/4
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 21 not taken.
✓ Branch 7 → 8 taken 9 times.
✗ Branch 7 → 29 not taken.
9 assemblefile(asmname);
560 // RPG Hacker: Necessary, because finishpass() can throws warning and errors.
561
1/4
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 21 not taken.
✓ Branch 12 → 13 taken 9 times.
✗ Branch 12 → 29 not taken.
9 string asmpath = filesystem->create_absolute_path(nullptr, asmname);
562
1/4
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 19 not taken.
✓ Branch 15 → 16 taken 9 times.
✗ Branch 15 → 27 not taken.
9 callstack_push cs_push(callstack_entry_type::FILE, asmpath);
563
1/4
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 17 not taken.
✓ Branch 16 → 17 taken 9 times.
✗ Branch 16 → 25 not taken.
9 finishpass();
564 9 }
565 3 return true;
566 } catch(errfatal&) {
567 return false;
568 }
569 3 };
570 #if defined(RUN_VIA_FIBER)
571 run_as_fiber(execute_patch);
572 #elif defined(RUN_VIA_THREAD)
573
1/4
✗ Branch 376 → 377 not taken.
✗ Branch 376 → 613 not taken.
✓ Branch 514 → 515 taken 3 times.
✗ Branch 514 → 837 not taken.
3 run_as_thread(execute_patch);
574 #else
575 execute_patch();
576 #endif
577
578
1/4
✗ Branch 377 → 378 not taken.
✗ Branch 377 → 613 not taken.
✓ Branch 515 → 516 taken 3 times.
✗ Branch 515 → 837 not taken.
3 closecachedfiles(); // this needs the vfs so do it before destroying it
579
1/4
✗ Branch 378 → 379 not taken.
✗ Branch 378 → 613 not taken.
✓ Branch 516 → 517 taken 3 times.
✗ Branch 516 → 837 not taken.
3 new_filesystem.destroy();
580 3 filesystem = nullptr;
581
582
2/16
✗ Branch 379 → 380 not taken.
✗ Branch 379 → 382 not taken.
✗ Branch 380 → 381 not taken.
✗ Branch 380 → 382 not taken.
✗ Branch 381 → 382 not taken.
✗ Branch 381 → 613 not taken.
✗ Branch 517 → 518 not taken.
✓ Branch 517 → 519 taken 3 times.
✗ Branch 519 → 520 not taken.
✓ Branch 519 → 524 taken 3 times.
✗ Branch 520 → 521 not taken.
✗ Branch 520 → 522 not taken.
✗ Branch 522 → 523 not taken.
✗ Branch 522 → 524 not taken.
✗ Branch 523 → 524 not taken.
✗ Branch 523 → 837 not taken.
3 if (werror && warned) throw_err_null(pass, err_werror);
583
3/10
✗ Branch 382 → 383 not taken.
✗ Branch 382 → 384 not taken.
✗ Branch 383 → 384 not taken.
✗ Branch 383 → 613 not taken.
✗ Branch 524 → 525 not taken.
✓ Branch 524 → 526 taken 3 times.
✓ Branch 526 → 527 taken 3 times.
✗ Branch 526 → 528 not taken.
✓ Branch 527 → 528 taken 3 times.
✗ Branch 527 → 837 not taken.
3 if (checksum_fix_enabled) fixchecksum();
584 //if (pcpos>romlen) romlen=pcpos;
585
2/6
✗ Branch 384 → 385 not taken.
✗ Branch 384 → 393 not taken.
✗ Branch 528 → 529 not taken.
✓ Branch 528 → 530 taken 3 times.
✗ Branch 530 → 531 not taken.
✓ Branch 530 → 539 taken 3 times.
3 if (errored)
586 {
587 if (errnum==0)
588 throw_err_null(pass, err_internal_error, "phantom error");
589 puts("Errors were detected while assembling the patch. Assembling aborted. Your ROM has not been modified.");
590 closerom(false);
591 reseteverything();
592 pause(err);
593 return 1;
594 }
595
2/6
✗ Branch 393 → 394 not taken.
✗ Branch 393 → 405 not taken.
✗ Branch 539 → 540 not taken.
✓ Branch 539 → 541 taken 3 times.
✗ Branch 541 → 542 not taken.
✓ Branch 541 → 555 taken 3 times.
3 if (warned)
596 {
597 if (libcon_interactive)
598 {
599 if (!libcon_question_bool("One or more warnings were detected while assembling the patch. "
600 "Do you want insert the patch anyways? (Default: yes)", true))
601 {
602 puts("ROM left unchanged.");
603 closerom(false);
604 reseteverything();
605 return 1;
606 }
607 }
608 else
609 {
610 if (verbose) puts("Assembling completed, but one or more warnings were detected.");
611 pause(warn);
612 }
613 }
614 else
615 {
616
3/8
✗ Branch 405 → 406 not taken.
✗ Branch 405 → 407 not taken.
✗ Branch 406 → 407 not taken.
✗ Branch 406 → 613 not taken.
✓ Branch 555 → 556 taken 1 time.
✓ Branch 555 → 557 taken 2 times.
✓ Branch 556 → 557 taken 1 time.
✗ Branch 556 → 837 not taken.
3 if (verbose) puts("Assembling completed without problems.");
617
1/8
✗ Branch 407 → 408 not taken.
✗ Branch 407 → 409 not taken.
✗ Branch 408 → 409 not taken.
✗ Branch 408 → 613 not taken.
✗ Branch 557 → 558 not taken.
✓ Branch 557 → 559 taken 3 times.
✗ Branch 558 → 559 not taken.
✗ Branch 558 → 837 not taken.
3 pause(yes);
618 }
619
1/4
✗ Branch 409 → 410 not taken.
✗ Branch 409 → 613 not taken.
✓ Branch 559 → 560 taken 3 times.
✗ Branch 559 → 837 not taken.
3 unsigned int romCrc = closerom();
620
1/4
✗ Branch 411 → 412 not taken.
✗ Branch 411 → 452 not taken.
✗ Branch 561 → 562 not taken.
✓ Branch 561 → 625 taken 3 times.
3 if (symbols)
621 {
622 if (!symfilename) symfilename = get_base_name(romname)+".sym";
623 string contents = create_symbols_file(symbols, romCrc).convert_line_endings_to_native();
624
625 FileHandleType symfile = open_file(symfilename, FileOpenMode_Write);
626
627 if (symfile == InvalidFileHandle)
628 {
629 puts(STR"Failed to create symbols file: \""+symfilename+"\".");
630 pause(err);
631 return 1;
632 }
633 else
634 {
635 write_file(symfile, (const char*)contents, (uint32_t)contents.length());
636 close_file(symfile);
637 }
638 }
639
1/4
✗ Branch 452 → 453 not taken.
✗ Branch 452 → 613 not taken.
✓ Branch 625 → 626 taken 3 times.
✗ Branch 625 → 837 not taken.
3 reseteverything();
640
11/44
✗ Branch 455 → 456 not taken.
✗ Branch 455 → 457 not taken.
✗ Branch 459 → 460 not taken.
✗ Branch 459 → 461 not taken.
✗ Branch 463 → 464 not taken.
✗ Branch 463 → 465 not taken.
✗ Branch 467 → 468 not taken.
✗ Branch 467 → 469 not taken.
✗ Branch 471 → 472 not taken.
✗ Branch 471 → 473 not taken.
✗ Branch 475 → 476 not taken.
✗ Branch 475 → 477 not taken.
✗ Branch 479 → 480 not taken.
✗ Branch 479 → 481 not taken.
✗ Branch 483 → 484 not taken.
✗ Branch 483 → 485 not taken.
✗ Branch 487 → 488 not taken.
✗ Branch 487 → 489 not taken.
✗ Branch 491 → 492 not taken.
✗ Branch 491 → 493 not taken.
✗ Branch 495 → 496 not taken.
✗ Branch 495 → 498 not taken.
✓ Branch 628 → 629 taken 3 times.
✗ Branch 628 → 630 not taken.
✓ Branch 632 → 633 taken 3 times.
✗ Branch 632 → 634 not taken.
✓ Branch 636 → 637 taken 3 times.
✗ Branch 636 → 638 not taken.
✓ Branch 640 → 641 taken 3 times.
✗ Branch 640 → 642 not taken.
✓ Branch 644 → 645 taken 3 times.
✗ Branch 644 → 646 not taken.
✓ Branch 648 → 649 taken 3 times.
✗ Branch 648 → 650 not taken.
✓ Branch 652 → 653 taken 3 times.
✗ Branch 652 → 654 not taken.
✓ Branch 656 → 657 taken 3 times.
✗ Branch 656 → 658 not taken.
✓ Branch 660 → 661 taken 3 times.
✗ Branch 660 → 662 not taken.
✓ Branch 664 → 665 taken 3 times.
✗ Branch 664 → 666 not taken.
✓ Branch 668 → 669 taken 3 times.
✗ Branch 668 → 670 not taken.
3 }
641 catch(errfatal&)
642 {
643 puts("A fatal error was detected while assembling the patch. Assembling aborted. Your ROM has not been modified.");
644 closerom(false);
645 reseteverything();
646 pause(err);
647 return 1;
648 }
649 3 return 0;
650 }
651