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