"Fossies" - the Fresh Open Source Software Archive

Member "unrar/cmddata.cpp" (4 May 2022, 27701 Bytes) of package /linux/misc/unrarsrc-6.1.7.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "cmddata.cpp" see the Fossies "Dox" file reference documentation.

    1 #include "rar.hpp"
    2 
    3 #include "cmdfilter.cpp"
    4 #include "cmdmix.cpp"
    5 
    6 CommandData::CommandData()
    7 {
    8   Init();
    9 }
   10 
   11 
   12 void CommandData::Init()
   13 {
   14   RAROptions::Init();
   15 
   16   *Command=0;
   17   *ArcName=0;
   18   FileLists=false;
   19   NoMoreSwitches=false;
   20 
   21   ListMode=RCLM_AUTO;
   22 
   23   BareOutput=false;
   24 
   25 
   26   FileArgs.Reset();
   27   ExclArgs.Reset();
   28   InclArgs.Reset();
   29   StoreArgs.Reset();
   30   ArcNames.Reset();
   31   NextVolSizes.Reset();
   32 }
   33 
   34 
   35 // Return the pointer to next position in the string and store dynamically
   36 // allocated command line parameter in Par.
   37 static const wchar *AllocCmdParam(const wchar *CmdLine,wchar **Par)
   38 {
   39   const wchar *NextCmd=GetCmdParam(CmdLine,NULL,0);
   40   if (NextCmd==NULL)
   41     return NULL;
   42   size_t ParSize=NextCmd-CmdLine+2; // Parameter size including the trailing zero.
   43   *Par=(wchar *)malloc(ParSize*sizeof(wchar));
   44   if (*Par==NULL)
   45     return NULL;
   46   return GetCmdParam(CmdLine,*Par,ParSize);
   47 }
   48 
   49 
   50 #if !defined(SFX_MODULE)
   51 void CommandData::ParseCommandLine(bool Preprocess,int argc, char *argv[])
   52 {
   53   *Command=0;
   54   NoMoreSwitches=false;
   55 #ifdef CUSTOM_CMDLINE_PARSER
   56   // In Windows we may prefer to implement our own command line parser
   57   // to avoid replacing \" by " in standard parser. Such replacing corrupts
   58   // destination paths like "dest path\" in extraction commands.
   59   const wchar *CmdLine=GetCommandLine();
   60 
   61   wchar *Par;
   62   for (bool FirstParam=true;;FirstParam=false)
   63   {
   64     if ((CmdLine=AllocCmdParam(CmdLine,&Par))==NULL)
   65       break;
   66     if (!FirstParam) // First parameter is the executable name.
   67       if (Preprocess)
   68         PreprocessArg(Par);
   69       else
   70         ParseArg(Par);
   71     free(Par);
   72   }
   73 #else
   74   Array<wchar> Arg;
   75   for (int I=1;I<argc;I++)
   76   {
   77     Arg.Alloc(strlen(argv[I])+1);
   78     CharToWide(argv[I],&Arg[0],Arg.Size());
   79     if (Preprocess)
   80       PreprocessArg(&Arg[0]);
   81     else
   82       ParseArg(&Arg[0]);
   83   }
   84 #endif
   85   if (!Preprocess)
   86     ParseDone();
   87 }
   88 #endif
   89 
   90 
   91 #if !defined(SFX_MODULE)
   92 void CommandData::ParseArg(wchar *Arg)
   93 {
   94   if (IsSwitch(*Arg) && !NoMoreSwitches)
   95     if (Arg[1]=='-' && Arg[2]==0)
   96       NoMoreSwitches=true;
   97     else
   98       ProcessSwitch(Arg+1);
   99   else
  100     if (*Command==0)
  101     {
  102       wcsncpyz(Command,Arg,ASIZE(Command));
  103 
  104 
  105       *Command=toupperw(*Command);
  106       // 'I' and 'S' commands can contain case sensitive strings after
  107       // the first character, so we must not modify their case.
  108       // 'S' can contain SFX name, which case is important in Unix.
  109       if (*Command!='I' && *Command!='S')
  110         wcsupper(Command);
  111       if (*Command=='P') // Enforce -idq for print command.
  112       {
  113         MsgStream=MSG_ERRONLY;
  114         SetConsoleMsgStream(MSG_ERRONLY);
  115       }
  116     }
  117     else
  118       if (*ArcName==0)
  119         wcsncpyz(ArcName,Arg,ASIZE(ArcName));
  120       else
  121       {
  122         // Check if last character is the path separator.
  123         size_t Length=wcslen(Arg);
  124         wchar EndChar=Length==0 ? 0:Arg[Length-1];
  125         bool EndSeparator=IsDriveDiv(EndChar) || IsPathDiv(EndChar);
  126 
  127         wchar CmdChar=toupperw(*Command);
  128         bool Add=wcschr(L"AFUM",CmdChar)!=NULL;
  129         bool Extract=CmdChar=='X' || CmdChar=='E';
  130         bool Repair=CmdChar=='R' && Command[1]==0;
  131         if (EndSeparator && !Add)
  132           wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
  133         else
  134           if ((Add || CmdChar=='T') && (*Arg!='@' || ListMode==RCLM_REJECT_LISTS))
  135             FileArgs.AddString(Arg);
  136           else
  137           {
  138             FindData FileData;
  139             bool Found=FindFile::FastFind(Arg,&FileData);
  140             if ((!Found || ListMode==RCLM_ACCEPT_LISTS) && 
  141                 ListMode!=RCLM_REJECT_LISTS && *Arg=='@' && !IsWildcard(Arg+1))
  142             {
  143               FileLists=true;
  144 
  145               ReadTextFile(Arg+1,&FileArgs,false,true,FilelistCharset,true,true,true);
  146 
  147             }
  148             else // We use 'destpath\' when extracting and reparing.
  149               if (Found && FileData.IsDir && (Extract || Repair) && *ExtrPath==0)
  150               {
  151                 wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
  152                 AddEndSlash(ExtrPath,ASIZE(ExtrPath));
  153               }
  154               else
  155                 FileArgs.AddString(Arg);
  156           }
  157       }
  158 }
  159 #endif
  160 
  161 
  162 void CommandData::ParseDone()
  163 {
  164   if (FileArgs.ItemsCount()==0 && !FileLists)
  165     FileArgs.AddString(MASKALL);
  166   wchar CmdChar=toupperw(Command[0]);
  167   bool Extract=CmdChar=='X' || CmdChar=='E' || CmdChar=='P';
  168   if (Test && Extract)
  169     Test=false;        // Switch '-t' is senseless for 'X', 'E', 'P' commands.
  170 
  171   // Suppress the copyright message and final end of line for 'lb' and 'vb'.
  172   if ((CmdChar=='L' || CmdChar=='V') && Command[1]=='B')
  173     BareOutput=true;
  174 }
  175 
  176 
  177 #if !defined(SFX_MODULE)
  178 void CommandData::ParseEnvVar()
  179 {
  180   char *EnvStr=getenv("RAR");
  181   if (EnvStr!=NULL)
  182   {
  183     Array<wchar> EnvStrW(strlen(EnvStr)+1);
  184     CharToWide(EnvStr,&EnvStrW[0],EnvStrW.Size());
  185     ProcessSwitchesString(&EnvStrW[0]);
  186   }
  187 }
  188 #endif
  189 
  190 
  191 
  192 #if !defined(SFX_MODULE)
  193 // Preprocess those parameters, which must be processed before the rest of
  194 // command line. Return 'false' to stop further processing.
  195 void CommandData::PreprocessArg(const wchar *Arg)
  196 {
  197   if (IsSwitch(Arg[0]) && !NoMoreSwitches)
  198   {
  199     Arg++;
  200     if (Arg[0]=='-' && Arg[1]==0) // Switch "--".
  201       NoMoreSwitches=true;
  202     if (wcsicomp(Arg,L"cfg-")==0)
  203       ConfigDisabled=true;
  204     if (wcsnicomp(Arg,L"ilog",4)==0)
  205     {
  206       // Ensure that correct log file name is already set
  207       // if we need to report an error when processing the command line.
  208       ProcessSwitch(Arg);
  209       InitLogOptions(LogName,ErrlogCharset);
  210     }
  211     if (wcsnicomp(Arg,L"sc",2)==0)
  212     {
  213       // Process -sc before reading any file lists.
  214       ProcessSwitch(Arg);
  215       if (*LogName!=0)
  216         InitLogOptions(LogName,ErrlogCharset);
  217     }
  218   }
  219   else
  220     if (*Command==0)
  221       wcsncpy(Command,Arg,ASIZE(Command)); // Need for rar.ini.
  222 }
  223 #endif
  224 
  225 
  226 #if !defined(SFX_MODULE)
  227 void CommandData::ReadConfig()
  228 {
  229   StringList List;
  230   if (ReadTextFile(DefConfigName,&List,true))
  231   {
  232     wchar *Str;
  233     while ((Str=List.GetString())!=NULL)
  234     {
  235       while (IsSpace(*Str))
  236         Str++;
  237       if (wcsnicomp(Str,L"switches=",9)==0)
  238         ProcessSwitchesString(Str+9);
  239       if (*Command!=0)
  240       {
  241         wchar Cmd[16];
  242         wcsncpyz(Cmd,Command,ASIZE(Cmd));
  243         wchar C0=toupperw(Cmd[0]);
  244         wchar C1=toupperw(Cmd[1]);
  245         if (C0=='I' || C0=='L' || C0=='M' || C0=='S' || C0=='V')
  246           Cmd[1]=0;
  247         if (C0=='R' && (C1=='R' || C1=='V'))
  248           Cmd[2]=0;
  249         wchar SwName[16+ASIZE(Cmd)];
  250         swprintf(SwName,ASIZE(SwName),L"switches_%ls=",Cmd);
  251         size_t Length=wcslen(SwName);
  252         if (wcsnicomp(Str,SwName,Length)==0)
  253           ProcessSwitchesString(Str+Length);
  254       }
  255     }
  256   }
  257 }
  258 #endif
  259 
  260 
  261 #if !defined(SFX_MODULE)
  262 void CommandData::ProcessSwitchesString(const wchar *Str)
  263 {
  264   wchar *Par;
  265   while ((Str=AllocCmdParam(Str,&Par))!=NULL)
  266   {
  267     if (IsSwitch(*Par))
  268       ProcessSwitch(Par+1);
  269     free(Par);
  270   }
  271 }
  272 #endif
  273 
  274 
  275 #if !defined(SFX_MODULE)
  276 void CommandData::ProcessSwitch(const wchar *Switch)
  277 {
  278 
  279   switch(toupperw(Switch[0]))
  280   {
  281     case '@':
  282       ListMode=Switch[1]=='+' ? RCLM_ACCEPT_LISTS:RCLM_REJECT_LISTS;
  283       break;
  284     case 'A':
  285       switch(toupperw(Switch[1]))
  286       {
  287         case 'C':
  288           ClearArc=true;
  289           break;
  290         case 'D':
  291           if (Switch[2]==0)
  292             AppendArcNameToPath=APPENDARCNAME_DESTPATH;
  293           else
  294             if (Switch[2]=='1')
  295               AppendArcNameToPath=APPENDARCNAME_OWNSUBDIR;
  296             else
  297               if (Switch[2]=='2')
  298                 AppendArcNameToPath=APPENDARCNAME_OWNDIR;
  299           break;
  300 #ifndef SFX_MODULE
  301         case 'G':
  302           if (Switch[2]=='-' && Switch[3]==0)
  303             GenerateArcName=0;
  304           else
  305             if (toupperw(Switch[2])=='F')
  306               wcsncpyz(DefGenerateMask,Switch+3,ASIZE(DefGenerateMask));
  307             else
  308             {
  309               GenerateArcName=true;
  310               wcsncpyz(GenerateMask,Switch+2,ASIZE(GenerateMask));
  311             }
  312           break;
  313 #endif
  314         case 'I':
  315           IgnoreGeneralAttr=true;
  316           break;
  317         case 'N': // Reserved for archive name.
  318           break;
  319         case 'O':
  320           AddArcOnly=true;
  321           break;
  322         case 'P':
  323           wcsncpyz(ArcPath,Switch+2,ASIZE(ArcPath));
  324           break;
  325         case 'S':
  326           SyncFiles=true;
  327           break;
  328         default:
  329           BadSwitch(Switch);
  330           break;
  331       }
  332       break;
  333     case 'C':
  334       if (Switch[2]==0)
  335         switch(toupperw(Switch[1]))
  336         {
  337           case '-':
  338             DisableComment=true;
  339             break;
  340           case 'U':
  341             ConvertNames=NAMES_UPPERCASE;
  342             break;
  343           case 'L':
  344             ConvertNames=NAMES_LOWERCASE;
  345             break;
  346         }
  347       break;
  348     case 'D':
  349       if (Switch[2]==0)
  350         switch(toupperw(Switch[1]))
  351         {
  352           case 'S':
  353             DisableSortSolid=true;
  354             break;
  355           case 'H':
  356             OpenShared=true;
  357             break;
  358           case 'F':
  359             DeleteFiles=true;
  360             break;
  361         }
  362       break;
  363     case 'E':
  364       switch(toupperw(Switch[1]))
  365       {
  366         case 'P':
  367           switch(Switch[2])
  368           {
  369             case 0:
  370               ExclPath=EXCL_SKIPWHOLEPATH;
  371               break;
  372             case '1':
  373               ExclPath=EXCL_BASEPATH;
  374               break;
  375             case '2':
  376               ExclPath=EXCL_SAVEFULLPATH;
  377               break;
  378             case '3':
  379               ExclPath=EXCL_ABSPATH;
  380               break;
  381             case '4':
  382               wcsncpyz(ExclArcPath,Switch+3,ASIZE(ExclArcPath));
  383               break;
  384           }
  385           break;
  386         default:
  387           if (Switch[1]=='+')
  388           {
  389             InclFileAttr|=GetExclAttr(Switch+2,InclDir);
  390             InclAttrSet=true;
  391           }
  392           else
  393             ExclFileAttr|=GetExclAttr(Switch+1,ExclDir);
  394           break;
  395       }
  396       break;
  397     case 'F':
  398       if (Switch[1]==0)
  399         FreshFiles=true;
  400       else
  401         BadSwitch(Switch);
  402       break;
  403     case 'H':
  404       switch (toupperw(Switch[1]))
  405       {
  406         case 'P':
  407           EncryptHeaders=true;
  408           if (Switch[2]!=0)
  409           {
  410             if (wcslen(Switch+2)>=MAXPASSWORD)
  411               uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1);
  412             Password.Set(Switch+2);
  413             cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0]));
  414           }
  415           else
  416             if (!Password.IsSet())
  417             {
  418               uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password);
  419               eprintf(L"\n");
  420             }
  421           break;
  422         default :
  423           BadSwitch(Switch);
  424           break;
  425       }
  426       break;
  427     case 'I':
  428       if (wcsnicomp(Switch+1,L"LOG",3)==0)
  429       {
  430         wcsncpyz(LogName,Switch[4]!=0 ? Switch+4:DefLogName,ASIZE(LogName));
  431         break;
  432       }
  433       if (wcsnicomp(Switch+1,L"SND",3)==0)
  434       {
  435         Sound=Switch[4]=='-' ? SOUND_NOTIFY_OFF : SOUND_NOTIFY_ON;
  436         break;
  437       }
  438       if (wcsicomp(Switch+1,L"ERR")==0)
  439       {
  440         MsgStream=MSG_STDERR;
  441         // Set it immediately when parsing the command line, so it also
  442         // affects messages issued while parsing the command line.
  443         SetConsoleMsgStream(MSG_STDERR);
  444         break;
  445       }
  446       if (wcsnicomp(Switch+1,L"EML",3)==0)
  447       {
  448         wcsncpyz(EmailTo,Switch[4]!=0 ? Switch+4:L"@",ASIZE(EmailTo));
  449         break;
  450       }
  451       if (wcsicomp(Switch+1,L"M")==0) // For compatibility with pre-WinRAR 6.0 -im syntax. Replaced with -idv.
  452       {
  453         VerboseOutput=true;
  454         break;
  455       }
  456       if (wcsicomp(Switch+1,L"NUL")==0)
  457       {
  458         MsgStream=MSG_NULL;
  459         SetConsoleMsgStream(MSG_NULL);
  460         break;
  461       }
  462       if (toupperw(Switch[1])=='D')
  463       {
  464         for (uint I=2;Switch[I]!=0;I++)
  465           switch(toupperw(Switch[I]))
  466           {
  467             case 'Q':
  468               MsgStream=MSG_ERRONLY;
  469               SetConsoleMsgStream(MSG_ERRONLY);
  470               break;
  471             case 'C':
  472               DisableCopyright=true;
  473               break;
  474             case 'D':
  475               DisableDone=true;
  476               break;
  477             case 'P':
  478               DisablePercentage=true;
  479               break;
  480             case 'N':
  481               DisableNames=true;
  482               break;
  483             case 'V':
  484               VerboseOutput=true;
  485               break;
  486           }
  487         break;
  488       }
  489       if (wcsnicomp(Switch+1,L"OFF",3)==0)
  490       {
  491         switch(Switch[4])
  492         {
  493           case 0:
  494           case '1':
  495             Shutdown=POWERMODE_OFF;
  496             break;
  497           case '2':
  498             Shutdown=POWERMODE_HIBERNATE;
  499             break;
  500           case '3':
  501             Shutdown=POWERMODE_SLEEP;
  502             break;
  503           case '4':
  504             Shutdown=POWERMODE_RESTART;
  505             break;
  506         }
  507         break;
  508       }
  509       if (wcsicomp(Switch+1,L"VER")==0)
  510       {
  511         PrintVersion=true;
  512         break;
  513       }
  514       break;
  515     case 'K':
  516       switch(toupperw(Switch[1]))
  517       {
  518         case 'B':
  519           KeepBroken=true;
  520           break;
  521         case 0:
  522           Lock=true;
  523           break;
  524       }
  525       break;
  526     case 'M':
  527       switch(toupperw(Switch[1]))
  528       {
  529         case 'C':
  530           {
  531             const wchar *Str=Switch+2;
  532             if (*Str=='-')
  533               for (uint I=0;I<ASIZE(FilterModes);I++)
  534                 FilterModes[I].State=FILTER_DISABLE;
  535             else
  536               while (*Str!=0)
  537               {
  538                 int Param1=0,Param2=0;
  539                 FilterState State=FILTER_AUTO;
  540                 FilterType Type=FILTER_NONE;
  541                 if (IsDigit(*Str))
  542                 {
  543                   Param1=atoiw(Str);
  544                   while (IsDigit(*Str))
  545                     Str++;
  546                 }
  547                 if (*Str==':' && IsDigit(Str[1]))
  548                 {
  549                   Param2=atoiw(++Str);
  550                   while (IsDigit(*Str))
  551                     Str++;
  552                 }
  553                 switch(toupperw(*(Str++)))
  554                 {
  555                   case 'T': Type=FILTER_PPM;         break;
  556                   case 'E': Type=FILTER_E8;          break;
  557                   case 'D': Type=FILTER_DELTA;       break;
  558                   case 'A': Type=FILTER_AUDIO;       break;
  559                   case 'C': Type=FILTER_RGB;         break;
  560                   case 'R': Type=FILTER_ARM;         break;
  561                 }
  562                 if (*Str=='+' || *Str=='-')
  563                   State=*(Str++)=='+' ? FILTER_FORCE:FILTER_DISABLE;
  564                 FilterModes[Type].State=State;
  565                 FilterModes[Type].Param1=Param1;
  566                 FilterModes[Type].Param2=Param2;
  567               }
  568             }
  569           break;
  570         case 'M':
  571           break;
  572         case 'D':
  573           break;
  574         case 'E':
  575           if (toupperw(Switch[2])=='S' && Switch[3]==0)
  576             SkipEncrypted=true;
  577           break;
  578         case 'S':
  579           {
  580             wchar StoreNames[1024];
  581             wcsncpyz(StoreNames,(Switch[2]==0 ? DefaultStoreList:Switch+2),ASIZE(StoreNames));
  582             wchar *Names=StoreNames;
  583             while (*Names!=0)
  584             {
  585               wchar *End=wcschr(Names,';');
  586               if (End!=NULL)
  587                 *End=0;
  588               if (*Names=='.')
  589                 Names++;
  590               wchar Mask[NM];
  591               if (wcspbrk(Names,L"*?.")==NULL)
  592                 swprintf(Mask,ASIZE(Mask),L"*.%ls",Names);
  593               else
  594                 wcsncpyz(Mask,Names,ASIZE(Mask));
  595               StoreArgs.AddString(Mask);
  596               if (End==NULL)
  597                 break;
  598               Names=End+1;
  599             }
  600           }
  601           break;
  602 #ifdef RAR_SMP
  603         case 'T':
  604           Threads=atoiw(Switch+2);
  605           if (Threads>MaxPoolThreads || Threads<1)
  606             BadSwitch(Switch);
  607           else
  608           {
  609           }
  610           break;
  611 #endif
  612         default:
  613           Method=Switch[1]-'0';
  614           if (Method>5 || Method<0)
  615             BadSwitch(Switch);
  616           break;
  617       }
  618       break;
  619     case 'N':
  620     case 'X':
  621       if (Switch[1]!=0)
  622       {
  623         StringList *Args=toupperw(Switch[0])=='N' ? &InclArgs:&ExclArgs;
  624         if (Switch[1]=='@' && !IsWildcard(Switch))
  625           ReadTextFile(Switch+2,Args,false,true,FilelistCharset,true,true,true);
  626         else
  627           Args->AddString(Switch+1);
  628       }
  629       break;
  630     case 'O':
  631       switch(toupperw(Switch[1]))
  632       {
  633         case '+':
  634           Overwrite=OVERWRITE_ALL;
  635           break;
  636         case '-':
  637           Overwrite=OVERWRITE_NONE;
  638           break;
  639         case 0:
  640           Overwrite=OVERWRITE_FORCE_ASK;
  641           break;
  642 #ifdef _WIN_ALL
  643         case 'C':
  644           SetCompressedAttr=true;
  645           break;
  646 #endif
  647         case 'H':
  648           SaveHardLinks=true;
  649           break;
  650 
  651 
  652 #ifdef SAVE_LINKS
  653         case 'L':
  654           SaveSymLinks=true;
  655           if (toupperw(Switch[2])=='A')
  656             AbsoluteLinks=true;
  657           break;
  658 #endif
  659 #ifdef _WIN_ALL
  660         case 'N':
  661           if (toupperw(Switch[2])=='I')
  662             AllowIncompatNames=true;
  663           break;
  664 #endif
  665         case 'P':
  666           wcsncpyz(ExtrPath,Switch+2,ASIZE(ExtrPath));
  667           AddEndSlash(ExtrPath,ASIZE(ExtrPath));
  668           break;
  669         case 'R':
  670           Overwrite=OVERWRITE_AUTORENAME;
  671           break;
  672 #ifdef _WIN_ALL
  673         case 'S':
  674           SaveStreams=true;
  675           break;
  676 #endif
  677         case 'W':
  678           ProcessOwners=true;
  679           break;
  680         default :
  681           BadSwitch(Switch);
  682           break;
  683       }
  684       break;
  685     case 'P':
  686       if (Switch[1]==0)
  687       {
  688         uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password);
  689         eprintf(L"\n");
  690       }
  691       else
  692       {
  693         if (wcslen(Switch+1)>=MAXPASSWORD)
  694           uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1);
  695         Password.Set(Switch+1);
  696         cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0]));
  697       }
  698       break;
  699 #ifndef SFX_MODULE
  700     case 'Q':
  701       if (toupperw(Switch[1])=='O')
  702         switch(toupperw(Switch[2]))
  703         {
  704           case 0:
  705             QOpenMode=QOPEN_AUTO;
  706             break;
  707           case '-':
  708             QOpenMode=QOPEN_NONE;
  709             break;
  710           case '+':
  711             QOpenMode=QOPEN_ALWAYS;
  712             break;
  713           default:
  714             BadSwitch(Switch);
  715             break;
  716         }
  717       else
  718         BadSwitch(Switch);
  719       break;
  720 #endif
  721     case 'R':
  722       switch(toupperw(Switch[1]))
  723       {
  724         case 0:
  725           Recurse=RECURSE_ALWAYS;
  726           break;
  727         case '-':
  728           Recurse=RECURSE_DISABLE;
  729           break;
  730         case '0':
  731           Recurse=RECURSE_WILDCARDS;
  732           break;
  733         case 'I':
  734           {
  735             Priority=atoiw(Switch+2);
  736             if (Priority<0 || Priority>15)
  737               BadSwitch(Switch);
  738             const wchar *ChPtr=wcschr(Switch+2,':');
  739             if (ChPtr!=NULL)
  740             {
  741               SleepTime=atoiw(ChPtr+1);
  742               if (SleepTime>1000)
  743                 BadSwitch(Switch);
  744               InitSystemOptions(SleepTime);
  745             }
  746             SetPriority(Priority);
  747           }
  748           break;
  749       }
  750       break;
  751     case 'S':
  752       if (IsDigit(Switch[1]))
  753       {
  754         Solid|=SOLID_COUNT;
  755         SolidCount=atoiw(&Switch[1]);
  756       }
  757       else
  758         switch(toupperw(Switch[1]))
  759         {
  760           case 0:
  761             Solid|=SOLID_NORMAL;
  762             break;
  763           case '-':
  764             Solid=SOLID_NONE;
  765             break;
  766           case 'E':
  767             Solid|=SOLID_FILEEXT;
  768             break;
  769           case 'V':
  770             Solid|=Switch[2]=='-' ? SOLID_VOLUME_DEPENDENT:SOLID_VOLUME_INDEPENDENT;
  771             break;
  772           case 'D':
  773             Solid|=SOLID_VOLUME_DEPENDENT;
  774             break;
  775           case 'I':
  776             ProhibitConsoleInput();
  777             wcsncpyz(UseStdin,Switch[2] ? Switch+2:L"stdin",ASIZE(UseStdin));
  778             break;
  779           case 'L':
  780             if (IsDigit(Switch[2]))
  781               FileSizeLess=atoilw(Switch+2);
  782             break;
  783           case 'M':
  784             if (IsDigit(Switch[2]))
  785               FileSizeMore=atoilw(Switch+2);
  786             break;
  787           case 'C':
  788             {
  789               bool AlreadyBad=false; // Avoid reporting "bad switch" several times.
  790 
  791               RAR_CHARSET rch=RCH_DEFAULT;
  792               switch(toupperw(Switch[2]))
  793               {
  794                 case 'A':
  795                   rch=RCH_ANSI;
  796                   break;
  797                 case 'O':
  798                   rch=RCH_OEM;
  799                   break;
  800                 case 'U':
  801                   rch=RCH_UNICODE;
  802                   break;
  803                 case 'F':
  804                   rch=RCH_UTF8;
  805                   break;
  806                 default :
  807                   BadSwitch(Switch);
  808                   AlreadyBad=true;
  809                   break;
  810               };
  811               if (!AlreadyBad)
  812                 if (Switch[3]==0)
  813                   CommentCharset=FilelistCharset=ErrlogCharset=RedirectCharset=rch;
  814                 else
  815                   for (uint I=3;Switch[I]!=0 && !AlreadyBad;I++)
  816                     switch(toupperw(Switch[I]))
  817                     {
  818                       case 'C':
  819                         CommentCharset=rch;
  820                         break;
  821                       case 'L':
  822                         FilelistCharset=rch;
  823                         break;
  824                       case 'R':
  825                         RedirectCharset=rch;
  826                         break;
  827                       default:
  828                         BadSwitch(Switch);
  829                         AlreadyBad=true;
  830                         break;
  831                     }
  832               // Set it immediately when parsing the command line, so it also
  833               // affects messages issued while parsing the command line.
  834               SetConsoleRedirectCharset(RedirectCharset);
  835             }
  836             break;
  837 
  838         }
  839       break;
  840     case 'T':
  841       switch(toupperw(Switch[1]))
  842       {
  843         case 'K':
  844           ArcTime=ARCTIME_KEEP;
  845           break;
  846         case 'L':
  847           ArcTime=ARCTIME_LATEST;
  848           break;
  849         case 'O':
  850           SetTimeFilters(Switch+2,true,true);
  851           break;
  852         case 'N':
  853           SetTimeFilters(Switch+2,false,true);
  854           break;
  855         case 'B':
  856           SetTimeFilters(Switch+2,true,false);
  857           break;
  858         case 'A':
  859           SetTimeFilters(Switch+2,false,false);
  860           break;
  861         case 'S':
  862           SetStoreTimeMode(Switch+2);
  863           break;
  864         case '-':
  865           Test=false;
  866           break;
  867         case 0:
  868           Test=true;
  869           break;
  870         default:
  871           BadSwitch(Switch);
  872           break;
  873       }
  874       break;
  875     case 'U':
  876       if (Switch[1]==0)
  877         UpdateFiles=true;
  878       else
  879         BadSwitch(Switch);
  880       break;
  881     case 'V':
  882       switch(toupperw(Switch[1]))
  883       {
  884         case 'P':
  885           VolumePause=true;
  886           break;
  887         case 'E':
  888           if (toupperw(Switch[2])=='R')
  889             VersionControl=atoiw(Switch+3)+1;
  890           break;
  891         case '-':
  892           VolSize=0;
  893           break;
  894         default:
  895           VolSize=VOLSIZE_AUTO; // UnRAR -v switch for list command.
  896           break;
  897       }
  898       break;
  899     case 'W':
  900       wcsncpyz(TempPath,Switch+1,ASIZE(TempPath));
  901       AddEndSlash(TempPath,ASIZE(TempPath));
  902       break;
  903     case 'Y':
  904       AllYes=true;
  905       break;
  906     case 'Z':
  907       if (Switch[1]==0)
  908       {
  909         // If comment file is not specified, we read data from stdin.
  910         wcsncpyz(CommentFile,L"stdin",ASIZE(CommentFile));
  911       }
  912       else
  913         wcsncpyz(CommentFile,Switch+1,ASIZE(CommentFile));
  914       break;
  915     case '?' :
  916       OutHelp(RARX_SUCCESS);
  917       break;
  918     default :
  919       BadSwitch(Switch);
  920       break;
  921   }
  922 }
  923 #endif
  924 
  925 
  926 #if !defined(SFX_MODULE)
  927 void CommandData::BadSwitch(const wchar *Switch)
  928 {
  929   mprintf(St(MUnknownOption),Switch);
  930   ErrHandler.Exit(RARX_USERERROR);
  931 }
  932 #endif
  933 
  934 
  935 void CommandData::ProcessCommand()
  936 {
  937 #ifndef SFX_MODULE
  938 
  939   const wchar *SingleCharCommands=L"FUADPXETK";
  940   if (Command[0]!=0 && Command[1]!=0 && wcschr(SingleCharCommands,Command[0])!=NULL || *ArcName==0)
  941     OutHelp(*Command==0 ? RARX_SUCCESS:RARX_USERERROR); // Return 'success' for 'rar' without parameters.
  942 
  943   const wchar *ArcExt=GetExt(ArcName);
  944 #ifdef _UNIX
  945   if (ArcExt==NULL && (!FileExist(ArcName) || IsDir(GetFileAttr(ArcName))))
  946     wcsncatz(ArcName,L".rar",ASIZE(ArcName));
  947 #else
  948   if (ArcExt==NULL)
  949     wcsncatz(ArcName,L".rar",ASIZE(ArcName));
  950 #endif
  951   // Treat arcname.part1 as arcname.part1.rar.
  952   if (ArcExt!=NULL && wcsnicomp(ArcExt,L".part",5)==0 && IsDigit(ArcExt[5]) &&
  953       !FileExist(ArcName))
  954   {
  955     wchar Name[NM];
  956     wcsncpyz(Name,ArcName,ASIZE(Name));
  957     wcsncatz(Name,L".rar",ASIZE(Name));
  958     if (FileExist(Name))
  959       wcsncpyz(ArcName,Name,ASIZE(ArcName));
  960   }
  961 
  962   if (wcschr(L"AFUMD",*Command)==NULL && *UseStdin==0)
  963   {
  964     if (GenerateArcName)
  965     {
  966       const wchar *Mask=*GenerateMask!=0 ? GenerateMask:DefGenerateMask;
  967       GenerateArchiveName(ArcName,ASIZE(ArcName),Mask,false);
  968     }
  969 
  970     StringList ArcMasks;
  971     ArcMasks.AddString(ArcName);
  972     ScanTree Scan(&ArcMasks,Recurse,SaveSymLinks,SCAN_SKIPDIRS);
  973     FindData FindData;
  974     while (Scan.GetNext(&FindData)==SCAN_SUCCESS)
  975       AddArcName(FindData.Name);
  976   }
  977   else
  978     AddArcName(ArcName);
  979 #endif
  980 
  981   switch(Command[0])
  982   {
  983     case 'P':
  984     case 'X':
  985     case 'E':
  986     case 'T':
  987       {
  988         CmdExtract Extract(this);
  989         Extract.DoExtract();
  990       }
  991       break;
  992 #ifndef SILENT
  993     case 'V':
  994     case 'L':
  995       ListArchive(this);
  996       break;
  997     default:
  998       OutHelp(RARX_USERERROR);
  999 #endif
 1000   }
 1001   if (!BareOutput)
 1002     mprintf(L"\n");
 1003 }
 1004 
 1005 
 1006 void CommandData::AddArcName(const wchar *Name)
 1007 {
 1008   ArcNames.AddString(Name);
 1009 }
 1010 
 1011 
 1012 bool CommandData::GetArcName(wchar *Name,int MaxSize)
 1013 {
 1014   return ArcNames.GetString(Name,MaxSize);
 1015 }
 1016 
 1017 
 1018 bool CommandData::IsSwitch(int Ch)
 1019 {
 1020 #if defined(_WIN_ALL) || defined(_EMX)
 1021   return Ch=='-' || Ch=='/';
 1022 #else
 1023   return Ch=='-';
 1024 #endif
 1025 }
 1026 
 1027 
 1028 #ifndef SFX_MODULE
 1029 uint CommandData::GetExclAttr(const wchar *Str,bool &Dir)
 1030 {
 1031   if (IsDigit(*Str))
 1032     return wcstol(Str,NULL,0);
 1033 
 1034   uint Attr=0;
 1035   while (*Str!=0)
 1036   {
 1037     switch(toupperw(*Str))
 1038     {
 1039       case 'D':
 1040         Dir=true;
 1041         break;
 1042 #ifdef _UNIX
 1043       case 'V':
 1044         Attr|=S_IFCHR;
 1045         break;
 1046 #elif defined(_WIN_ALL) || defined(_EMX)
 1047       case 'R':
 1048         Attr|=0x1;
 1049         break;
 1050       case 'H':
 1051         Attr|=0x2;
 1052         break;
 1053       case 'S':
 1054         Attr|=0x4;
 1055         break;
 1056       case 'A':
 1057         Attr|=0x20;
 1058         break;
 1059 #endif
 1060     }
 1061     Str++;
 1062   }
 1063   return Attr;
 1064 }
 1065 #endif
 1066 
 1067 
 1068 
 1069 
 1070 #ifndef SFX_MODULE
 1071 bool CommandData::CheckWinSize()
 1072 {
 1073   // Define 0x100000000 as macro to avoid troubles with older compilers.
 1074   const uint64 MaxDictSize=INT32TO64(1,0);
 1075   // Limit the dictionary size to 4 GB.
 1076   for (uint64 I=0x10000;I<=MaxDictSize;I*=2)
 1077     if (WinSize==I)
 1078       return true;
 1079   WinSize=0x400000;
 1080   return false;
 1081 }
 1082 #endif
 1083 
 1084 
 1085 #ifndef SFX_MODULE
 1086 void CommandData::ReportWrongSwitches(RARFORMAT Format)
 1087 {
 1088   if (Format==RARFMT15)
 1089   {
 1090     if (HashType!=HASH_CRC32)
 1091       uiMsg(UIERROR_INCOMPATSWITCH,L"-ht",4);
 1092 #ifdef _WIN_ALL
 1093     if (SaveSymLinks)
 1094       uiMsg(UIERROR_INCOMPATSWITCH,L"-ol",4);
 1095 #endif
 1096     if (SaveHardLinks)
 1097       uiMsg(UIERROR_INCOMPATSWITCH,L"-oh",4);
 1098 
 1099 #ifdef _WIN_ALL
 1100     // Do not report a wrong dictionary size here, because we are not sure
 1101     // yet about archive format. We can switch to RAR5 mode later
 1102     // if we update RAR5 archive.
 1103 
 1104 
 1105 #endif
 1106     if (QOpenMode!=QOPEN_AUTO)
 1107       uiMsg(UIERROR_INCOMPATSWITCH,L"-qo",4);
 1108   }
 1109   if (Format==RARFMT50)
 1110   {
 1111   }
 1112 }
 1113 #endif