#include "rar.hpp"

CommandData::CommandData()
{
  FileArgs=ExclArgs=StoreArgs=ArcNames=NULL;
  Init();
}


CommandData::~CommandData()
{
  Close();
}


void CommandData::Init()
{
  Close();

  *Command=0;
  *ArcName=0;
  *ArcNameW=0;
  FileLists=false;
  NoMoreSwitches=false;
  TimeConverted=false;

  FileArgs=new StringList;
  ExclArgs=new StringList;
  StoreArgs=new StringList;
  ArcNames=new StringList;
}


void CommandData::Close()
{
  delete FileArgs;
  delete ExclArgs;
  delete StoreArgs;
  delete ArcNames;
  FileArgs=ExclArgs=StoreArgs=ArcNames=NULL;
}


#ifndef SFX_MODULE
void CommandData::ParseArg(char *Arg)
{
  if (IsSwitch(*Arg) && !NoMoreSwitches)
    if (Arg[1]=='-')
      NoMoreSwitches=true;
    else
      ProcessSwitch(&Arg[1]);
  else
    if (*Command==0)
    {
      strncpy(Command,Arg,sizeof(Command));
      if (toupper(*Command)=='S')
      {
        const char *SFXName=Command[1] ? Command+1:DefSFXName;
        if (PointToName(SFXName)!=SFXName || FileExist(SFXName))
          strcpy(SFXModule,SFXName);
        else
          GetConfigName(SFXName,SFXModule);
      }
#ifndef GUI
      strupper(Command);
#endif
    }
    else
      if (*ArcName==0)
        strncpy(ArcName,Arg,sizeof(ArcName));
      else
      {
        int Length=strlen(Arg);
        char EndChar=Arg[Length-1];
        char CmdChar=toupper(*Command);
        bool Add=strchr("AFUM",CmdChar)!=NULL;
        bool Extract=CmdChar=='X' || CmdChar=='E';
        if ((IsDriveDiv(EndChar) || IsPathDiv(EndChar)) && !Add)
          strcpy(ExtrPath,Arg);
        else
          if ((Add || CmdChar=='T') && *Arg!='@')
            FileArgs->AddString(Arg);
          else
          {
            struct FindData FileData;
            int Found=FindFile::FastFind(Arg,NULL,&FileData);
            if (!Found && *Arg=='@' && !IsWildcard(Arg))
            {
              ReadTextFile(Arg+1,FileArgs,false,true,true,true,true);
              FileLists=true;
            }
            else
              if (Found && FileData.IsDir && Extract && *ExtrPath==0)
              {
                strcpy(ExtrPath,Arg);
                AddEndSlash(ExtrPath);
              }
              else
                FileArgs->AddString(Arg);
          }
      }
}
#endif


void CommandData::ParseDone()
{
  if (FileArgs->ItemsCount()==0 && !FileLists)
    FileArgs->AddString(MASKALL);
  char CmdChar=toupper(*Command);
  bool Extract=CmdChar=='X' || CmdChar=='E';
  if (Test && Extract)
    Test=false;
}


#ifndef SFX_MODULE
void CommandData::ParseEnvVar()
{
  char *EnvStr=getenv("RAR");
  if (EnvStr!=NULL)
    ProcessSwitchesString(EnvStr);
}
#endif


#if !defined(GUI) && !defined(SFX_MODULE)
bool CommandData::IsConfigEnabled(int argc,char *argv[])
{
  for (int I=1;I<argc;I++)
    if (IsSwitch(*argv[I]) && stricomp(&argv[I][1],"cfg-")==0)
      return(false);
  return(true);
}
#endif


#if !defined(GUI) && !defined(SFX_MODULE)
void CommandData::ReadConfig(int argc,char *argv[])
{
  StringList List;
  if (ReadTextFile(DefConfigName,&List,true))
  {
    char *Str;
    while ((Str=List.GetString())!=NULL)
      if (strnicomp(Str,"switches=",9)==0)
        ProcessSwitchesString(Str+9);
  }
}
#endif


