Home | History | Annotate | Download | only in Common
      1 // CommandLineParser.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #include "CommandLineParser.h"
      6 
      7 static bool IsString1PrefixedByString2_NoCase(const wchar_t *u, const char *a)
      8 {
      9   for (;;)
     10   {
     11     char c = *a;
     12     if (c == 0)
     13       return true;
     14     if ((unsigned char)MyCharLower_Ascii(c) != MyCharLower_Ascii(*u))
     15       return false;
     16     a++;
     17     u++;
     18   }
     19 }
     20 
     21 namespace NCommandLineParser {
     22 
     23 bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2)
     24 {
     25   dest1.Empty();
     26   dest2.Empty();
     27   bool quoteMode = false;
     28   unsigned i;
     29   for (i = 0; i < src.Len(); i++)
     30   {
     31     wchar_t c = src[i];
     32     if ((c == L' ' || c == L'\t') && !quoteMode)
     33     {
     34       dest2 = src.Ptr(i + 1);
     35       return i != 0;
     36     }
     37     if (c == L'\"')
     38       quoteMode = !quoteMode;
     39     else
     40       dest1 += c;
     41   }
     42   return i != 0;
     43 }
     44 
     45 void SplitCommandLine(const UString &s, UStringVector &parts)
     46 {
     47   UString sTemp = s;
     48   sTemp.Trim();
     49   parts.Clear();
     50   for (;;)
     51   {
     52     UString s1, s2;
     53     if (SplitCommandLine(sTemp, s1, s2))
     54       parts.Add(s1);
     55     if (s2.IsEmpty())
     56       break;
     57     sTemp = s2;
     58   }
     59 }
     60 
     61 
     62 static const char *kStopSwitchParsing = "--";
     63 
     64 static bool inline IsItSwitchChar(wchar_t c)
     65 {
     66   return (c == '-');
     67 }
     68 
     69 CParser::CParser(unsigned numSwitches):
     70   _numSwitches(numSwitches),
     71   _switches(0)
     72 {
     73   _switches = new CSwitchResult[numSwitches];
     74 }
     75 
     76 CParser::~CParser()
     77 {
     78   delete []_switches;
     79 }
     80 
     81 
     82 // if (s) contains switch then function updates switch structures
     83 // out: true, if (s) is a switch
     84 bool CParser::ParseString(const UString &s, const CSwitchForm *switchForms)
     85 {
     86   if (s.IsEmpty() || !IsItSwitchChar(s[0]))
     87     return false;
     88 
     89   unsigned pos = 1;
     90   unsigned switchIndex = 0;
     91   int maxLen = -1;
     92 
     93   for (unsigned i = 0; i < _numSwitches; i++)
     94   {
     95     const char *key = switchForms[i].Key;
     96     unsigned switchLen = MyStringLen(key);
     97     if ((int)switchLen <= maxLen || pos + switchLen > s.Len())
     98       continue;
     99     if (IsString1PrefixedByString2_NoCase((const wchar_t *)s + pos, key))
    100     {
    101       switchIndex = i;
    102       maxLen = switchLen;
    103     }
    104   }
    105 
    106   if (maxLen < 0)
    107   {
    108     ErrorMessage = "Unknown switch:";
    109     return false;
    110   }
    111 
    112   pos += maxLen;
    113 
    114   CSwitchResult &sw = _switches[switchIndex];
    115   const CSwitchForm &form = switchForms[switchIndex];
    116 
    117   if (!form.Multi && sw.ThereIs)
    118   {
    119     ErrorMessage = "Multiple instances for switch:";
    120     return false;
    121   }
    122 
    123   sw.ThereIs = true;
    124 
    125   int rem = s.Len() - pos;
    126   if (rem < form.MinLen)
    127   {
    128     ErrorMessage = "Too short switch:";
    129     return false;
    130   }
    131 
    132   sw.WithMinus = false;
    133   sw.PostCharIndex = -1;
    134 
    135   switch (form.Type)
    136   {
    137     case NSwitchType::kMinus:
    138       if (rem == 1)
    139       {
    140         sw.WithMinus = (s[pos] == '-');
    141         if (sw.WithMinus)
    142           return true;
    143         ErrorMessage = "Incorrect switch postfix:";
    144         return false;
    145       }
    146       break;
    147 
    148     case NSwitchType::kChar:
    149       if (rem == 1)
    150       {
    151         wchar_t c = s[pos];
    152         if (c <= 0x7F)
    153         {
    154           sw.PostCharIndex = FindCharPosInString(form.PostCharSet, (char)c);
    155           if (sw.PostCharIndex >= 0)
    156             return true;
    157         }
    158         ErrorMessage = "Incorrect switch postfix:";
    159         return false;
    160       }
    161       break;
    162 
    163     case NSwitchType::kString:
    164       sw.PostStrings.Add((const wchar_t *)s + pos);
    165       return true;
    166   }
    167 
    168   if (pos != s.Len())
    169   {
    170     ErrorMessage = "Too long switch:";
    171     return false;
    172   }
    173   return true;
    174 }
    175 
    176 bool CParser::ParseStrings(const CSwitchForm *switchForms, const UStringVector &commandStrings)
    177 {
    178   ErrorLine.Empty();
    179   bool stopSwitch = false;
    180   FOR_VECTOR (i, commandStrings)
    181   {
    182     const UString &s = commandStrings[i];
    183     if (!stopSwitch)
    184     {
    185       if (s.IsEqualTo(kStopSwitchParsing))
    186       {
    187         stopSwitch = true;
    188         continue;
    189       }
    190       if (!s.IsEmpty() && IsItSwitchChar(s[0]))
    191       {
    192         if (ParseString(s, switchForms))
    193           continue;
    194         ErrorLine = s;
    195         return false;
    196       }
    197     }
    198     NonSwitchStrings.Add(s);
    199   }
    200   return true;
    201 }
    202 
    203 }
    204