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  int i;
15  for (i = 0; i < src.Length(); i++)
16  {
17    wchar_t c = src[i];
18    if (c == L' ' && !quoteMode)
19    {
20      dest2 = src.Mid(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 wchar_t kSwitchID1 = '-';
49// static const wchar_t kSwitchID2 = '/';
50
51static const wchar_t kSwitchMinus = '-';
52static const wchar_t *kStopSwitchParsing = L"--";
53
54static bool IsItSwitchChar(wchar_t c)
55{
56  return (c == kSwitchID1 /*|| c == kSwitchID2 */);
57}
58
59CParser::CParser(int numSwitches):
60  _numSwitches(numSwitches)
61{
62  _switches = new CSwitchResult[_numSwitches];
63}
64
65CParser::~CParser()
66{
67  delete []_switches;
68}
69
70void CParser::ParseStrings(const CSwitchForm *switchForms,
71  const UStringVector &commandStrings)
72{
73  int numCommandStrings = commandStrings.Size();
74  bool stopSwitch = false;
75  for (int i = 0; i < numCommandStrings; i++)
76  {
77    const UString &s = commandStrings[i];
78    if (stopSwitch)
79      NonSwitchStrings.Add(s);
80    else
81      if (s == kStopSwitchParsing)
82        stopSwitch = true;
83      else
84        if (!ParseString(s, switchForms))
85          NonSwitchStrings.Add(s);
86  }
87}
88
89// if string contains switch then function updates switch structures
90// out: (string is a switch)
91bool CParser::ParseString(const UString &s, const CSwitchForm *switchForms)
92{
93  int len = s.Length();
94  if (len == 0)
95    return false;
96  int pos = 0;
97  if (!IsItSwitchChar(s[pos]))
98    return false;
99  while (pos < len)
100  {
101    if (IsItSwitchChar(s[pos]))
102      pos++;
103    const int kNoLen = -1;
104    int matchedSwitchIndex = 0; // GCC Warning
105    int maxLen = kNoLen;
106    for (int switchIndex = 0; switchIndex < _numSwitches; switchIndex++)
107    {
108      int switchLen = MyStringLen(switchForms[switchIndex].IDString);
109      if (switchLen <= maxLen || pos + switchLen > len)
110        continue;
111
112      UString temp = s + pos;
113      temp = temp.Left(switchLen);
114      if (temp.CompareNoCase(switchForms[switchIndex].IDString) == 0)
115      // if (_strnicmp(switchForms[switchIndex].IDString, LPCSTR(s) + pos, switchLen) == 0)
116      {
117        matchedSwitchIndex = switchIndex;
118        maxLen = switchLen;
119      }
120    }
121    if (maxLen == kNoLen)
122      throw "maxLen == kNoLen";
123    CSwitchResult &matchedSwitch = _switches[matchedSwitchIndex];
124    const CSwitchForm &switchForm = switchForms[matchedSwitchIndex];
125    if ((!switchForm.Multi) && matchedSwitch.ThereIs)
126      throw "switch must be single";
127    matchedSwitch.ThereIs = true;
128    pos += maxLen;
129    int tailSize = len - pos;
130    NSwitchType::EEnum type = switchForm.Type;
131    switch(type)
132    {
133      case NSwitchType::kPostMinus:
134        {
135          if (tailSize == 0)
136            matchedSwitch.WithMinus = false;
137          else
138          {
139            matchedSwitch.WithMinus = (s[pos] == kSwitchMinus);
140            if (matchedSwitch.WithMinus)
141              pos++;
142          }
143          break;
144        }
145      case NSwitchType::kPostChar:
146        {
147          if (tailSize < switchForm.MinLen)
148            throw "switch is not full";
149          UString set = switchForm.PostCharSet;
150          const int kEmptyCharValue = -1;
151          if (tailSize == 0)
152            matchedSwitch.PostCharIndex = kEmptyCharValue;
153          else
154          {
155            int index = set.Find(s[pos]);
156            if (index < 0)
157              matchedSwitch.PostCharIndex =  kEmptyCharValue;
158            else
159            {
160              matchedSwitch.PostCharIndex = index;
161              pos++;
162            }
163          }
164          break;
165        }
166      case NSwitchType::kLimitedPostString:
167      case NSwitchType::kUnLimitedPostString:
168        {
169          int minLen = switchForm.MinLen;
170          if (tailSize < minLen)
171            throw "switch is not full";
172          if (type == NSwitchType::kUnLimitedPostString)
173          {
174            matchedSwitch.PostStrings.Add(s.Mid(pos));
175            return true;
176          }
177          int maxLen = switchForm.MaxLen;
178          UString stringSwitch = s.Mid(pos, minLen);
179          pos += minLen;
180          for (int i = minLen; i < maxLen && pos < len; i++, pos++)
181          {
182            wchar_t c = s[pos];
183            if (IsItSwitchChar(c))
184              break;
185            stringSwitch += c;
186          }
187          matchedSwitch.PostStrings.Add(stringSwitch);
188          break;
189        }
190      case NSwitchType::kSimple:
191          break;
192    }
193  }
194  return true;
195}
196
197const CSwitchResult& CParser::operator[](size_t index) const
198{
199  return _switches[index];
200}
201
202/////////////////////////////////
203// Command parsing procedures
204
205int ParseCommand(int numCommandForms, const CCommandForm *commandForms,
206    const UString &commandString, UString &postString)
207{
208  for (int i = 0; i < numCommandForms; i++)
209  {
210    const UString id = commandForms[i].IDString;
211    if (commandForms[i].PostStringMode)
212    {
213      if (commandString.Find(id) == 0)
214      {
215        postString = commandString.Mid(id.Length());
216        return i;
217      }
218    }
219    else
220      if (commandString == id)
221      {
222        postString.Empty();
223        return i;
224      }
225  }
226  return -1;
227}
228
229}
230