1// CommandLineParser.cpp
2
3#include "StdAfx.h"
4
5#include "CommandLineParser.h"
6
7static 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
21namespace NCommandLineParser {
22
23bool 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
45void 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
62static const char *kStopSwitchParsing = "--";
63
64static bool inline IsItSwitchChar(wchar_t c)
65{
66  return (c == '-');
67}
68
69CParser::CParser(unsigned numSwitches):
70  _numSwitches(numSwitches),
71  _switches(0)
72{
73  _switches = new CSwitchResult[numSwitches];
74}
75
76CParser::~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
84bool 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
171bool 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