1// CommandLineParser.cs 2 3using System; 4using System.Collections; 5 6namespace SevenZip.CommandLineParser 7{ 8 public enum SwitchType 9 { 10 Simple, 11 PostMinus, 12 LimitedPostString, 13 UnLimitedPostString, 14 PostChar 15 } 16 17 public class SwitchForm 18 { 19 public string IDString; 20 public SwitchType Type; 21 public bool Multi; 22 public int MinLen; 23 public int MaxLen; 24 public string PostCharSet; 25 26 public SwitchForm(string idString, SwitchType type, bool multi, 27 int minLen, int maxLen, string postCharSet) 28 { 29 IDString = idString; 30 Type = type; 31 Multi = multi; 32 MinLen = minLen; 33 MaxLen = maxLen; 34 PostCharSet = postCharSet; 35 } 36 public SwitchForm(string idString, SwitchType type, bool multi, int minLen): 37 this(idString, type, multi, minLen, 0, "") 38 { 39 } 40 public SwitchForm(string idString, SwitchType type, bool multi): 41 this(idString, type, multi, 0) 42 { 43 } 44 } 45 46 public class SwitchResult 47 { 48 public bool ThereIs; 49 public bool WithMinus; 50 public ArrayList PostStrings = new ArrayList(); 51 public int PostCharIndex; 52 public SwitchResult() 53 { 54 ThereIs = false; 55 } 56 } 57 58 public class Parser 59 { 60 public ArrayList NonSwitchStrings = new ArrayList(); 61 SwitchResult[] _switches; 62 63 public Parser(int numSwitches) 64 { 65 _switches = new SwitchResult[numSwitches]; 66 for (int i = 0; i < numSwitches; i++) 67 _switches[i] = new SwitchResult(); 68 } 69 70 bool ParseString(string srcString, SwitchForm[] switchForms) 71 { 72 int len = srcString.Length; 73 if (len == 0) 74 return false; 75 int pos = 0; 76 if (!IsItSwitchChar(srcString[pos])) 77 return false; 78 while (pos < len) 79 { 80 if (IsItSwitchChar(srcString[pos])) 81 pos++; 82 const int kNoLen = -1; 83 int matchedSwitchIndex = 0; 84 int maxLen = kNoLen; 85 for (int switchIndex = 0; switchIndex < _switches.Length; switchIndex++) 86 { 87 int switchLen = switchForms[switchIndex].IDString.Length; 88 if (switchLen <= maxLen || pos + switchLen > len) 89 continue; 90 if (String.Compare(switchForms[switchIndex].IDString, 0, 91 srcString, pos, switchLen, true) == 0) 92 { 93 matchedSwitchIndex = switchIndex; 94 maxLen = switchLen; 95 } 96 } 97 if (maxLen == kNoLen) 98 throw new Exception("maxLen == kNoLen"); 99 SwitchResult matchedSwitch = _switches[matchedSwitchIndex]; 100 SwitchForm switchForm = switchForms[matchedSwitchIndex]; 101 if ((!switchForm.Multi) && matchedSwitch.ThereIs) 102 throw new Exception("switch must be single"); 103 matchedSwitch.ThereIs = true; 104 pos += maxLen; 105 int tailSize = len - pos; 106 SwitchType type = switchForm.Type; 107 switch (type) 108 { 109 case SwitchType.PostMinus: 110 { 111 if (tailSize == 0) 112 matchedSwitch.WithMinus = false; 113 else 114 { 115 matchedSwitch.WithMinus = (srcString[pos] == kSwitchMinus); 116 if (matchedSwitch.WithMinus) 117 pos++; 118 } 119 break; 120 } 121 case SwitchType.PostChar: 122 { 123 if (tailSize < switchForm.MinLen) 124 throw new Exception("switch is not full"); 125 string charSet = switchForm.PostCharSet; 126 const int kEmptyCharValue = -1; 127 if (tailSize == 0) 128 matchedSwitch.PostCharIndex = kEmptyCharValue; 129 else 130 { 131 int index = charSet.IndexOf(srcString[pos]); 132 if (index < 0) 133 matchedSwitch.PostCharIndex = kEmptyCharValue; 134 else 135 { 136 matchedSwitch.PostCharIndex = index; 137 pos++; 138 } 139 } 140 break; 141 } 142 case SwitchType.LimitedPostString: 143 case SwitchType.UnLimitedPostString: 144 { 145 int minLen = switchForm.MinLen; 146 if (tailSize < minLen) 147 throw new Exception("switch is not full"); 148 if (type == SwitchType.UnLimitedPostString) 149 { 150 matchedSwitch.PostStrings.Add(srcString.Substring(pos)); 151 return true; 152 } 153 String stringSwitch = srcString.Substring(pos, minLen); 154 pos += minLen; 155 for (int i = minLen; i < switchForm.MaxLen && pos < len; i++, pos++) 156 { 157 char c = srcString[pos]; 158 if (IsItSwitchChar(c)) 159 break; 160 stringSwitch += c; 161 } 162 matchedSwitch.PostStrings.Add(stringSwitch); 163 break; 164 } 165 } 166 } 167 return true; 168 169 } 170 171 public void ParseStrings(SwitchForm[] switchForms, string[] commandStrings) 172 { 173 int numCommandStrings = commandStrings.Length; 174 bool stopSwitch = false; 175 for (int i = 0; i < numCommandStrings; i++) 176 { 177 string s = commandStrings[i]; 178 if (stopSwitch) 179 NonSwitchStrings.Add(s); 180 else 181 if (s == kStopSwitchParsing) 182 stopSwitch = true; 183 else 184 if (!ParseString(s, switchForms)) 185 NonSwitchStrings.Add(s); 186 } 187 } 188 189 public SwitchResult this[int index] { get { return _switches[index]; } } 190 191 public static int ParseCommand(CommandForm[] commandForms, string commandString, 192 out string postString) 193 { 194 for (int i = 0; i < commandForms.Length; i++) 195 { 196 string id = commandForms[i].IDString; 197 if (commandForms[i].PostStringMode) 198 { 199 if (commandString.IndexOf(id) == 0) 200 { 201 postString = commandString.Substring(id.Length); 202 return i; 203 } 204 } 205 else 206 if (commandString == id) 207 { 208 postString = ""; 209 return i; 210 } 211 } 212 postString = ""; 213 return -1; 214 } 215 216 static bool ParseSubCharsCommand(int numForms, CommandSubCharsSet[] forms, 217 string commandString, ArrayList indices) 218 { 219 indices.Clear(); 220 int numUsedChars = 0; 221 for (int i = 0; i < numForms; i++) 222 { 223 CommandSubCharsSet charsSet = forms[i]; 224 int currentIndex = -1; 225 int len = charsSet.Chars.Length; 226 for (int j = 0; j < len; j++) 227 { 228 char c = charsSet.Chars[j]; 229 int newIndex = commandString.IndexOf(c); 230 if (newIndex >= 0) 231 { 232 if (currentIndex >= 0) 233 return false; 234 if (commandString.IndexOf(c, newIndex + 1) >= 0) 235 return false; 236 currentIndex = j; 237 numUsedChars++; 238 } 239 } 240 if (currentIndex == -1 && !charsSet.EmptyAllowed) 241 return false; 242 indices.Add(currentIndex); 243 } 244 return (numUsedChars == commandString.Length); 245 } 246 const char kSwitchID1 = '-'; 247 const char kSwitchID2 = '/'; 248 249 const char kSwitchMinus = '-'; 250 const string kStopSwitchParsing = "--"; 251 252 static bool IsItSwitchChar(char c) 253 { 254 return (c == kSwitchID1 || c == kSwitchID2); 255 } 256 } 257 258 public class CommandForm 259 { 260 public string IDString = ""; 261 public bool PostStringMode = false; 262 public CommandForm(string idString, bool postStringMode) 263 { 264 IDString = idString; 265 PostStringMode = postStringMode; 266 } 267 } 268 269 class CommandSubCharsSet 270 { 271 public string Chars = ""; 272 public bool EmptyAllowed = false; 273 } 274} 275