asar coverage - build #259


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