asar coverage - build #93


src/asar/
File: src/asar/interface-cli.cpp
Date: 2024-01-19 18:20:15
Lines:
158/259
61.0%
Functions:
9/9
100.0%
Branches:
126/425
29.6%

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