#ifndef SFX_MODULE
void CommandData::ProcessSwitchesString(char *Str)
{
  while (*Str)
  {
    while (!IsSwitch(*Str) && *Str!=0)
      Str++;
    if (*Str==0)
      break;
    char *Next=Str;
    while (!(Next[0]==' ' && IsSwitch(Next[1])) && *Next!=0)
      Next++;
    char NextChar=*Next;
    *Next=0;
    ProcessSwitch(Str+1);
    *Next=NextChar;
    Str=Next;
  }
}
#endif


#ifndef SFX_MODULE
void CommandData::ProcessSwitch(char *Switch)
{

  switch(toupper(Switch[0]))
  {
    case 'I':
      if (strnicomp(&Switch[1],"LOG",3)==0)
      {
        strncpy(LogName,Switch[4] ? Switch+4:DefLogName,sizeof(LogName));
        break;
      }
      if (stricomp(&Switch[1],"SND")==0)
      {
        Sound=true;
        break;
      }
      if (stricomp(&Switch[1],"ERR")==0)
      {
        MsgStream=MSG_STDERR;
        break;
      }
      if (strnicomp(&Switch[1],"EML",3)==0)
      {
        strncpy(EmailTo,Switch[4] ? Switch+4:"@",sizeof(EmailTo));
        EmailTo[sizeof(EmailTo)-1]=0;
        break;
      }
      if (stricomp(&Switch[1],"NUL")==0)
      {
        MsgStream=MSG_NULL;
        break;
      }
      if (stricomp(&Switch[1],"DP")==0)
      {
        DisablePercentage=true;
        break;
      }
      break;
    case 'T':
      switch(toupper(Switch[1]))
      {
        case 'K':
          ArcTime=ARCTIME_KEEP;
          break;
        case 'L':
          ArcTime=ARCTIME_LATEST;
          break;
        case 'O':
          FileTimeOlder=TextAgeToSeconds(Switch+2);
          break;
        case 'N':
          FileTimeNewer=TextAgeToSeconds(Switch+2);
          break;
        case 'B':
          FileTimeBefore=IsoTextToDosTime(Switch+2);
          break;
        case 'A':
          FileTimeAfter=IsoTextToDosTime(Switch+2);
          break;
        case 0:
          Test=true;
          break;
        default:
          BadSwitch(Switch);
          break;
      }
      break;
    case 'A':
      switch(toupper(Switch[1]))
      {
        case 'C':
          ClearArc=true;
          break;
        case 'D':
          AppendArcNameToPath=true;
          break;
        case 'G':
          if (Switch[2]=='-' && Switch[3]==0)
            GenerateArcName=0;
          else
          {
            GenerateArcName=true;
            strncpy(GenerateMask,Switch+2,sizeof(GenerateMask));
          }
          break;
        case 'N': //reserved for archive name
          break;
        case 'O':
          AddArcOnly=true;
          break;
        case 'P':
          strcpy(ArcPath,Switch+2);
          break;
        case 'S':
          SyncFiles=true;
          break;
      }
      break;
    case 'D':
      if (Switch[2]==0)
        switch(toupper(Switch[1]))
        {
          case 'S':
            DisableSortSolid=true;
            break;
          case 'H':
            OpenShared=true;
            break;
          case 'F':
            DeleteFiles=true;
            break;
        }
      break;
    case 'O':
      switch(toupper(Switch[1]))
      {
        case '+':
          Overwrite=OVERWRITE_ALL;
          break;
        case '-':
          Overwrite=OVERWRITE_NONE;
          break;
        case 'W':
          ProcessOwners=true;
          break;
#ifdef SAVE_LINKS
        case 'L':
          SaveLinks=true;
          break;
#endif
#ifdef _WIN_32
        case 'S':
          SaveStreams=true;
          break;
#endif
        default :
          BadSwitch(Switch);
          break;
      }
      break;
    case 'R':
      switch(toupper(Switch[1]))
      {
        case 0:
          Recurse=RECURSE_ALWAYS;
          break;
        case '-':
          Recurse=0;
          break;
        case '0':
          Recurse=RECURSE_WILDCARDS;
          break;
        case 'R':
          Recovery=GetRecoverySize(Switch+2,DEFAULT_RECOVERY);
          break;
        case 'V':
          RecVolNumber=GetRecoverySize(Switch+2,DEFAULT_RECVOLUMES);
          break;
        case 'I':
          {
            Priority=atoi(Switch+2);
            char *ChPtr=strchr(Switch+2,':');
            if (ChPtr!=NULL)
              SleepTime=atoi(ChPtr+1);
            SetPriority(Priority);
          }
          break;
      }
      break;
    case 'Y':
      AllYes=true;
      break;
    case 'X':
      if (Switch[1]!=0)
        if (Switch[1]=='@' && !IsWildcard(Switch))
          ReadTextFile(Switch+2,ExclArgs,false,true,true,true,true);
        else
          ExclArgs->AddString(Switch+1);
      break;
    case 'E':
      switch(toupper(Switch[1]))
      {
        case 'P':
          switch(Switch[2])
          {
            case 0:
              ExclPath=EXCL_SKIPWHOLEPATH;
              break;
            case '1':
              ExclPath=EXCL_BASEPATH;
              break;
            case '2':
              ExclPath=EXCL_SAVEFULLPATH;
              break;
          }
          break;
        case 'D':
          ExclEmptyDir=true;
          break;
        case 'E':
          ProcessEA=false;
          break;
        case 'N':
          NoEndBlock=true;
          break;
        default:
          ExclFileAttr=GetExclAttr(&Switch[1]);
          break;
      }
      break;
    case 'P':
      if (Switch[1]==0)
      {
#ifndef GUI
        GetPassword(PASSWORD_GLOBAL,NULL,Password,sizeof(Password));
        eprintf("\n");
#endif
      }
      else
        strncpy(Password,Switch+1,sizeof(Password));
      break;
    case 'H':
      if (toupper(Switch[1])=='P')
      {
        EncryptHeaders=true;
        if (Switch[2]!=0)
          strncpy(Password,Switch+2,sizeof(Password));
        else
          if (*Password==0)
          {
#ifndef GUI
            GetPassword(PASSWORD_GLOBAL,NULL,Password,sizeof(Password));
            eprintf("\n");
#endif
          }
      }
      break;
    case 'Z':
      strncpy(CommentFile,Switch[1]!=0 ? Switch+1:"stdin",sizeof(CommentFile));
      break;
    case 'M':
      switch(toupper(Switch[1]))
      {
        case 'C':
          {
            char *Str=Switch+2;
            if (*Str=='-')
              for (int I=0;I<sizeof(FilterModes)/sizeof(FilterModes[0]);I++)
                FilterModes[I].State=FILTER_DISABLE;
            else
              while (*Str)
              {
                int Param1=0,Param2=0;
                FilterState State=FILTER_AUTO;
                FilterType Type=FILTER_NONE;
                if (isdigit(*Str))
                {
                  Param1=atoi(Str);
                  while (isdigit(*Str))
                    Str++;
                }
                if (*Str==':' && isdigit(Str[1]))
                {
                  Param2=atoi(++Str);
                  while (isdigit(*Str))
                    Str++;
                }
                switch(toupper(*(Str++)))
                {
                  case 'T': Type=FILTER_PPM;         break;
                  case 'E': Type=FILTER_E8;          break;
                  case 'D': Type=FILTER_DELTA;       break;
                  case 'A': Type=FILTER_AUDIO;       break;
                  case 'C': Type=FILTER_RGB;         break;
                  case 'I': Type=FILTER_ITANIUM;     break;
                  case 'L': Type=FILTER_UPCASETOLOW; break;
                }
                if (*Str=='+' || *Str=='-')
                  State=*(Str++)=='+' ? FILTER_FORCE:FILTER_DISABLE;
                FilterModes[Type].State=State;
                FilterModes[Type].Param1=Param1;
                FilterModes[Type].Param2=Param2;
              }
            }
          break;
        case 'M':
          break;
        case 'D':
          {
            if ((WinSize=atoi(&Switch[2]))==0)
              WinSize=0x10000<<(toupper(Switch[2])-'A');
            else
              WinSize*=1024;
            if (!CheckWinSize())
              BadSwitch(Switch);
          }
          break;
        case 'S':
          {
            char *Names=Switch+2,DefNames[512];
            if (*Names==0)
            {
              strcpy(DefNames,DefaultStoreList);
              Names=DefNames;
            }
            while (*Names!=0)
            {
              char *End=strchr(Names,';');
              if (End!=NULL)
                *End=0;
              if (*Names=='.')
                Names++;
              char Mask[NM];
              if (strpbrk(Names,"*?.")==NULL)
                sprintf(Mask,"*.%s",Names);
              else
                strcpy(Mask,Names);
              StoreArgs->AddString(Mask);
              if (End==NULL)
                break;
              Names=End+1;
            }
          }
          break;
        default:
          Method=Switch[1]-'0';
          if (Method>5 || Method<0)
            BadSwitch(Switch);
          break;
      }
      break;
    case 'V':
      switch(toupper(Switch[1]))
      {
#ifdef _WIN_32
        case 'D':
          EraseDisk=true;
          break;
#endif
        case 'N':
          OldNumbering=true;
          break;
        case 'P':
          VolumePause=true;
          break;
        case 'E':
          if (toupper(Switch[2])=='R')
            VersionControl=atoi(Switch+3)+1;
          break;
        case '-':
          VolSize=0;
          break;
        default:
          VolSize=atoil(&Switch[1]);

          if (VolSize==0)
            VolSize=INT64ERR;
          else
            switch (Switch[strlen(Switch)-1])
            {
              case 'f':
              case 'F':
                switch(int64to32(VolSize))
                {
                  case 360:
                    VolSize=362496;
                    break;
                  case 720:
                    VolSize=730112;
                    break;
                  case 1200:
                    VolSize=1213952;
                    break;
                  case 1440:
                    VolSize=1457664;
                    break;
                  case 2880:
                    VolSize=2915328;
                    break;
                }
                break;
              case 'k':
                VolSize*=1024;
                break;
              case 'm':
                VolSize*=1024*1024;
                break;
              case 'M':
                VolSize*=1000*1000;
                break;
              case 'b':
              case 'B':
                break;
              default:
                VolSize*=1000;
                break;
            }
          break;
      }
      break;
    case 'F':
      if (Switch[1]==0)
        FreshFiles=true;
      break;
    case 'U':
      if (Switch[1]==0)
        UpdateFiles=true;
      break;
    case 'W':
      strncpy(TempPath,&Switch[1],sizeof(TempPath)-1);
      AddEndSlash(TempPath);
      break;
    case 'S':
      if (strnicomp(Switch,"SFX",3)==0)
      {
        const char *SFXName=Switch[3] ? Switch+3:DefSFXName;
        if (PointToName(SFXName)!=SFXName || FileExist(SFXName))
          strcpy(SFXModule,SFXName);
        else
          GetConfigName(SFXName,SFXModule);
      }
      if (isdigit(Switch[1]))
      {
        Solid|=SOLID_COUNT;
        SolidCount=atoi(&Switch[1]);
      }
      else
        switch(toupper(Switch[1]))
        {
          case 0:
            Solid|=SOLID_NORMAL;
            break;
          case '-':
            Solid=SOLID_NONE;
            break;
          case 'E':
            Solid|=SOLID_FILEEXT;
            break;
          case 'V':
            Solid|=Switch[2]=='-' ? SOLID_VOLUME_DEPENDENT:SOLID_VOLUME_INDEPENDENT;
            break;
          case 'D':
            Solid|=SOLID_VOLUME_DEPENDENT;
            break;
        }
      break;
    case 'C':
      if (Switch[2]==0)
        switch(toupper(Switch[1]))
        {
          case '-':
            DisableComment=true;
            break;
          case 'U':
            ConvertNames=NAMES_UPPERCASE;
            break;
          case 'L':
            ConvertNames=NAMES_LOWERCASE;
            break;
        }
      break;
    case 'K':
      switch(toupper(Switch[1]))
      {
        case 'B':
          KeepBroken=true;
          break;
        case 0:
          Lock=true;
          break;
      }
      break;
#ifndef GUI
    case '?' :
      OutHelp();
      break;
#endif
    default :
      BadSwitch(Switch);
      break;
  }
}
#endif


