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