LCOV - code coverage report
Current view: top level - asar - interface-cli.cpp (source / functions) Coverage Total Hit
Test: asar build #66 Lines: 59.4 % 293 174
Test Date: 2024-01-16 02:45:19 Functions: 100.0 % 9 9
Branches: 36.2 % 362 131

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

Generated by: LCOV version 2.0-1