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