1 // CommandLineParser.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "CommandLineParser.h"
6 
IsString1PrefixedByString2_NoCase(const wchar_t * u,const char * a)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 
SplitCommandLine(const UString & src,UString & dest1,UString & dest2)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 
SplitCommandLine(const UString & s,UStringVector & parts)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 
IsItSwitchChar(wchar_t c)64 static bool inline IsItSwitchChar(wchar_t c)
65 {
66   return (c == '-');
67 }
68 
CParser(unsigned numSwitches)69 CParser::CParser(unsigned numSwitches):
70   _numSwitches(numSwitches),
71   _switches(0)
72 {
73   _switches = new CSwitchResult[numSwitches];
74 }
75 
~CParser()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
ParseString(const UString & s,const CSwitchForm * switchForms)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 
ParseStrings(const CSwitchForm * switchForms,const UStringVector & commandStrings)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