Index: src/Common/NetTopologySuite/Utilities/RToolsUtil/Opts.cs
===================================================================
diff -u -r8f6ae890fed8e8eae3a32f9c0498a10f82e0ddf9 -r5fc71a385897af92ccb092f2f969b5709afab85a
--- src/Common/NetTopologySuite/Utilities/RToolsUtil/Opts.cs (.../Opts.cs) (revision 8f6ae890fed8e8eae3a32f9c0498a10f82e0ddf9)
+++ src/Common/NetTopologySuite/Utilities/RToolsUtil/Opts.cs (.../Opts.cs) (revision 5fc71a385897af92ccb092f2f969b5709afab85a)
@@ -29,502 +29,580 @@
namespace RTools_NTS.Util
{
- ///
- /// A command-line option parser similar to Perl's getopts.
- /// This is for parsing command-line
- /// options like "-name foo -type theType -v -d". This parses a string[]
- /// (like main usually takes) and collects argument information
- /// based on a parse specification.
- ///
- ///
- ///
- /// The UsageSpec endCapStyle parse is unfinished.
- /// Basically the UsageSpec endCapStyle parse is more expressive than the
- /// ParseSpec endCapStyle parse (see below). But in this current implementation,
- /// none of the additional expressiveness is used. In other words
- /// this class does not currently do anything with the optional/required
- /// switches (-file [-help]) and does not do anything with the pipe
- /// operator.
- ///
- ///
- /// This takes two types of parse specifications, a perl getopts endCapStyle
- /// such as "file=s, type:s, v, d" (see the ParseSpec property),
- /// or a unix usage endCapStyle such as
- /// "-file fileName -type [typeName] [-v|-d]" (see the UsageSpec property).
- ///
- ///
- /// For the ParseSpec property, the rules are as follows:
- /// 1) The string is comma-separated like "file=s, type:s, v, d"
- /// 2) = means must have an argument
- /// 3) : means may have an argument
- ///
- ///
- /// For the UsageSpec property, the rules are as follows:
- /// 1) Optional arguments must be enclosed in square brackets [].
- /// 2) Argument names must be all word characters (- is considered to be a
- /// word character).
- ///
- ///
- ///
- ///
- ///
- /// Here's an example use:
- ///
- /// Opts opts = new Opts();
- /// opts.ParseSpec = "file=s, type:s, v, d");
- /// - or -
- /// opts.UsageSpec = "-file fileName -type [typeName] [-v|-d]";
- /// if (!opts.Parse(args, out errorMessage)) { // display error message and usage }
- /// if (opts.Options.ContainsKey("v")) // -v was specified
- /// if (!opts.Options.ContainsKey("file")) { error... // need -file specified }
- /// Console.WriteLine("-file specified is {0}", opts.Options["file"]);
- ///
- ///
- ///
- public class Opts
- {
- // ----------------------------------------------------------------
- #region Private variables
- // ----------------------------------------------------------------
+ ///
+ /// A command-line option parser similar to Perl's getopts.
+ /// This is for parsing command-line
+ /// options like "-name foo -type theType -v -d". This parses a string[]
+ /// (like main usually takes) and collects argument information
+ /// based on a parse specification.
+ ///
+ ///
+ ///
+ /// The UsageSpec endCapStyle parse is unfinished.
+ /// Basically the UsageSpec endCapStyle parse is more expressive than the
+ /// ParseSpec endCapStyle parse (see below). But in this current implementation,
+ /// none of the additional expressiveness is used. In other words
+ /// this class does not currently do anything with the optional/required
+ /// switches (-file [-help]) and does not do anything with the pipe
+ /// operator.
+ ///
+ ///
+ /// This takes two types of parse specifications, a perl getopts endCapStyle
+ /// such as "file=s, type:s, v, d" (see the ParseSpec property),
+ /// or a unix usage endCapStyle such as
+ /// "-file fileName -type [typeName] [-v|-d]" (see the UsageSpec property).
+ ///
+ ///
+ /// For the ParseSpec property, the rules are as follows:
+ /// 1) The string is comma-separated like "file=s, type:s, v, d"
+ /// 2) = means must have an argument
+ /// 3) : means may have an argument
+ ///
+ ///
+ /// For the UsageSpec property, the rules are as follows:
+ /// 1) Optional arguments must be enclosed in square brackets [].
+ /// 2) Argument names must be all word characters (- is considered to be a
+ /// word character).
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Here's an example use:
+ ///
+ /// Opts opts = new Opts();
+ /// opts.ParseSpec = "file=s, type:s, v, d");
+ /// - or -
+ /// opts.UsageSpec = "-file fileName -type [typeName] [-v|-d]";
+ /// if (!opts.Parse(args, out errorMessage)) { // display error message and usage }
+ /// if (opts.Options.ContainsKey("v")) // -v was specified
+ /// if (!opts.Options.ContainsKey("file")) { error... // need -file specified }
+ /// Console.WriteLine("-file specified is {0}", opts.Options["file"]);
+ ///
+ ///
+ ///
+ public class Opts
+ {
+ // ---------------------------------------------------------------------
- ///
- /// Peer class for logging.
- ///
- private Logger log;
+ #region TestSelf
- ///
- /// Has all the info after the parse... presence, and arguments.
- ///
- private Hashtable options;
+ // ---------------------------------------------------------------------
+ ///
+ /// Simple self test.
+ ///
+ /// bool - true for success, false for failure.
+ public static bool TestSelf()
+ {
+ Logger log = new Logger("testSelf");
+ log.Verbosity = VerbosityLevel.Debug;
+ log.Info("Starting...");
- ///
- /// After the parse, has the arguments which were unswitched
- /// (not after an option like -file).
- ///
- private ArrayList unswitchedArgs;
+ //
+ // try parseSpec endCapStyle
+ //
+ string parseSpec = "file=s, type:s, v, d, number=s";
+ string[] testArgs =
+ {
+ "-file",
+ "fileName",
+ "-type",
+ "-v",
+ "hello",
+ "-number",
+ "-3.2"
+ };
+ string errorMessage = null;
- ///
- /// The specification.
- ///
- private string parseSpec;
+ Opts opts = new Opts();
+ opts.ParseSpec = parseSpec;
+ log.Info("ParseSpec:");
+ opts.DisplayParseSpec(" ");
- ///
- /// Set from the parseSpec. This is for options which require arguments.
- ///
- private ArrayList requireArg;
+ if (!opts.Parse(testArgs, out errorMessage))
+ {
+ log.Error("Unable to parse test string.");
+ log.Error("Error message is '{0}'", errorMessage);
+ return (false);
+ }
- ///
- /// Set from the parseSpec. This is for options which may have arguments.
- ///
- private ArrayList mayHaveArg;
+ log.Info("After parse:");
+ opts.Display(" ");
- ///
- /// Set from the parseSpec. This is for options which do not have arguments.
- ///
- private ArrayList noArg;
+ // check results
+ if (opts.Options["file"] == null)
+ {
+ log.Error("Parse didn't get -file option");
+ return (false);
+ }
+ log.Info("-file argument was {0}", opts.Options["file"]);
- #endregion
+ if (opts.Options.ContainsKey("v"))
+ {
+ log.Info("-v option was found");
+ }
+ else
+ {
+ log.Error("Parse didn't find -v option");
+ return (false);
+ }
- // ----------------------------------------------------------------------
- #region Properties
- // ----------------------------------------------------------------------
+ if (opts.Options.ContainsKey("type"))
+ {
+ log.Info("-type arg was '{0}'", opts.Options["type"]);
+ }
+ else
+ {
+ log.Error("Parse didn't find -type option");
+ return (false);
+ }
- ///
- /// The specification of what options to look for, which
- /// have arguments, etc. This is the "name=s, type:s, v, d"
- /// endCapStyle.
- ///
- public string ParseSpec
- {
- get { return(parseSpec); }
- set
- {
- Initialize();
- string[] words = value.Split(',');
- char[] typeChars = {':', '='};
- foreach (string word in words)
- {
- int nameLen = word.IndexOfAny(typeChars);
- if (nameLen < 0) nameLen = word.Length;
- string name = word.Substring(0, nameLen).Trim();
- if (word.IndexOf(':') >= 0)
- mayHaveArg.Add(name);
- else if (word.IndexOf('=') >= 0)
- requireArg.Add(name);
- else noArg.Add(name);
- }
- parseSpec = value;
- }
- }
+ //
+ // try usageSpec endCapStyle
+ //
+ log.Info("----------------------------------------------------------");
+ log.Info("UsageSpec style of use.");
+ string usageSpec = "cmd -file fileName -type [typeName] [-v|-d] [-number num] file ...";
+ log.Info("Input usage: {0}", usageSpec);
+ opts.UsageSpec = usageSpec;
+ log.Info("UsageSpec:");
+ opts.DisplayParseSpec(" ");
- ///
- /// The specification of what options to look for, which
- /// have arguments, etc. This is the "-name fileName [-v|-d]"
- /// endCapStyle.
- ///
- public string UsageSpec
- {
- get { return(parseSpec); }
- set
- {
- Initialize();
- StreamTokenizer tokenizer = new StreamTokenizer();
- tokenizer.Verbosity = VerbosityLevel.Warn;
- tokenizer.Settings.WordChar('-');
- ArrayList tokens = new ArrayList();
- tokenizer.TokenizeString(value, tokens);
- StringBuilder sb = new StringBuilder();
+ if (!opts.Parse(testArgs, out errorMessage))
+ {
+ log.Error("Unable to parse test string.");
+ log.Error("Error message is '{0}'", errorMessage);
+ return (false);
+ }
- for (int i = 0; i < tokens.Count; i++)
- {
- Token t = (Token)tokens[i];
- Token nextToken = null;
- if (i + 1 < tokens.Count) nextToken = (Token)tokens[i + 1];
+ if (opts.Options.ContainsKey("v"))
+ {
+ log.Info("-v was specified");
+ }
- if ((t is WordToken) && (IsSwitch(t.StringValue)))
- {
- // it's a switch
- string name = t.StringValue.Substring(1); // drop the -
- if ((nextToken != null) && (nextToken is WordToken)
- && (!IsSwitch(nextToken.StringValue)))
- {
- requireArg.Add(name);
- if (sb.Length > 0) sb.Append(",");
- sb.Append(name + "=s");
- }
- else if ((nextToken == '[') && (i + 2 < tokens.Count))
- {
- Token twoAhead = (Token)tokens[i + 2];
- if ((twoAhead is WordToken) && (!IsSwitch(twoAhead.StringValue)))
- {
- // optional
- mayHaveArg.Add(name);
- if (sb.Length > 0) sb.Append(",");
- sb.Append(name + ":s");
- }
- }
- else
- {
- // switch with no arg
- noArg.Add(name);
- if (sb.Length > 0) sb.Append(",");
- sb.Append(name);
- }
- }
- }
- parseSpec = sb.ToString();
- }
- }
+ log.Info("After parse:");
+ opts.Display(" ");
- ///
- /// This hashtable is built during Parse. This contains the results
- /// of the parse for switches (options). Options which don't take
- /// arguments will map to bool True. Options which may have arguments
- /// will map to the argument string if present, and null if not present.
- /// Options which must have arguments will map to the argument string
- /// if the Parse succeeds.
- ///
- public Hashtable Options
- {
- get { return(options); }
- }
+ // done
+ log.Info("Done.");
+ return (true);
+ }
- ///
- /// These are the rest of the command line arguments which are
- /// not associated with options (switches like "-file").
- ///
- public ArrayList UnswitchedArgs
- {
- get { return(unswitchedArgs); }
- }
+ #endregion
- ///
- /// The verbosity level for this object's Logger.
- ///
- public VerbosityLevel Verbosity
- {
- get { return(log.Verbosity); }
- set { log.Verbosity = value; }
- }
+ // ----------------------------------------------------------------
- #endregion
+ #region Private variables
- // ---------------------------------------------------------------------
- #region Constructors/Destructor
- // ---------------------------------------------------------------------
+ // ----------------------------------------------------------------
- ///
- /// Default constructor.
- ///
- public Opts()
- {
- Initialize();
- }
+ ///
+ /// Peer class for logging.
+ ///
+ private Logger log;
- ///
- /// Utility function, things common to constructors.
- ///
- void Initialize()
- {
- log = new Logger("Opts");
- options = new Hashtable();
- unswitchedArgs = new ArrayList();
- requireArg = new ArrayList();
- mayHaveArg = new ArrayList();
- noArg = new ArrayList();
- }
+ ///
+ /// Has all the info after the parse... presence, and arguments.
+ ///
+ private Hashtable options;
- #endregion
+ ///
+ /// After the parse, has the arguments which were unswitched
+ /// (not after an option like -file).
+ ///
+ private ArrayList unswitchedArgs;
- // ---------------------------------------------------------------------
- #region Standard Methods
- // ---------------------------------------------------------------------
+ ///
+ /// The specification.
+ ///
+ private string parseSpec;
- ///
- /// Display the state of this object.
- ///
- public void Display()
- {
- Display(String.Empty);
- }
+ ///
+ /// Set from the parseSpec. This is for options which require arguments.
+ ///
+ private ArrayList requireArg;
- ///
- /// Display the state of this object, with a per-line prefix.
- ///
- /// The pre-line prefix.
- public void Display(string prefix)
- {
- log.WriteLine(prefix + "Opts display:");
- log.WriteLine(prefix + " parseSpec: {0}", parseSpec);
- log.WriteLine(prefix + " options: ");
- foreach(DictionaryEntry entry in options)
- {
- log.WriteLine(prefix + " {0} -> {1}", entry.Key, entry.Value);
- }
- log.WriteLine(prefix + " unswitched args: ");
- foreach(string s in unswitchedArgs)
- {
- log.WriteLine(prefix + " {0}", s);
- }
- }
+ ///
+ /// Set from the parseSpec. This is for options which may have arguments.
+ ///
+ private ArrayList mayHaveArg;
- ///
- /// Display the information gained from the parseSpec.
- ///
- public void DisplayParseSpec()
- {
- Display(String.Empty);
- }
+ ///
+ /// Set from the parseSpec. This is for options which do not have arguments.
+ ///
+ private ArrayList noArg;
- ///
- /// Display the information gained from the parseSpec.
- ///
- /// A prefix to prepend to each line.
- public void DisplayParseSpec(string prefix)
- {
- log.WriteLine(prefix + "parseSpec: {0}", parseSpec);
- log.WriteLine(prefix + " mayHaveArg: ");
- foreach(string s in mayHaveArg)
- log.WriteLine(prefix + " {0}", s);
- log.WriteLine(prefix + " requireArg: ");
- foreach(string s in requireArg)
- log.WriteLine(prefix + " {0}", s);
- log.WriteLine(prefix + " noArg: ");
- foreach(string s in noArg)
- log.WriteLine(prefix + " {0}", s);
- }
+ #endregion
- #endregion
+ // ----------------------------------------------------------------------
- // ---------------------------------------------------------------------
- #region main Methods
- // ---------------------------------------------------------------------
+ #region Properties
- ///
- /// Utility method to determine whether a string is a switch or not.
- /// This currently just checks if it starts with a - which is not
- /// followed by a digit.
- ///
- /// The string to test.
- /// bool - true for yes it's a switch
- private bool IsSwitch(string s)
- {
- if ((s == null) || (s.Length < 2)) return(false);
- if ((s[0] == '-') && (!Char.IsDigit(s[1]))) return(true);
- return(false);
- }
+ // ----------------------------------------------------------------------
- ///
- /// Parse the options string[], determine if the parse spec
- /// requirements are met, and provide an error message string
- /// if not.
- ///
- /// The string[] to parse.
- /// Output error message. This
- /// is set if the input options don't have all the pieces
- /// required by the parseSpec string.
- /// bool - true if parseSpec requirements are met,
- /// false otherwise.
- public bool Parse(string[] args, out string errorMessage)
- {
- errorMessage = null;
- for (int i = 0; i < args.Length; i++)
- {
- string s = args[i].Trim();
- if (IsSwitch(s))
- {
- // it's a switch
- string name = s.Substring(1);
- if (requireArg.Contains(name))
- {
- if (i + 1 < args.Length)
- {
- if (!IsSwitch(args[i + 1]))
- {
- options[name] = args[i + 1].Trim();
- i++;
- }
- else
- {
- errorMessage = String.Format("Option '{0}' requires an argument, but next word is {1}",
- name, args[i + 1]);
- return(false);
- }
- }
- else
- {
- errorMessage = String.Format("Option '{0}' requires an argument, but "
- + "there are no words after it", name);
- return(false);
- }
- }
- else if (mayHaveArg.Contains(name))
- {
- options[name] = null;
- if (i + 1 < args.Length)
- {
- if (args[i + 1].Trim()[0] != '-')
- {
- options[name] = args[i + 1].Trim();
- i++;
- }
- }
- }
- else if (noArg.Contains(name))
- {
- options[name] = true;
- }
- else
- {
- // it's a switch, but wasn't in parse spec
- errorMessage = String.Format("Option '{0}' isn't a recognized switch.", name);
- return(false);
- }
- }
- else
- {
- // not a switch
- unswitchedArgs.Add(s);
- }
- }
- return(true);
- }
+ ///
+ /// The specification of what options to look for, which
+ /// have arguments, etc. This is the "name=s, type:s, v, d"
+ /// endCapStyle.
+ ///
+ public string ParseSpec
+ {
+ get
+ {
+ return (parseSpec);
+ }
+ set
+ {
+ Initialize();
+ string[] words = value.Split(',');
+ char[] typeChars =
+ {
+ ':',
+ '='
+ };
+ foreach (string word in words)
+ {
+ int nameLen = word.IndexOfAny(typeChars);
+ if (nameLen < 0)
+ {
+ nameLen = word.Length;
+ }
+ string name = word.Substring(0, nameLen).Trim();
+ if (word.IndexOf(':') >= 0)
+ {
+ mayHaveArg.Add(name);
+ }
+ else if (word.IndexOf('=') >= 0)
+ {
+ requireArg.Add(name);
+ }
+ else
+ {
+ noArg.Add(name);
+ }
+ }
+ parseSpec = value;
+ }
+ }
- #endregion
+ ///
+ /// The specification of what options to look for, which
+ /// have arguments, etc. This is the "-name fileName [-v|-d]"
+ /// endCapStyle.
+ ///
+ public string UsageSpec
+ {
+ get
+ {
+ return (parseSpec);
+ }
+ set
+ {
+ Initialize();
+ StreamTokenizer tokenizer = new StreamTokenizer();
+ tokenizer.Verbosity = VerbosityLevel.Warn;
+ tokenizer.Settings.WordChar('-');
+ ArrayList tokens = new ArrayList();
+ tokenizer.TokenizeString(value, tokens);
+ StringBuilder sb = new StringBuilder();
- // ---------------------------------------------------------------------
- #region TestSelf
- // ---------------------------------------------------------------------
- ///
- /// Simple self test.
- ///
- /// bool - true for success, false for failure.
- public static bool TestSelf()
- {
- Logger log = new Logger("testSelf");
- log.Verbosity = VerbosityLevel.Debug;
- log.Info("Starting...");
+ for (int i = 0; i < tokens.Count; i++)
+ {
+ Token t = (Token) tokens[i];
+ Token nextToken = null;
+ if (i + 1 < tokens.Count)
+ {
+ nextToken = (Token) tokens[i + 1];
+ }
- //
- // try parseSpec endCapStyle
- //
- string parseSpec = "file=s, type:s, v, d, number=s";
- string[] testArgs = {"-file", "fileName", "-type", "-v", "hello",
- "-number", "-3.2"};
- string errorMessage = null;
+ if ((t is WordToken) && (IsSwitch(t.StringValue)))
+ {
+ // it's a switch
+ string name = t.StringValue.Substring(1); // drop the -
+ if ((nextToken != null) && (nextToken is WordToken)
+ && (!IsSwitch(nextToken.StringValue)))
+ {
+ requireArg.Add(name);
+ if (sb.Length > 0)
+ {
+ sb.Append(",");
+ }
+ sb.Append(name + "=s");
+ }
+ else if ((nextToken == '[') && (i + 2 < tokens.Count))
+ {
+ Token twoAhead = (Token) tokens[i + 2];
+ if ((twoAhead is WordToken) && (!IsSwitch(twoAhead.StringValue)))
+ {
+ // optional
+ mayHaveArg.Add(name);
+ if (sb.Length > 0)
+ {
+ sb.Append(",");
+ }
+ sb.Append(name + ":s");
+ }
+ }
+ else
+ {
+ // switch with no arg
+ noArg.Add(name);
+ if (sb.Length > 0)
+ {
+ sb.Append(",");
+ }
+ sb.Append(name);
+ }
+ }
+ }
+ parseSpec = sb.ToString();
+ }
+ }
- Opts opts = new Opts();
- opts.ParseSpec = parseSpec;
- log.Info("ParseSpec:");
- opts.DisplayParseSpec(" ");
+ ///
+ /// This hashtable is built during Parse. This contains the results
+ /// of the parse for switches (options). Options which don't take
+ /// arguments will map to bool True. Options which may have arguments
+ /// will map to the argument string if present, and null if not present.
+ /// Options which must have arguments will map to the argument string
+ /// if the Parse succeeds.
+ ///
+ public Hashtable Options
+ {
+ get
+ {
+ return (options);
+ }
+ }
- if (!opts.Parse(testArgs, out errorMessage))
- {
- log.Error("Unable to parse test string.");
- log.Error("Error message is '{0}'", errorMessage);
- return(false);
- }
+ ///
+ /// These are the rest of the command line arguments which are
+ /// not associated with options (switches like "-file").
+ ///
+ public ArrayList UnswitchedArgs
+ {
+ get
+ {
+ return (unswitchedArgs);
+ }
+ }
- log.Info("After parse:");
- opts.Display(" ");
+ ///
+ /// The verbosity level for this object's Logger.
+ ///
+ public VerbosityLevel Verbosity
+ {
+ get
+ {
+ return (log.Verbosity);
+ }
+ set
+ {
+ log.Verbosity = value;
+ }
+ }
- // check results
- if (opts.Options["file"] == null)
- {
- log.Error("Parse didn't get -file option");
- return(false);
- }
- log.Info("-file argument was {0}", opts.Options["file"]);
+ #endregion
- if (opts.Options.ContainsKey("v")) log.Info("-v option was found");
- else
- {
- log.Error("Parse didn't find -v option");
- return(false);
- }
-
- if (opts.Options.ContainsKey("type"))
- {
- log.Info("-type arg was '{0}'", opts.Options["type"]);
- }
- else
- {
- log.Error("Parse didn't find -type option");
- return(false);
- }
+ // ---------------------------------------------------------------------
- //
- // try usageSpec endCapStyle
- //
- log.Info("----------------------------------------------------------");
- log.Info("UsageSpec style of use.");
- string usageSpec = "cmd -file fileName -type [typeName] [-v|-d] [-number num] file ...";
- log.Info("Input usage: {0}", usageSpec);
- opts.UsageSpec = usageSpec;
- log.Info("UsageSpec:");
- opts.DisplayParseSpec(" ");
+ #region Constructors/Destructor
- if (!opts.Parse(testArgs, out errorMessage))
- {
- log.Error("Unable to parse test string.");
- log.Error("Error message is '{0}'", errorMessage);
- return(false);
- }
+ // ---------------------------------------------------------------------
- if (opts.Options.ContainsKey("v"))
- {
- log.Info("-v was specified");
- }
+ ///
+ /// Default constructor.
+ ///
+ public Opts()
+ {
+ Initialize();
+ }
- log.Info("After parse:");
- opts.Display(" ");
+ ///
+ /// Utility function, things common to constructors.
+ ///
+ private void Initialize()
+ {
+ log = new Logger("Opts");
+ options = new Hashtable();
+ unswitchedArgs = new ArrayList();
+ requireArg = new ArrayList();
+ mayHaveArg = new ArrayList();
+ noArg = new ArrayList();
+ }
- // done
- log.Info("Done.");
- return(true);
- }
- #endregion
- }
-}
+ #endregion
+ // ---------------------------------------------------------------------
+ #region Standard Methods
+
+ // ---------------------------------------------------------------------
+
+ ///
+ /// Display the state of this object.
+ ///
+ public void Display()
+ {
+ Display(String.Empty);
+ }
+
+ ///
+ /// Display the state of this object, with a per-line prefix.
+ ///
+ /// The pre-line prefix.
+ public void Display(string prefix)
+ {
+ log.WriteLine(prefix + "Opts display:");
+ log.WriteLine(prefix + " parseSpec: {0}", parseSpec);
+ log.WriteLine(prefix + " options: ");
+ foreach (DictionaryEntry entry in options)
+ {
+ log.WriteLine(prefix + " {0} -> {1}", entry.Key, entry.Value);
+ }
+ log.WriteLine(prefix + " unswitched args: ");
+ foreach (string s in unswitchedArgs)
+ {
+ log.WriteLine(prefix + " {0}", s);
+ }
+ }
+
+ ///
+ /// Display the information gained from the parseSpec.
+ ///
+ public void DisplayParseSpec()
+ {
+ Display(String.Empty);
+ }
+
+ ///
+ /// Display the information gained from the parseSpec.
+ ///
+ /// A prefix to prepend to each line.
+ public void DisplayParseSpec(string prefix)
+ {
+ log.WriteLine(prefix + "parseSpec: {0}", parseSpec);
+ log.WriteLine(prefix + " mayHaveArg: ");
+ foreach (string s in mayHaveArg)
+ {
+ log.WriteLine(prefix + " {0}", s);
+ }
+ log.WriteLine(prefix + " requireArg: ");
+ foreach (string s in requireArg)
+ {
+ log.WriteLine(prefix + " {0}", s);
+ }
+ log.WriteLine(prefix + " noArg: ");
+ foreach (string s in noArg)
+ {
+ log.WriteLine(prefix + " {0}", s);
+ }
+ }
+
+ #endregion
+
+ // ---------------------------------------------------------------------
+
+ #region main Methods
+
+ // ---------------------------------------------------------------------
+
+ ///
+ /// Utility method to determine whether a string is a switch or not.
+ /// This currently just checks if it starts with a - which is not
+ /// followed by a digit.
+ ///
+ /// The string to test.
+ /// bool - true for yes it's a switch
+ private bool IsSwitch(string s)
+ {
+ if ((s == null) || (s.Length < 2))
+ {
+ return (false);
+ }
+ if ((s[0] == '-') && (!Char.IsDigit(s[1])))
+ {
+ return (true);
+ }
+ return (false);
+ }
+
+ ///
+ /// Parse the options string[], determine if the parse spec
+ /// requirements are met, and provide an error message string
+ /// if not.
+ ///
+ /// The string[] to parse.
+ /// Output error message. This
+ /// is set if the input options don't have all the pieces
+ /// required by the parseSpec string.
+ /// bool - true if parseSpec requirements are met,
+ /// false otherwise.
+ public bool Parse(string[] args, out string errorMessage)
+ {
+ errorMessage = null;
+ for (int i = 0; i < args.Length; i++)
+ {
+ string s = args[i].Trim();
+ if (IsSwitch(s))
+ {
+ // it's a switch
+ string name = s.Substring(1);
+ if (requireArg.Contains(name))
+ {
+ if (i + 1 < args.Length)
+ {
+ if (!IsSwitch(args[i + 1]))
+ {
+ options[name] = args[i + 1].Trim();
+ i++;
+ }
+ else
+ {
+ errorMessage = String.Format("Option '{0}' requires an argument, but next word is {1}",
+ name, args[i + 1]);
+ return (false);
+ }
+ }
+ else
+ {
+ errorMessage = String.Format("Option '{0}' requires an argument, but "
+ + "there are no words after it", name);
+ return (false);
+ }
+ }
+ else if (mayHaveArg.Contains(name))
+ {
+ options[name] = null;
+ if (i + 1 < args.Length)
+ {
+ if (args[i + 1].Trim()[0] != '-')
+ {
+ options[name] = args[i + 1].Trim();
+ i++;
+ }
+ }
+ }
+ else if (noArg.Contains(name))
+ {
+ options[name] = true;
+ }
+ else
+ {
+ // it's a switch, but wasn't in parse spec
+ errorMessage = String.Format("Option '{0}' isn't a recognized switch.", name);
+ return (false);
+ }
+ }
+ else
+ {
+ // not a switch
+ unswitchedArgs.Add(s);
+ }
+ }
+ return (true);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file