1// CommandLineParser.cpp
2
3#include "StdAfx.h"
4
5#include "CommandLineParser.h"
6
7namespace NCommandLineParser {
8
9bool 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
31void 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
48static const char * const kStopSwitchParsing = "--";
49
50static bool inline IsItSwitchChar(wchar_t c)
51{
52  return (c == '-');
53}
54
55CParser::CParser():
56  _switches(NULL),
57  StopSwitchIndex(-1)
58{
59}
60
61CParser::~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
69bool 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 = (int)switchLen;
88    }
89  }
90
91  if (maxLen < 0)
92  {
93    ErrorMessage = "Unknown switch:";
94    return false;
95  }
96
97  pos += (unsigned)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  const unsigned 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
164bool 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 = (int)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