xref: /aosp_15_r20/external/lzma/CPP/Common/CommandLineParser.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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