asar coverage - build #


src/asar/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
103 of 288, 0 excluded
35.8%
Functions:
3 of 23, 0 excluded
13.0%
Branches:
121 of 1201, 0 excluded
10.1%

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