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