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 (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 != 0)
    139       {
    140         sw.WithMinus = (s[pos] == '-');
    141         if (sw.WithMinus)
    142           pos++;
    143       }
    144       break;
    145 
    146     case NSwitchType::kChar:
    147       if (rem != 0)
    148       {
    149         wchar_t c = s[pos];
    150         if (c <= 0x7F)
    151         {
    152           sw.PostCharIndex = FindCharPosInString(form.PostCharSet, (char)c);
    153           if (sw.PostCharIndex >= 0)
    154             pos++;
    155         }
    156       }
    157       break;
    158 
    159     case NSwitchType::kString:
    160       sw.PostStrings.Add((const wchar_t *)s + pos);
    161       return true;
    162   }
    163   if (pos != s.Len())
    164   {
    165     ErrorMessage = "Too long switch:";
    166     return false;
    167   }
    168   return true;
    169 }
    170 
    171 bool CParser::ParseStrings(const CSwitchForm *switchForms, const UStringVector &commandStrings)
    172 {
    173   ErrorLine.Empty();
    174   bool stopSwitch = false;
    175   FOR_VECTOR (i, commandStrings)
    176   {
    177     const UString &s = commandStrings[i];
    178     if (!stopSwitch)
    179     {
    180       if (s.IsEqualTo(kStopSwitchParsing))
    181       {
    182         stopSwitch = true;
    183         continue;
    184       }
    185       if (!s.IsEmpty() && IsItSwitchChar(s[0]))
    186       {
    187         if (ParseString(s, switchForms))
    188           continue;
    189         ErrorLine = s;
    190         return false;
    191       }
    192     }
    193     NonSwitchStrings.Add(s);
    194   }
    195   return true;
    196 }
    197 
    198 }
    199