#ifndef SFX_MODULE
void CommandData::BadSwitch(char *Switch)
{
  mprintf(St(MUnknownOption),Switch);
  ErrHandler.Exit(USER_ERROR);
}
#endif


#ifndef GUI
void CommandData::OutTitle()
{
#if defined(__GNUC__) && defined(SFX_MODULE)
  mprintf(St(MCopyrightS));
#else
#ifndef SILENT
  static bool TitleShown=false;
  if (TitleShown)
    return;
  TitleShown=true;
  char Version[50];
  int Beta=RARVER_BETA;
  if (Beta!=0)
    sprintf(Version,"%d.%02d %s %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA);
  else
    sprintf(Version,"%d.%02d",RARVER_MAJOR,RARVER_MINOR);
#ifdef UNRAR
  mprintf(St(MUCopyright),Version,RARVER_YEAR);
#else
  mprintf(St(MCopyright),Version,RARVER_YEAR,RARVER_DAY,GetMonthName(RARVER_MONTH-1),RARVER_YEAR);
  char RegName[512];
  strcpy(RegName,Reg.RegName);
#ifdef _WIN_32
  OemToChar(RegName,RegName);
#endif
#endif
#endif
#endif
}
#endif


void CommandData::OutHelp()
{
#if !defined(GUI) && !defined(SILENT)
  OutTitle();
  static MSGID Help[]={
#ifdef SFX_MODULE
    MCHelpCmd,MSHelpCmdE,MSHelpCmdT,MSHelpCmdV
#elif defined(UNRAR)
    MUNRARTitle1,MRARTitle2,MCHelpCmd,MCHelpCmdE,MCHelpCmdL,MCHelpCmdP,
    MCHelpCmdT,MCHelpCmdV,MCHelpCmdX,MCHelpSw,MCHelpSwm,MCHelpSwAC,MCHelpSwAD,
    MCHelpSwAP,MCHelpSwAVm,MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU,
    MCHelpSwDH,MCHelpSwEP,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR,MCHelpSwINUL,
    MCHelpSwKB,MCHelpSwOp,MCHelpSwOm,MCHelpSwOW,MCHelpSwP,MCHelpSwPm,
    MCHelpSwR,MCHelpSwRI,MCHelpSwTA,MCHelpSwTB,MCHelpSwTN,MCHelpSwTO,
    MCHelpSwU,MCHelpSwV,MCHelpSwVER,MCHelpSwVP,MCHelpSwX,MCHelpSwXa,
    MCHelpSwXal,MCHelpSwY
#else
    MRARTitle1,MRARTitle2,MCHelpCmd,MCHelpCmdA,MCHelpCmdC,MCHelpCmdCF,
    MCHelpCmdCW,MCHelpCmdD,MCHelpCmdE,MCHelpCmdF,MCHelpCmdK,MCHelpCmdL,
    MCHelpCmdM,MCHelpCmdP,MCHelpCmdR,MCHelpCmdRC,MCHelpCmdRR,MCHelpCmdRV,
    MCHelpCmdS,MCHelpCmdT,MCHelpCmdU,MCHelpCmdV,MCHelpCmdX,MCHelpSw,
    MCHelpSwm,MCHelpSwAC,MCHelpSwAD,MCHelpSwAG,MCHelpSwAO,MCHelpSwAP,
    MCHelpSwAS,MCHelpSwAV,MCHelpSwAVm,MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,
    MCHelpSwCU,MCHelpSwDF,MCHelpSwDH,MCHelpSwDS,MCHelpSwEa,MCHelpSwED,
    MCHelpSwEE,MCHelpSwEN,MCHelpSwEP,MCHelpSwEP1,MCHelpSwEP2,
    MCHelpSwF,MCHelpSwHP,MCHelpSwIDP,MCHelpSwIEML,MCHelpSwIERR,MCHelpSwILOG,
    MCHelpSwINUL,MCHelpSwISND,MCHelpSwK,MCHelpSwKB,MCHelpSwMn,
    MCHelpSwMC,MCHelpSwMD,MCHelpSwMS,MCHelpSwOp,MCHelpSwOm,MCHelpSwOL,
    MCHelpSwOS,MCHelpSwOW,MCHelpSwP,MCHelpSwPm,MCHelpSwR,MCHelpSwR0,
    MCHelpSwRI,MCHelpSwRR,MCHelpSwRV,MCHelpSwS,MCHelpSwSm,MCHelpSwSFX,
    MCHelpSwT,MCHelpSwTA,MCHelpSwTB,MCHelpSwTK,MCHelpSwTL,MCHelpSwTN,
    MCHelpSwTO,MCHelpSwU,MCHelpSwV,MCHelpSwVn,MCHelpSwVD,MCHelpSwVER,
    MCHelpSwVN,MCHelpSwVP,MCHelpSwW,MCHelpSwX,MCHelpSwXa,MCHelpSwXal,
    MCHelpSwY,MCHelpSwZ
#endif
  };

  for (int I=0;I<sizeof(Help)/sizeof(Help[0]);I++)
  {
#ifndef SFX_MODULE
#ifdef DISABLEAUTODETECT
    if (Help[I]==MCHelpSwV)
      continue;
#endif
#ifndef _WIN_32
    if (Help[I]==MCHelpSwIEML || Help[I]==MCHelpSwVD || Help[I]==MCHelpSwAC ||
        Help[I]==MCHelpSwAO || Help[I]==MCHelpSwDH || Help[I]==MCHelpSwOS)
      continue;
#endif
#if !defined(_UNIX) && !defined(_WIN_32)
    if (Help[I]==MCHelpSwOW)
      continue;
#endif
#ifndef SAVE_LINKS
    if (Help[I]==MCHelpSwOL)
      continue;
#endif
#ifndef ENABLE_CHANGE_PRIORITY
    if (Help[I]==MCHelpSwRI)
      continue;
#endif
#if !defined(_BEOS)
    if (Help[I]==MCHelpSwEE)
    {
#if defined(_EMX) && !defined(_DJGPP)
      if (_osmode != OS2_MODE)
        continue;
#else
      continue;
#endif
    }
#endif
#endif
    mprintf(St(Help[I]));
  }
  mprintf("\n");
  ErrHandler.Exit(USER_ERROR);
#endif
}


bool CommandData::ExclCheck(char *CheckName,bool CheckFullPath)
{
  char *Name=ConvertPath(CheckName,NULL);
  char FullName[NM],*ExclName;
  *FullName=0;
  ExclArgs->Rewind();
  while ((ExclName=ExclArgs->GetString())!=NULL)
#ifndef SFX_MODULE
    if (CheckFullPath && IsFullPath(ExclName))
    {
      if (*FullName==0)
        ConvertNameToFull(CheckName,FullName);
      if (CmpName(ExclName,FullName,MATCH_WILDSUBPATH))
        return(true);
    }
    else
#endif
      if (CmpName(ConvertPath(ExclName,NULL),Name,MATCH_SUBPATH))
        return(true);
  return(false);
}




#ifndef SFX_MODULE
bool CommandData::TimeCheck(uint FileDosTime)
{
  if (FileTimeBefore!=0 && FileDosTime>=FileTimeBefore)
    return(true);
  if (FileTimeAfter!=0 && FileDosTime<=FileTimeAfter)
    return(true);
  if (FileTimeOlder!=0 || FileTimeNewer!=0)
  {
    if (!TimeConverted)
    {
      if (FileTimeOlder!=0)
        FileTimeOlder=SecondsToDosTime(FileTimeOlder);
      if (FileTimeNewer!=0)
        FileTimeNewer=SecondsToDosTime(FileTimeNewer);
      TimeConverted=true;
    }
    if (FileTimeOlder!=0 && FileDosTime>=FileTimeOlder)
      return(true);
    if (FileTimeNewer!=0 && FileDosTime<=FileTimeNewer)
      return(true);
  }
  return(false);
}
#endif


bool CommandData::IsProcessFile(FileHeader &NewLhd,bool *ExactMatch)
{
  if (ExclCheck(NewLhd.FileName,false))
    return(false);
#ifndef SFX_MODULE
  if (TimeCheck(NewLhd.FileTime))
    return(false);
#endif
  char *ArgName;
  wchar *ArgNameW;
  FileArgs->Rewind();
  while (FileArgs->GetString(&ArgName,&ArgNameW))
  {
#ifndef SFX_MODULE
    bool Unicode=(NewLhd.Flags & LHD_UNICODE) || ArgNameW!=NULL;
    if (Unicode)
    {
      wchar NameW[NM],ArgW[NM],*NamePtr=NewLhd.FileNameW;
      if (ArgNameW==NULL)
      {
        CharToWide(ArgName,ArgW);
        ArgNameW=ArgW;
      }
      if ((NewLhd.Flags & LHD_UNICODE)==0)
      {
        CharToWide(NewLhd.FileName,NameW);
        NamePtr=NameW;
      }
      if (CmpName(ArgNameW,NamePtr,MATCH_WILDSUBPATH))
      {
        if (ExactMatch!=NULL)
          *ExactMatch=stricompcw(ArgNameW,NamePtr)==0;
        return(true);
      }
    }
#endif
    if (CmpName(ArgName,NewLhd.FileName,MATCH_WILDSUBPATH))
    {
      if (ExactMatch!=NULL)
        *ExactMatch=stricompc(ArgName,NewLhd.FileName)==0;
      return(true);
    }
  }
  return(false);
}


void CommandData::ProcessCommand()
{
#ifndef SFX_MODULE
  if (Command[1] && strchr("FUADPXETK",*Command)!=NULL || *ArcName==0)
    OutHelp();

#ifdef _UNIX
  if (GetExt(ArcName)==NULL && (!FileExist(ArcName) || IsDir(GetFileAttr(ArcName))))
    strcat(ArcName,".rar");
#else
  if (GetExt(ArcName)==NULL)
    strcat(ArcName,".rar");
#endif

  if (strchr("AFUMD",*Command)==NULL)
  {
    StringList ArcMasks;
    ArcMasks.AddString(ArcName);
    ScanTree Scan(&ArcMasks,Recurse,SaveLinks,SCAN_SKIPDIRS);
    FindData FindData;
    while (Scan.GetNext(&FindData)==SCAN_SUCCESS)
      AddArcName(FindData.Name,FindData.NameW);
  }
  else
    AddArcName(ArcName,NULL);
#endif

  switch(Command[0])
  {
    case 'P':
    case 'X':
    case 'E':
    case 'T':
      {
        CmdExtract Extract;
        Extract.DoExtract(this);
      }
      break;
#if !defined(GUI) && !defined(SILENT)
    case 'V':
    case 'L':
      ListArchive(this);
      break;
    default:
      OutHelp();
#endif
  }
#ifndef GUI
  mprintf("\n");
#endif
}


void CommandData::AddArcName(char *Name,wchar *NameW)
{
  ArcNames->AddString(Name,NameW);
}


bool CommandData::GetArcName(char *Name,wchar *NameW,int MaxSize)
{
  if (!ArcNames->GetString(Name,NameW,NM))
    return(false);
  return(true);
}


bool CommandData::IsSwitch(int Ch)
{
#if defined(_WIN_32) || defined(_EMX)
  return(Ch=='-' || Ch=='/');
#else
  return(Ch=='-');
#endif
}


#ifndef SFX_MODULE
uint CommandData::GetExclAttr(char *Str)
{
#ifdef _UNIX
  return(strtol(Str,NULL,0));
#endif
#if defined(_WIN_32) || defined(_EMX)
  uint Attr;
  if (isdigit(*Str))
    return(strtol(Str,NULL,0));
  else
  {
    for (Attr=0;*Str;Str++)
      switch(toupper(*Str))
      {
        case 'R':
          Attr|=0x1;
          break;
        case 'H':
          Attr|=0x2;
          break;
        case 'S':
          Attr|=0x4;
          break;
        case 'D':
          Attr|=0x10;
          break;
        case 'A':
          Attr|=0x20;
          break;
      }
    return(Attr);
  }
#endif
}
#endif


#ifndef SFX_MODULE
int CommandData::GetRecoverySize(char *Str,int DefSize)
{
  if (*Str=='-')
    return(0);
  if (*Str==0)
    return(DefSize);
  int Size=atoi(Str);
  if (Size<=100 && strpbrk(Str,"%p")!=NULL)
    Size=-Size;
  return(Size);
}
#endif


#ifndef SFX_MODULE
bool CommandData::CheckWinSize()
{
  static int ValidSize[]={
    0x10000,0x20000,0x40000,0x80000,0x100000,0x200000,0x400000
  };
  for (int I=0;I<sizeof(ValidSize)/sizeof(ValidSize[0]);I++)
    if (WinSize==ValidSize[I])
      return(true);
  WinSize=0x400000;
  return(false);
}
#endif
