/// <summary> /// <para>Class CLAParser provides everything for easy and fast handling of commandline arguments.</para> /// <para>Usage:</para> /// <para>1) Create an instance of CLAParser by calling this constructor.</para> /// <para>2) Define parameters by calling Parameter() as often as needed.</para> /// <para>3) Optionally: Set variables such as AllowAdditionalParameters and ParameterPrefix.</para> /// <para>4) Call Parse(), catch all CmdLineArgumentExceptions, and show those to user.</para> /// <para>5) Call GetUsage() and GetParameterInfo() to create information about using commandline arguments.</para> /// </summary> /// <param name="NamespaceOfResX">Pass the name of the default namespace (usually the namespace of main code file Program.cs)<para>[This is necessary so that CLAParser can find its resource files (CmdLineArgumentParserRes.resx, CmdLineArgumentParserRes.de-DE.resx, ...)]</para></param> public CLAParser(string NamespaceOfResX) { CmdLineArgResourceManager = new ResourceManager(NamespaceOfResX + ".CmdLineArgumentParserRes", this.GetType().Assembly); FoundParameters = new StringDictionary(); WantedParameters = new SortedDictionary<string, ParameterDefintion>(StringComparer.InvariantCultureIgnoreCase); Enumerator = FoundParameters.GetEnumerator(); ParameterPrefix = "/"; AllowAdditionalParameters = false; }
// Uses the enumerator. // NOTE: The foreach statement is the preferred way of enumerating the contents of a collection. public static void PrintKeysAndValues2(StringDictionary myCol) { IEnumerator myEnumerator = myCol.GetEnumerator(); DictionaryEntry de; Console.WriteLine(" KEY VALUE"); while (myEnumerator.MoveNext()) { de = (DictionaryEntry)myEnumerator.Current; Console.WriteLine(" {0,-25} {1}", de.Key, de.Value); } Console.WriteLine(); }
public void Empty () { StringDictionary sd = new StringDictionary (); Assert.AreEqual (0, sd.Count, "Count"); Assert.IsFalse (sd.IsSynchronized, "IsSynchronized"); Assert.AreEqual (0, sd.Keys.Count, "Keys"); Assert.AreEqual (0, sd.Values.Count, "Values"); Assert.IsNotNull (sd.SyncRoot, "SyncRoot"); Assert.IsFalse (sd.ContainsKey ("a"), "ContainsKey"); Assert.IsFalse (sd.ContainsValue ("1"), "ContainsValue"); sd.CopyTo (new DictionaryEntry[0], 0); Assert.IsNotNull (sd.GetEnumerator (), "GetEnumerator"); sd.Remove ("a"); // doesn't exists sd.Clear (); }
public void Test01() { StringDictionary sd; IEnumerator en; DictionaryEntry curr; // Enumerator.Current value // simple string values string[] values = { "a", "aa", "", " ", "text", " spaces", "1", "$%^#", "2222222222222222222222222", System.DateTime.Today.ToString(), Int32.MaxValue.ToString() }; // keys for simple string values string[] keys = { "zero", "one", " ", "", "aa", "1", System.DateTime.Today.ToString(), "$%^#", Int32.MaxValue.ToString(), " spaces", "2222222222222222222222222" }; // [] StringDictionary GetEnumerator() //----------------------------------------------------------------- sd = new StringDictionary(); // [] Enumerator for empty dictionary // en = sd.GetEnumerator(); string type = en.GetType().ToString(); if (type.IndexOf("Enumerator", 0) == 0) { Assert.False(true, string.Format("Error, type is not Enumerator")); } // // MoveNext should return false // bool res = en.MoveNext(); if (res) { Assert.False(true, string.Format("Error, MoveNext returned true")); } // // Attempt to get Current should result in exception // Assert.Throws<InvalidOperationException>(() => { curr = (DictionaryEntry)en.Current; }); // // Filled collection // [] Enumerator for filled dictionary // for (int i = 0; i < values.Length; i++) { sd.Add(keys[i], values[i]); } en = sd.GetEnumerator(); type = en.GetType().ToString(); if (type.IndexOf("Enumerator", 0) == 0) { Assert.False(true, string.Format("Error, type is not Enumerator")); } // // MoveNext should return true // for (int i = 0; i < sd.Count; i++) { res = en.MoveNext(); if (!res) { Assert.False(true, string.Format("Error, MoveNext returned false", i)); } curr = (DictionaryEntry)en.Current; // //enumerator enumerates in different than added order // so we'll check Contains // if (!sd.ContainsValue(curr.Value.ToString())) { Assert.False(true, string.Format("Error, Current dictionary doesn't contain value from enumerator", i)); } if (!sd.ContainsKey(curr.Key.ToString())) { Assert.False(true, string.Format("Error, Current dictionary doesn't contain key from enumerator", i)); } if (String.Compare(sd[curr.Key.ToString()], curr.Value.ToString()) != 0) { Assert.False(true, string.Format("Error, Value for current Key is different in dictionary", i)); } // while we didn't MoveNext, Current should return the same value DictionaryEntry curr1 = (DictionaryEntry)en.Current; if (!curr.Equals(curr1)) { Assert.False(true, string.Format("Error, second call of Current returned different result", i)); } } // next MoveNext should bring us outside of the collection // res = en.MoveNext(); res = en.MoveNext(); if (res) { Assert.False(true, string.Format("Error, MoveNext returned true")); } // // Attempt to get Current should result in exception // Assert.Throws<InvalidOperationException>(() => { curr = (DictionaryEntry)en.Current; }); en.Reset(); // // Attempt to get Current should result in exception // Assert.Throws<InvalidOperationException>(() => { curr = (DictionaryEntry)en.Current; }); // // [] Modify dictionary when enumerating // if (sd.Count < 1) { for (int i = 0; i < values.Length; i++) { sd.Add(keys[i], values[i]); } } en = sd.GetEnumerator(); res = en.MoveNext(); if (!res) { Assert.False(true, string.Format("Error, MoveNext returned false")); } curr = (DictionaryEntry)en.Current; int cnt = sd.Count; sd.Remove(keys[0]); if (sd.Count != cnt - 1) { Assert.False(true, string.Format("Error, didn't remove item with 0th key")); } // will return just removed item DictionaryEntry curr2 = (DictionaryEntry)en.Current; if (!curr.Equals(curr2)) { Assert.False(true, string.Format("Error, current returned different value after modification")); } // exception expected Assert.Throws<InvalidOperationException>(() => { res = en.MoveNext(); }); // // [] Modify dictionary when enumerated beyond the end // sd.Clear(); for (int i = 0; i < values.Length; i++) { sd.Add(keys[i], values[i]); } en = sd.GetEnumerator(); for (int i = 0; i < sd.Count; i++) { en.MoveNext(); } curr = (DictionaryEntry)en.Current; curr = (DictionaryEntry)en.Current; cnt = sd.Count; sd.Remove(keys[0]); if (sd.Count != cnt - 1) { Assert.False(true, string.Format("Error, didn't remove item with 0th key")); } // will return just removed item curr2 = (DictionaryEntry)en.Current; if (!curr.Equals(curr2)) { Assert.False(true, string.Format("Error, current returned different value after modification")); } // exception expected Assert.Throws<InvalidOperationException>(() => { res = en.MoveNext(); }); }
/// <summary> /// <para>Starts the parsing process. Throws CmdLineArgumentExceptions in case of errors.</para> /// <para>Afterwards use the enumerator or the dictionary interface to access the found paramters and their values.</para> /// </summary> /// <param name="ArgumentLine">Argument line passed via command line to the program.</param> public void Parse(string ArgumentLine) { FoundParameters = new StringDictionary(); Enumerator = FoundParameters.GetEnumerator(); //pure: ^[\s]*((?<unknownvalues>("[^"]*")|('[^']*')|([^ "'/-]*)?)[\s]*)*([\s]*[/-](?<name>[^\s-/:=]+)([:=]?)([\s]*)(?<value>("[^"]*")|('[^']*')|([\s]*[^/-][^\s]+[\s]*)|([^/-]+)|)?([\s]*))*$ string CorrectCmdLineRegEx = "^[\\s]*((?<unknownvalues>(\"[^\"]*\")|('[^']*')|([^ \"'/-]*)?)[\\s]*)*([\\s]*[/-](?<name>[^\\s-/:=]+)([:=]?)([\\s]*)(?<value>(\"[^\"]*\")|('[^']*')|([\\s]*[^/-][^\\s]+[\\s]*)|([^/-]+)|)?([\\s]*))*$"; string ParamValuePairRegEx = "^(([\\s]*[/-])(?<name>[^\\s-/:=]+)([:=]?)([\\s]*)(?<value>(\"[^\"]*\")|('[^']*')|([\\s]*[^/-][^\\s]+[\\s]*)|([^/-]+)|)?([\\s]*))*$"; //start from beginning (^) and go to very end ($) //first optionally remove spaces [\s]* (this might not be necessary) //find optionally values without parameter. one of following: // 1) anything enclosed by double quotes ("[^"]*") // 2) anything enclosed by single quotes ('[^']*') // 3) anything that is not double or single quote nor slash nor minus [^"'/-]* // 4) or anything that contains no space [^ ]*? //find each parameter-value pair which seems to be okay. however, there might be unwanted some / or - signs in between. //each pair must start with a space followed by / or - ([\s]+[/-]) //next is the parameter name which can be anything but spaces, -, /, or : ([^\\s-/:=]) //next is the value which can either be one of following: (note: order matters!) // -anything except " enclosed by " or anything except ' enclosed by ' ((\"[^\"]*\")|('[^']*')) // -anything but spaces not starting with / nor - optionally enclosed by spaces (([\\s]*[^/-][^\\s]+[\\s]*)) // -anything but / or - ([^/-]+). //the argument may end with spaces (([\\s]*)) RegexOptions ro = new RegexOptions(); ro = ro | RegexOptions.IgnoreCase; ro = ro | RegexOptions.Multiline; Regex ParseCmdLine = new Regex(CorrectCmdLineRegEx, ro); ///For test and debug purposes function Matches() is used which returns ///a MatchCollection. However, there should never be more than one entry. /*MatchCollection mc = ParseCmdLine.Matches(ArgumentLine.ToString()); if (mc.Count > 1) throw new Exception("Internal Exception: MatchCollection contains more than 1 entry!"); foreach (Match m in mc)*/ ///By default use Match() because in case of no match raising ExceptionSyntaxError would be skipped by Matches() and foreach. Match m = ParseCmdLine.Match(ArgumentLine.ToString()); { if (m.Success == false) { ///Regular expression did not match ArgumentLine. There might be two / or -. ///Find out up to where ArgumentLine seems to be okay and raise an exception reporting the rest. int LastCorrectPosition = FindMismatchReasonInRegex(CorrectCmdLineRegEx, ArgumentLine); string ProbableErrorCause = ArgumentLine.Substring(LastCorrectPosition); throw new ExceptionSyntaxError(String("Exception") + String("ExceptionSyntaxError") + ArgumentLine + String("ExceptionSyntaxError2") + ProbableErrorCause + String("ExceptionSyntaxError3")); } else { //RegEx match ArgumentLine, thus syntax is ok. ///try to add values without parameters to FoundParameter using function ///AddNewFoundParameter(). Before adding move quotes if any. ///If those arguments are not allowed AddNewFoundParameter() raises an exception. Group u_grp = m.Groups["unknownvalues"]; String unknownValues = null; if (u_grp != null && u_grp.Value == string.Empty && u_grp.Captures != null && u_grp.Captures.Count > 0) { String g = ""; foreach (Capture f in u_grp.Captures) { g += f + " "; } unknownValues = g.TrimEnd(); } else { unknownValues = u_grp.Value; } if (unknownValues != null && unknownValues != string.Empty) { string unknown = unknownValues.Trim(); Regex Enclosed = new Regex("^(\".*\")|('.*')$"); Match e = Enclosed.Match(unknown); if (e.Length != 0) unknown = unknown.Substring(1, unknown.Length - 2); //check whether this first (unknown) value is actually a boolean parameter. (e.g. /help) //if it is a boolean parameter (or switch) add if as such. bool unknownParameterHandled = false; if (WantedParameters.ContainsKey(unknown)) { if (WantedParameters[unknown].ValueType == ValueType.Bool || WantedParameters[unknown].ValueType == ValueType.MultipleBool) { AddNewFoundParameter(unknown, ""); unknownParameterHandled = true; } } else if ((unknown[0] == '/' || unknown[0] == '-') && WantedParameters.ContainsKey(unknown.Substring(1))) { if (WantedParameters[unknown.Substring(1)].ValueType == ValueType.Bool || WantedParameters[unknown.Substring(1)].ValueType == ValueType.MultipleBool) { AddNewFoundParameter(unknown.Substring(1), ""); unknownParameterHandled = true; } } //check if found (unknown) parameter is actually parameter-value-pair (e.g. /parameter="value" //but only add it as param-value-pair if it was NOT quoted (e.Length == 0) if (unknownParameterHandled == false && e.Length == 0) { ParseCmdLine = new Regex(ParamValuePairRegEx, ro); Match pair = ParseCmdLine.Match(unknown); if (pair.Success == true) { Group param_grp3 = pair.Groups["name"]; Group value_grp3 = pair.Groups["value"]; if (param_grp3.Captures.Count != 1 || value_grp3.Captures.Count != 1) throw new Exception("Internal Exception: First parameter is parameter-value-pair but does not consist of exactly 1 parameter and 1 value. This should never happen."); AddNewFoundParameter(param_grp3.Captures[0].ToString(), value_grp3.Captures[0].ToString()); unknownParameterHandled = true; } } //is first (unknown) parameter was not processed yet (i.e. it is not boolean parameter nor param-value-pair), //add it as unknown parameter now. if (unknownParameterHandled == false) AddNewFoundParameter("", unknown); } Group param_grp = m.Groups["name"]; Group value_grp = m.Groups["value"]; if (param_grp == null || value_grp == null) { //this should never happen. throw new Exception("Internal Exception: Commandline parameter(s) incorrect."); } ///RegEx find always pairs of name- and value-group. their count should thus always match. if (param_grp.Captures.Count != value_grp.Captures.Count) throw new Exception("Internal Exception: Number of parameters and number of values is not equal. This should never happen."); ///try to add each name-value-match to FoundParameters using AddNewFoundParameter() function. ///if value is quoted, remove quotes before calling AddNewFoundParameter(). ///if value is of wrong type AddNewFoundParameter() throws an exception. for (int i = 0; i < param_grp.Captures.Count; i++) { //if there are spaces at either side of value or param, trim those. string value = value_grp.Captures[i].ToString().Trim(); string param = param_grp.Captures[i].ToString().Trim(); Regex Enclosed = new Regex("^(\".*\")|('.*')$"); Match e = Enclosed.Match(value); if (e.Length != 0) value = value.Substring(1, value.Length - 2); AddNewFoundParameter(param, value); } } } CheckRequiredParameters(); }
public void Test01() { IntlStrings intl; StringDictionary sd; // simple string values string[] values = { "", " ", "a", "aa", "text", " spaces", "1", "$%^#", "2222222222222222222222222", System.DateTime.Today.ToString(), Int32.MaxValue.ToString() }; // keys for simple string values string[] keys = { "zero", "one", " ", "", "aa", "1", System.DateTime.Today.ToString(), "$%^#", Int32.MaxValue.ToString(), " spaces", "2222222222222222222222222" }; Array destination; int cnt = 0; // Count // initialize IntStrings intl = new IntlStrings(); // [] StringDictionary is constructed as expected //----------------------------------------------------------------- sd = new StringDictionary(); // [] Copy empty dictionary into empty array // destination = Array.CreateInstance(typeof(Object), sd.Count); Assert.Throws<ArgumentOutOfRangeException>(() => { sd.CopyTo(destination, -1); }); sd.CopyTo(destination, 0); Assert.Throws<ArgumentException>(() => { sd.CopyTo(destination, 1); }); // [] Copy empty dictionary into non-empty array // destination = Array.CreateInstance(typeof(Object), values.Length); for (int i = 0; i < values.Length; i++) { destination.SetValue(values[i], i); } sd.CopyTo(destination, 0); if (destination.Length != values.Length) { Assert.False(true, string.Format("Error, altered array after copying empty collection")); } if (destination.Length == values.Length) { for (int i = 0; i < values.Length; i++) { if (String.Compare(destination.GetValue(i).ToString(), values[i]) != 0) { Assert.False(true, string.Format("Error, altered item {0} after copying empty collection", i)); } } } // [] add simple strings and CopyTo(Array, 0) // cnt = sd.Count; int len = values.Length; for (int i = 0; i < len; i++) { sd.Add(keys[i], values[i]); } if (sd.Count != len) { Assert.False(true, string.Format("Error, count is {0} instead of {1}", sd.Count, values.Length)); } destination = Array.CreateInstance(typeof(Object), len); sd.CopyTo(destination, 0); IEnumerator en = sd.GetEnumerator(); // // order of items is the same as order of enumerator // for (int i = 0; i < len; i++) { en.MoveNext(); // verify that collection is copied correctly // DictionaryEntry curr = (DictionaryEntry)en.Current; if (String.Compare(curr.Value.ToString(), ((DictionaryEntry)destination.GetValue(i)).Value.ToString()) != 0) { Assert.False(true, string.Format("Error, copied \"{1}\" instead of \"{2}\"", i, ((DictionaryEntry)destination.GetValue(i)).Value, curr.Value)); } if (String.Compare(curr.Key.ToString(), ((DictionaryEntry)destination.GetValue(i)).Key.ToString()) != 0) { Assert.False(true, string.Format("Error, copied \"{1}\" instead of \"{2}\"", i, ((DictionaryEntry)destination.GetValue(i)).Key, curr.Key)); } } // // [] add simple strings and CopyTo(Array, middle_index) sd.Clear(); for (int i = 0; i < len; i++) { sd.Add(keys[i], values[i]); } if (sd.Count != len) { Assert.False(true, string.Format("Error, count is {0} instead of {1}", sd.Count, values.Length)); } destination = Array.CreateInstance(typeof(Object), len * 2); sd.CopyTo(destination, len); en = sd.GetEnumerator(); // // order of items is the same as order of enumerator // for (int i = 0; i < len; i++) { en.MoveNext(); // verify that collection is copied correctly // DictionaryEntry curr = (DictionaryEntry)en.Current; if (String.Compare(curr.Value.ToString(), ((DictionaryEntry)destination.GetValue(i + len)).Value.ToString()) != 0) { Assert.False(true, string.Format("Error, copied \"{1}\" instead of \"{2}\"", i, ((DictionaryEntry)destination.GetValue(i + len)).Value, curr.Value)); } if (String.Compare(curr.Key.ToString(), ((DictionaryEntry)destination.GetValue(i + len)).Key.ToString()) != 0) { Assert.False(true, string.Format("Error, copied \"{1}\" instead of \"{2}\"", i, ((DictionaryEntry)destination.GetValue(i + len)).Key, curr.Key)); } } // // Intl strings // [] add intl strings and CopyTo(Array, 0) // string[] intlValues = new string[len * 2]; // fill array with unique strings // for (int i = 0; i < len * 2; i++) { string val = intl.GetRandomString(MAX_LEN); while (Array.IndexOf(intlValues, val) != -1) val = intl.GetRandomString(MAX_LEN); intlValues[i] = val; } Boolean caseInsensitive = false; for (int i = 0; i < len * 2; i++) { if (intlValues[i].Length != 0 && intlValues[i].ToLowerInvariant() == intlValues[i].ToUpperInvariant()) caseInsensitive = true; } sd.Clear(); for (int i = 0; i < len; i++) { sd.Add(intlValues[i + len], intlValues[i]); } if (sd.Count != (len)) { Assert.False(true, string.Format("Error, count is {0} instead of {1}", sd.Count, len)); } destination = Array.CreateInstance(typeof(Object), len); sd.CopyTo(destination, 0); en = sd.GetEnumerator(); // // order of items is the same as order of enumerator // for (int i = 0; i < len; i++) { en.MoveNext(); // verify that collection is copied correctly // DictionaryEntry curr = (DictionaryEntry)en.Current; if (String.Compare(curr.Value.ToString(), ((DictionaryEntry)destination.GetValue(i)).Value.ToString()) != 0) { Assert.False(true, string.Format("Error, copied \"{1}\" instead of \"{2}\"", i, ((DictionaryEntry)destination.GetValue(i)).Value, curr.Value)); } if (String.Compare(curr.Key.ToString(), ((DictionaryEntry)destination.GetValue(i)).Key.ToString()) != 0) { Assert.False(true, string.Format("Error, copied \"{1}\" instead of \"{2}\"", i, ((DictionaryEntry)destination.GetValue(i)).Key, curr.Key)); } } // // Intl strings // [] add intl strings and CopyTo(Array, middle_index) // destination = Array.CreateInstance(typeof(Object), len * 2); sd.CopyTo(destination, len); en = sd.GetEnumerator(); // // order of items is the same as order of enumerator // for (int i = 0; i < len; i++) { en.MoveNext(); // verify that collection is copied correctly // DictionaryEntry curr = (DictionaryEntry)en.Current; if (String.Compare(curr.Value.ToString(), ((DictionaryEntry)destination.GetValue(i + len)).Value.ToString()) != 0) { Assert.False(true, string.Format("Error, copied \"{1}\" instead of \"{2}\"", i, ((DictionaryEntry)destination.GetValue(i + len)).Value, curr.Value)); } if (String.Compare(curr.Key.ToString(), ((DictionaryEntry)destination.GetValue(i + len)).Key.ToString()) != 0) { Assert.False(true, string.Format("Error, copied \"{1}\" instead of \"{2}\"", i, ((DictionaryEntry)destination.GetValue(i + len)).Key, curr.Key)); } } // // [] Case sensitivity // string[] intlValuesLower = new string[len * 2]; // fill array with unique strings // for (int i = 0; i < len * 2; i++) { intlValues[i] = intlValues[i].ToUpperInvariant(); } for (int i = 0; i < len * 2; i++) { intlValuesLower[i] = intlValues[i].ToLowerInvariant(); } sd.Clear(); // // will use first half of array as values and second half as keys // for (int i = 0; i < len; i++) { sd.Add(intlValues[i + len], intlValues[i]); // adding uppercase strings } destination = Array.CreateInstance(typeof(Object), len); sd.CopyTo(destination, 0); en = sd.GetEnumerator(); // // order of items is the same as order of enumerator // for (int i = 0; i < len; i++) { en.MoveNext(); // verify that collection is copied correctly // DictionaryEntry curr = (DictionaryEntry)en.Current; if (String.Compare(curr.Value.ToString(), ((DictionaryEntry)destination.GetValue(i)).Value.ToString()) != 0) { Assert.False(true, string.Format("Error, copied \"{1}\" instead of \"{2}\"", i, ((DictionaryEntry)destination.GetValue(i)).Value, curr.Value)); } if (!caseInsensitive && (Array.IndexOf(intlValuesLower, ((DictionaryEntry)destination.GetValue(i)).Value.ToString()) != -1)) { Assert.False(true, string.Format("Error, copied lowercase string")); } if (String.Compare(curr.Key.ToString(), ((DictionaryEntry)destination.GetValue(i)).Key.ToString()) != 0) { Assert.False(true, string.Format("Error, copied \"{1}\" instead of \"{2}\"", i, ((DictionaryEntry)destination.GetValue(i)).Key, curr.Key)); } if (Array.IndexOf(intlValuesLower, ((DictionaryEntry)destination.GetValue(i)).Key.ToString()) == -1) { Assert.False(true, string.Format("Error, copied uppercase key")); } } // // [] CopyTo(null, int) // destination = null; Assert.Throws<ArgumentNullException>(() => { sd.CopyTo(destination, 0); }); // // [] CopyTo(string[], -1) // cnt = sd.Count; destination = Array.CreateInstance(typeof(Object), cnt); Assert.Throws<ArgumentOutOfRangeException>(() => { sd.CopyTo(destination, -1); }); // // [] CopyTo(Array, upperBound+1) // if (sd.Count < 1) { for (int i = 0; i < len; i++) { sd.Add(keys[i], values[i]); } } destination = Array.CreateInstance(typeof(Object), len); Assert.Throws<ArgumentException>(() => { sd.CopyTo(destination, len); }); // // [] CopyTo(Array, upperBound+2) // Assert.Throws<ArgumentException>(() => { sd.CopyTo(destination, len + 1); }); // // [] CopyTo(Array, not_enough_space) // Assert.Throws<ArgumentException>(() => { sd.CopyTo(destination, len / 2); }); // // [] CopyTo(multidim_Array, 0) // destination = new object[len, len]; Assert.Throws<ArgumentException>(() => { sd.CopyTo(destination, 0); }); }