asar coverage - build #252


src/asar/
File: src/asar/interface-cli.cpp
Date: 2025-02-21 20:14:43
Lines:
174/286
60.8%
Functions:
9/9
100.0%
Branches:
226/645
35.0%

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