Home | History | Annotate | Download | only in Common
      1 // CommandLineParser.cs
      2 
      3 using System;
      4 using System.Collections;
      5 
      6 namespace 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