asar coverage - build #158


src/asar/
File: src/asar/interface-cli.cpp
Date: 2024-01-26 20:14:55
Lines:
172/285
60.4%
Functions:
9/9
100.0%
Branches:
222/663
33.5%

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 228 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 114 times.
114 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 114 HANDLE win_handle = (HANDLE)_get_osfhandle(fileno(output_loc));
84
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 114 times.
114 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 228 }
103
104 228 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 114 times.
114 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 114 times.
114 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 228 }
119
120 static int max_num_errors = 20;
121
122 468 void error_interface(int errid, int whichpass, const char * e_)
123 {
124 468 errored = true;
125
2/2
✓ Branch 0 taken 196 times.
✓ Branch 1 taken 272 times.
468 if (pass == whichpass)
126 {
127 196 errnum++;
128
1/2
✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
196 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 188 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 91 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 91 times.
✗ Branch 5 not taken.
196 bool show_block = (current_block && (errid != error_id_error_command && errid != error_id_limit_reached));
131 98 bool show_stack = (errid != error_id_limit_reached);
132 98 string location;
133 98 string details;
134
1/2
✓ Branch 0 taken 196 times.
✗ Branch 1 not taken.
196 get_current_line_details(&location, &details, !show_block);
135
7/16
✓ Branch 0 taken 196 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 196 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 98 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 98 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 98 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 98 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 98 times.
✗ Branch 15 not taken.
294 string error_string = (show_stack ? location+": " : STR "") + "error: (" + get_error_name((asar_error_id)errid) + "): " + e_;
136
5/14
✓ Branch 0 taken 196 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 196 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 196 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 98 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 98 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
294 string details_string = (show_stack ? details + get_callstack() : "") + "\n";
137
1/2
✓ Branch 0 taken 196 times.
✗ Branch 1 not taken.
196 set_text_color(errloc, &error_string, ansi_text_color::BRIGHT_RED);
138
1/2
✓ Branch 0 taken 196 times.
✗ Branch 1 not taken.
196 fputs(error_string, errloc);
139
1/2
✓ Branch 0 taken 196 times.
✗ Branch 1 not taken.
196 reset_text_color(errloc, &details_string);
140
1/2
✓ Branch 0 taken 196 times.
✗ Branch 1 not taken.
196 fputs(details_string, errloc);
141
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 196 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
196 if (errnum == max_num_errors + 1) asar_throw_error(pass, error_type_fatal, error_id_limit_reached, max_num_errors);
142 196 }
143 468 }
144
145 static bool werror=false;
146 static bool warned=false;
147
148 32 void warn(int errid, const char * e_)
149 {
150
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
32 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 15 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 3 times.
32 bool show_block = (current_block && (errid != warning_id_warn_command));
153 16 string location;
154 16 string details;
155
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 get_current_line_details(&location, &details, !show_block);
156
5/10
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 16 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 16 times.
✗ Branch 9 not taken.
48 string warning_string = location+": warning: (" + get_warning_name((asar_warning_id)errid) + "): " + e_;
157
3/6
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
48 string details_string = details + get_callstack() + "\n";
158
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 set_text_color(errloc, &warning_string, ansi_text_color::BRIGHT_YELLOW);
159
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 fputs(warning_string, errloc);
160
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 reset_text_color(errloc, &details_string);
161
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 fputs(details_string, errloc);
162 32 warned=true;
163 32 }
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 236 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 118 } 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 118 _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 118 SetConsoleOutputCP(CP_UTF8);
229 118 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 118 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 1180 times.
✓ Branch 1 taken 118 times.
1298 for (int i = 0; i < argc; ++i)
240 {
241
2/4
✓ Branch 0 taken 1180 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1180 times.
1180 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 1180 raw_argv_arr[i] = u8_argv_arr[i];
249 }
250
251 argv = (const char**)raw_argv_arr;
252 #endif
253
254 try
255 {
256 236 romdata_r = nullptr;
257
12/22
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 118 times.
✓ Branch 2 taken 118 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 118 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 118 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 118 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 118 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 118 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 118 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 118 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 118 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 118 times.
✗ Branch 21 not taken.
472 string version=STR"Asar "+dec(asarver_maj)+"."+dec(asarver_min)+"."+dec(asarver_bug)+(asarver_beta?"pre":"")
258
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
354 +", originally developed by Alcaro, maintained by Asar devs.\n"+
259
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 "Source code: https://github.com/RPGHacker/asar\n";
260 118 const char * myname=argv[0];
261
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 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 236 times.
✗ Branch 1 not taken.
236 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 236 ignoretitleerrors=false;
301 118 string par;
302 236 bool verbose=libcon_interactive;
303
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 string symbols="";
304
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 string symfilename="";
305
306 118 autoarray<string> includepaths;
307 118 autoarray<const char*> includepath_cstrs;
308
309
6/8
✓ Branch 0 taken 1652 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1534 times.
✓ Branch 3 taken 118 times.
✓ Branch 4 taken 826 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 708 times.
✓ Branch 7 taken 118 times.
2478 while ((par=libcon_option()))
310 {
311 708 cmdlparam postprocess_param = cmdlparam_none;
312 708 const char* postprocess_arg = nullptr;
313
314 #define checkstartmatch(arg, stringliteral) (!strncmp(arg, stringliteral, strlen(stringliteral)))
315
316
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1416 times.
1416 if (par=="--no-title-check") ignoretitleerrors=true;
317
4/6
✓ Branch 0 taken 1416 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 708 times.
✓ Branch 3 taken 708 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 708 times.
1416 else if (par == "-v" || par=="--verbose") verbose=true;
318
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1416 times.
1416 else if (checkstartmatch(par, "--symbols="))
319 {
320 if (par == "--symbols=none") symbols = "";
321 else if (par=="--symbols=wla") symbols="wla";
322 else if (par=="--symbols=nocash") symbols="nocash";
323 else libcon_badusage();
324 }
325
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1416 times.
1416 else if (checkstartmatch(par, "--symbols-path=")) {
326 symfilename=((const char*)par) + strlen("--symbols-path=");
327 }
328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1416 times.
1416 else if (checkstartmatch(par, "--error-limit="))
329 {
330 char* out;
331 long lim = strtol((const char*)par + strlen("--error-limit="), &out, 10);
332 max_num_errors = lim;
333 }
334
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1416 times.
1416 else if (par=="--version")
335 {
336 puts(version);
337 return 0;
338 }
339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1416 times.
1416 else if (checkstartmatch(par, "--pause-mode="))
340 {
341 if (par=="--pause-mode=never") pause=pause_no;
342 else if (par=="--pause-mode=on-error") pause=pause_err;
343 else if (par=="--pause-mode=on-warning") pause=pause_warn;
344 else if (par=="--pause-mode=always") pause=pause_yes;
345 else libcon_badusage();
346 }
347
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1416 times.
1416 else if(checkstartmatch(par, "--fix-checksum=")) {
348 if(par=="--fix-checksum=on") {
349 force_checksum_fix = true;
350 checksum_fix_enabled = true;
351 } else if(par=="--fix-checksum=off") {
352 force_checksum_fix = true;
353 checksum_fix_enabled = false;
354 } else libcon_badusage();
355 }
356
2/2
✓ Branch 0 taken 236 times.
✓ Branch 1 taken 1180 times.
1416 else if (checkstartmatch(par, "-I"))
357 {
358 118 postprocess_param = cmdlparam_addincludepath;
359 236 postprocess_arg = ((const char*)par) + strlen("-I");
360 }
361
2/2
✓ Branch 0 taken 944 times.
✓ Branch 1 taken 236 times.
1180 else if (checkstartmatch(par, "-D"))
362 {
363 472 postprocess_param = cmdlparam_adddefine;
364 944 postprocess_arg = ((const char*)par) + strlen("-D");
365 }
366
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 236 times.
236 else if (par == "--include")
367 {
368 postprocess_arg = libcon_option_value();
369 if (postprocess_arg != nullptr)
370 {
371 postprocess_param = cmdlparam_addincludepath;
372 }
373 }
374
1/2
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
236 else if (par == "--define")
375 {
376
1/2
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
236 postprocess_arg = libcon_option_value();
377
2/2
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 118 times.
236 if (postprocess_arg != nullptr)
378 {
379 118 postprocess_param = cmdlparam_adddefine;
380 }
381 }
382 else if (checkstartmatch(par, "-w"))
383 {
384 const char* w_param = ((const char*)par) + strlen("-w");
385
386 if (checkstartmatch(w_param, "error"))
387 {
388 werror = true;
389 }
390 else if (checkstartmatch(w_param, "no"))
391 {
392 const char* name_start = w_param + strlen("no");
393 asar_warning_id warnid = parse_warning_id_from_string(name_start);
394
395 if (warnid != warning_id_end)
396 {
397 set_warning_enabled(warnid, false);
398 }
399 else
400 {
401 asar_throw_error(pass, error_type_null, error_id_invalid_warning_id, name_start, "-wno");
402 }
403 }
404 else
405 {
406 asar_warning_id warnid = parse_warning_id_from_string(w_param);
407
408 if (warnid != warning_id_end)
409 {
410 set_warning_enabled(warnid, true);
411 }
412 else
413 {
414 asar_throw_error(pass, error_type_null, error_id_invalid_warning_id, w_param, "-w");
415 }
416 }
417
418 }
419 else if (par=="--full-error-stack") simple_callstacks=false;
420 else libcon_badusage();
421
422
2/2
✓ Branch 0 taken 236 times.
✓ Branch 1 taken 1180 times.
1416 if (postprocess_param == cmdlparam_addincludepath)
423 {
424
2/4
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 118 times.
✗ Branch 3 not taken.
236 includepaths.append(postprocess_arg);
425 }
426
1/2
✓ Branch 0 taken 1180 times.
✗ Branch 1 not taken.
1180 else if (postprocess_param == cmdlparam_adddefine)
427 {
428
2/2
✓ Branch 0 taken 944 times.
✓ Branch 1 taken 236 times.
1180 if (strchr(postprocess_arg, '=') != nullptr)
429 {
430 // argument contains value, not only name
431 472 const char* eq_loc = strchr(postprocess_arg, '=');
432
1/2
✓ Branch 0 taken 472 times.
✗ Branch 1 not taken.
944 string name = string(postprocess_arg, (int)(eq_loc - postprocess_arg));
433
1/2
✓ Branch 0 taken 472 times.
✗ Branch 1 not taken.
944 strip_whitespace(name);
434
1/2
✓ Branch 0 taken 472 times.
✗ Branch 1 not taken.
944 name.strip_prefix('!'); // remove leading ! if present
435
436
2/6
✓ Branch 0 taken 944 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 944 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
944 if (!validatedefinename(name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_invalid, "command line defines", name.data());
437
438
3/4
✓ Branch 0 taken 472 times.
✓ Branch 1 taken 472 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 472 times.
944 if (clidefines.exists(name)) {
439 asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Command line define", name.data());
440 pause(err);
441 return 1;
442 }
443
2/4
✓ Branch 0 taken 944 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 472 times.
✗ Branch 3 not taken.
944 clidefines.create(name) = eq_loc + 1;
444
1/2
✓ Branch 0 taken 472 times.
✗ Branch 1 not taken.
944 }
445 else
446 {
447 // argument doesn't have a value, only name
448
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 string name = postprocess_arg;
449
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
236 strip_whitespace(name);
450
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
236 name.strip_prefix('!'); // remove leading ! if present
451
452
2/6
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 236 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
236 if (!validatedefinename(name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_invalid, "command line defines", name.data());
453
454
3/4
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 118 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 118 times.
236 if (clidefines.exists(name)) {
455 asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "Command line define", name.data());
456 pause(err);
457 return 1;
458 }
459
2/4
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 118 times.
✗ Branch 3 not taken.
236 clidefines.create(name) = "";
460
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
236 }
461 }
462 }
463
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 236 times.
236 if (verbose)
464 {
465 puts(version);
466 }
467
2/4
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 118 times.
✗ Branch 3 not taken.
236 string asmname=libcon_require_filename("Enter patch name:");
468
2/4
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 118 times.
✗ Branch 3 not taken.
236 string romname=libcon_optional_filename("Enter ROM name:", nullptr);
469 //char * outname=libcon_optional_filename("Enter output ROM name:", nullptr);
470
1/2
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
236 libcon_end();
471
2/10
✗ Branch 0 not taken.
✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 118 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
236 if (!strchr(asmname, '.') && !file_exists(asmname)) asmname+=".asm";
472
3/4
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 118 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 118 times.
236 if (!romname)
473 {
474 string romnametmp = get_base_name(asmname);
475 if (file_exists(romnametmp+".sfc")) romname=romnametmp+".sfc";
476 else if (file_exists(romnametmp+".smc")) romname=romnametmp+".smc";
477 else romname=romnametmp+".sfc";
478 }
479
2/8
✗ Branch 0 not taken.
✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 118 times.
236 else if (!strchr(romname, '.') && !file_exists(romname))
480 {
481 if (file_exists(romname+".sfc")) romname+=".sfc";
482 else if (file_exists(romname+".smc")) romname+=".smc";
483 }
484
3/4
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 235 times.
236 if (!file_exists(romname))
485 {
486
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 FileHandleType f = open_file(romname, FileOpenMode_Write);
487
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (f == InvalidFileHandle)
488 {
489 asar_throw_error(pass, error_type_fatal, error_id_create_rom_failed);
490 }
491
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 close_file(f);
492 }
493
2/4
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 236 times.
236 if (!openrom(romname, false))
494 {
495 asar_throw_error(pass, error_type_null, openromerror);
496 pause(err);
497 return 1;
498 }
499 //check if the ROM title and checksum looks sane
500
3/4
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 178 times.
✓ Branch 2 taken 58 times.
✗ Branch 3 not taken.
236 if (romlen>=32768 && !ignoretitleerrors)
501 {
502
1/2
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
58 bool validtitle=setmapper();
503
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if (!validtitle)
504 {
505 string title;
506 for (int i=0;i<21;i++)
507 {
508 unsigned char c=romdata[snestopc(0x00FFC0+i)];
509 if (c==7) c=14;
510 if (c==8) c=27;//to not generate more hard-to-print characters than needed
511 if (c==9) c=26;//random characters are picked in accordance with the charset Windows-1252, but they should be garbage in all charsets
512 if (c=='\r') c=17;
513 if (c=='\n') c=25;
514 if (c=='\0') c=155;
515 title+=(char)c;
516 }
517 if (libcon_interactive)
518 {
519 if (!libcon_question_bool(STR"Warning: The ROM title appears to be \""+title+"\", which looks like garbage. "
520 "Is this your ROM title? (Note that improperly answering \"yes\" will crash your ROM.)", false))
521 {
522 puts("Assembling aborted. snespurify should be able to fix your ROM.");
523 return 1;
524 }
525 }
526 else
527 {
528 puts(STR"Error: The ROM title appears to be \""+title+"\", which looks like garbage. "
529 "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.");
530 pause(err);
531 return 1;
532 }
533 }
534 }
535
536
2/4
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 236 times.
✗ Branch 3 not taken.
354 string stdincludespath = STR dir(argv[0]) + "stdincludes.txt";
537
1/2
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
236 parse_std_includes(stdincludespath, includepaths);
538
539
2/2
✓ Branch 0 taken 472 times.
✓ Branch 1 taken 236 times.
708 for (int i = 0; i < includepaths.count; ++i)
540 {
541
2/4
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 236 times.
✗ Branch 3 not taken.
472 includepath_cstrs.append((const char*)includepaths[i]);
542 }
543
544 236 size_t includepath_count = (size_t)includepath_cstrs.count;
545
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 virtual_filesystem new_filesystem;
546
2/4
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 118 times.
✗ Branch 3 not taken.
236 new_filesystem.initialize(&includepath_cstrs[0], includepath_count);
547 236 filesystem = &new_filesystem;
548
549
2/4
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 236 times.
✗ Branch 3 not taken.
354 string stddefinespath = STR dir(argv[0]) + "stddefines.txt";
550
1/2
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
236 parse_std_defines(stddefinespath);
551
552 236 auto execute_patch = [&]()
553 {
554 try {
555
2/2
✓ Branch 0 taken 688 times.
✓ Branch 1 taken 226 times.
914 for (pass=0;pass<3;pass++)
556 {
557 //pass 1: find which bank all labels are in, for label optimizations
558 // freespaces are listed as above 0xFFFFFF, to find if it's in the ROM or if it's dynamic
559 //pass 2: find where exactly all labels are
560 //pass 3: assemble it all
561
1/2
✓ Branch 0 taken 688 times.
✗ Branch 1 not taken.
688 initstuff();
562
2/2
✓ Branch 0 taken 678 times.
✓ Branch 1 taken 10 times.
688 assemblefile(asmname);
563 // RPG Hacker: Necessary, because finishpass() can throws warning and errors.
564
2/4
✓ Branch 0 taken 678 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 339 times.
✗ Branch 3 not taken.
1017 callstack_push cs_push(callstack_entry_type::FILE, filesystem->create_absolute_path(nullptr, asmname));
565
1/2
✓ Branch 0 taken 678 times.
✗ Branch 1 not taken.
678 finishpass();
566 678 }
567 113 return true;
568
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 } catch(errfatal&) {
569 5 return false;
570 10 }
571 236 };
572 #if defined(RUN_VIA_FIBER)
573
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 run_as_fiber(execute_patch);
574 #elif defined(RUN_VIA_THREAD)
575
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 run_as_thread(execute_patch);
576 #else
577 execute_patch();
578 #endif
579
580
1/2
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
236 closecachedfiles(); // this needs the vfs so do it before destroying it
581
1/2
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
236 new_filesystem.destroy();
582 236 filesystem = nullptr;
583
584
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
236 if (werror && warned) asar_throw_error(pass, error_type_null, error_id_werror);
585
3/4
✓ Branch 0 taken 226 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 226 times.
✗ Branch 3 not taken.
236 if (checksum_fix_enabled) fixchecksum();
586 //if (pcpos>romlen) romlen=pcpos;
587
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 166 times.
236 if (errored)
588 {
589
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 if (errnum==0)
590 asar_throw_error(pass, error_type_null, error_id_phantom_error);
591
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.");
592
1/2
✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
70 closerom(false);
593
1/2
✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
70 reseteverything();
594
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
70 pause(err);
595 70 return 1;
596 }
597
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 152 times.
166 if (warned)
598 {
599
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (libcon_interactive)
600 {
601 if (!libcon_question_bool("One or more warnings were detected while assembling the patch. "
602 "Do you want insert the patch anyways? (Default: yes)", true))
603 {
604 puts("ROM left unchanged.");
605 closerom(false);
606 reseteverything();
607 return 1;
608 }
609 }
610 else
611 {
612
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
14 if (verbose) puts("Assembling completed, but one or more warnings were detected.");
613
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
14 pause(warn);
614 }
615 }
616 else
617 {
618
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.");
619
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 152 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
152 pause(yes);
620 }
621
1/2
✓ Branch 0 taken 166 times.
✗ Branch 1 not taken.
166 unsigned int romCrc = closerom();
622
3/4
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 83 times.
166 if (symbols)
623 {
624 if (!symfilename) symfilename = get_base_name(romname)+".sym";
625 string contents = create_symbols_file(symbols, romCrc).convert_line_endings_to_native();
626
627 FileHandleType symfile = open_file(symfilename, FileOpenMode_Write);
628
629 if (symfile == InvalidFileHandle)
630 {
631 puts(STR"Failed to create symbols file: \""+symfilename+"\".");
632 pause(err);
633 return 1;
634 }
635 else
636 {
637 write_file(symfile, (const char*)contents, (uint32_t)contents.length());
638 close_file(symfile);
639 }
640 }
641
1/2
✓ Branch 0 taken 166 times.
✗ Branch 1 not taken.
166 reseteverything();
642
22/22
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 35 times.
✓ Branch 2 taken 83 times.
✓ Branch 3 taken 35 times.
✓ Branch 4 taken 83 times.
✓ Branch 5 taken 35 times.
✓ Branch 6 taken 83 times.
✓ Branch 7 taken 35 times.
✓ Branch 8 taken 83 times.
✓ Branch 9 taken 35 times.
✓ Branch 10 taken 83 times.
✓ Branch 11 taken 35 times.
✓ Branch 12 taken 83 times.
✓ Branch 13 taken 35 times.
✓ Branch 14 taken 83 times.
✓ Branch 15 taken 35 times.
✓ Branch 16 taken 83 times.
✓ Branch 17 taken 35 times.
✓ Branch 18 taken 83 times.
✓ Branch 19 taken 35 times.
✓ Branch 20 taken 83 times.
✓ Branch 21 taken 35 times.
621 }
643 catch(errfatal&)
644 {
645 puts("A fatal error was detected while assembling the patch. Assembling aborted. Your ROM has not been modified.");
646 closerom(false);
647 reseteverything();
648 pause(err);
649 return 1;
650 }
651 166 return 0;
652 118 }
653