using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections.Specialized; using Yaulw.Tools; namespace Yaulw.Other { /// /// CommandLine Arguments Parser for an Application /// /// /// internal CMDline cmdline = new CMDline(typeof(App.CommandLine_Option), typeof(App.CommandLine_Flag)); /// /// public enum CommandLine_Flag /// { /// START, /// STOP, /// SHOW, /// } /// /// public enum CommandLine_Option /// { /// ADD_SOMETHING, /// REMOVE_SOMETHING, /// } /// /// cmdline.Parse(e.Args); /// /// if (cmdline.HasParams) /// { /// if (App.cmdline.ShowHelp || !App.cmdline.ParamsValid) /// { /// ShowCommandLineHelp(); /// return; /// } /// /// string AddSomething = cmdline.GetOptionValue(CommandLine_Option.ADD_SOMETHING, ""); // /// } /// /// /// public class CMDline { #region private Variables // Flag or Option Specifiers CONSTS private const String FLAG_OR_OPTION_SPECIFIER = "-/"; private const String HELP_FLAG_SPECIFIER = "?"; // Private Parsing Enums private Type _CMDLineOptions = null; private Type _CMDLineFlags = null; // Private Parsing Data Structures private Stack _stringStack = new Stack(); private StringDictionary _stringDictionary = new StringDictionary(); // Keep track of the last parsed args as an array private string[] _lastparsedArgs = null; #endregion #region Construction /// /// The Command Line Class needs to know what Options and Flags to Parse for /// /// Pass an Enum used to determine CommandLine Options /// Pass an Enum used to determine CommandLine Flags public CMDline(Type Enum_CMDLineOptions, Type Enum_CMDLineFlags) { if (Enum_CMDLineOptions.IsEnum && Enum_CMDLineFlags.IsEnum) { _CMDLineOptions = Enum_CMDLineOptions; _CMDLineFlags = Enum_CMDLineFlags; } else throw new ArgumentException("Both CMDLineOptions and CMDLineFlags must be Enums"); } #endregion #region Public Properties /// /// True if User Passed in any Parameters /// public bool HasParams { get { return (_stringDictionary.Count >= 1); } } /// /// True if User requested Command-Line Help /// public bool ShowHelp { get { return GetFlagOrOptionValueBool(HELP_FLAG_SPECIFIER); } } /// /// True if all Parameters parsed are valid, False otherwise /// public bool ParamsValid { get { if (!HasParams) return true; string[] OptionNames = Enum.GetNames(_CMDLineOptions); string[] FlagNames = Enum.GetNames(_CMDLineFlags); // Get All Flags and Options List AllFlagsAndOptions = new List(); foreach (string Option in OptionNames) AllFlagsAndOptions.Add(Option.ToLower()); foreach (string Flag in FlagNames) AllFlagsAndOptions.Add(Flag.ToLower()); // Verify the Parameters bool InvalidParamFound = false; foreach (string key in _stringDictionary.Keys) { InvalidParamFound = (key != HELP_FLAG_SPECIFIER) && !AllFlagsAndOptions.Contains(key); if (InvalidParamFound) break; } return !InvalidParamFound; } } #endregion #region Public Methods /// /// Main Entry Function to Retrieve an Option Value /// /// Should be a System Type like string, bool, int32, double, decimal, etc... /// option to retrieve (From CMDLineOptions Enum) /// Default value to use if nothing was retrieved * Error occured * /// value or default value, if not found public T GetOptionValue(Enum option, T DefaultValue) { T RetVal = DefaultValue; string StringVal = GetFlagOrOptionValueStr(option.ToString()); try { if (ObjTool.IsNotNullAndNotEmpty(StringVal)) { RetVal = ObjTool.ConvertStringToObj(StringVal); } } catch (Exception) { /* ignore */ } return RetVal; } /// /// Main Entry Function to Retrieve a Flag Value /// /// flag enum to retrieve (From CMDLineFlags Enum) /// Bool Value found or false if not found public bool GetFlagValue(Enum flag) { return GetFlagOrOptionValueBool(flag.ToString()); } /// /// Returns the Last Parsed Arguments as a string /// /// returns last parsed args or String.Empty if none public string ParsedArgs() { if (_lastparsedArgs != null && _lastparsedArgs.Length > 0) { StringBuilder sb = new StringBuilder(); foreach (string s in _lastparsedArgs) { sb.Append(s); sb.Append(" "); } sb.Remove(sb.Length - 1, 1); // remove trailing " " return sb.ToString(); } return string.Empty; } #endregion #region Private Helper Functions /// /// Main Function used to Retrieve a String Value /// /// Flag or Option to get Value for /// Value or Empty if not found private string GetFlagOrOptionValueStr(string FlagOrOption) { // If there is a FLAG_OR_OPTION_CHARS, stripe it if (IsFlagOrOption(FlagOrOption)) FlagOrOption = GetFlagOrOption(FlagOrOption); FlagOrOption = FlagOrOption.ToLower(); if (_stringDictionary.ContainsKey(FlagOrOption)) return _stringDictionary[FlagOrOption]; return String.Empty; } /// /// Main Function used to Retrieve a Bool Value /// /// Flag or Option to get Value for /// True or False if not found private bool GetFlagOrOptionValueBool(string FlagOrOption) { try { string Value = GetFlagOrOptionValueStr(FlagOrOption); if (!String.IsNullOrEmpty(Value)) { bool bValue = bool.Parse(Value); return bValue; } } catch (Exception) { /*Ignore*/ } return false; } #endregion #region Parsing Methods /// true if the param is a flag or option private bool IsFlagOrOption(string arg) { return (FLAG_OR_OPTION_SPECIFIER.Contains(arg[0].ToString())); } /// the Value of a Param private string GetFlagOrOption(string arg) { return arg.Substring(1); } /// /// Main Entry Function used to Parse CommandLine parameters /// /// command line arguments /// true if any parsing occured, false otherwise public bool Parse(string[] args) { return Parse(args, true); } /// /// Main Entry Function used to Parse CommandLine parameters /// /// command line arguments /// Allows you to not parse Options as True, if in case the option is blank it will just be considered a blank option/flag /// true if any parsing occured, false otherwise public bool Parse(string[] args, bool bAlwaysParseOptionsAsTrue) { if (args == null || args.Length <= 0) return false; _stringDictionary.Clear(); _stringStack.Clear(); _lastparsedArgs = args; foreach (string arg in args) { if (!String.IsNullOrEmpty(arg)) { if (IsFlagOrOption(arg)) { _stringStack.Push(GetFlagOrOption(arg).ToLower()); if (bAlwaysParseOptionsAsTrue) _stringDictionary[GetFlagOrOption(arg).ToLower()] = "TRUE"; } else { // must have a flag or option on the stack, // if it does we use it if (_stringStack.Count >= 1) { _stringDictionary[_stringStack.Pop()] = Parse_ArgCleanup(arg); } } } } _stringStack.Clear(); return true; } /// /// Used only when cmd is constructed with (null, null), /// and the cmd.Parse function is called. will iterate thru the internal /// dictionary and stack and make sure that the command string / line items /// are valid /// /// public string MakeValidCmdStrFromNewlyParsedCmdLine() { StringBuilder sb = new StringBuilder(); foreach (string key in _stringDictionary.Keys) { sb.Append(FLAG_OR_OPTION_SPECIFIER[0]); sb.Append(MakeValidCmdStr(key)); sb.Append("="); sb.Append(_stringDictionary[key]); sb.Append(""); } foreach (string flag in _stringStack) { sb.Append(FLAG_OR_OPTION_SPECIFIER[0]); sb.Append(MakeValidCmdStr(flag)); sb.Append(""); } // remove trailing space sb = sb.Remove(sb.Length - 1, 1); return sb.ToString(); } /// /// It appears that the Command-Line can foul us up sometimes when passing /// certain arguments. This function deals with these special cases. /// /// arg to check/poss.clean up /// cleaned up arg, if needed private string Parse_ArgCleanup(string arg) { if (!String.IsNullOrEmpty(arg) && (arg.Length > 2) && (arg[arg.Length - 1] == '"')) // when passing a \ at the end of the command-line with a " { arg = arg.Remove(arg.Length - 1); arg += "\\"; } return arg; } #endregion #region Static Generate CmdLine Method /// /// Generates a CommandLine Parameter String from the Options/Flags Given /// /// StringDictionary that contains all the Options, to use /// List that contains all the Flags to use /// a string that can be passed via the commandLine public static string GenerateCmdLine(StringDictionary Options, List Flags) { string CmdLine = String.Empty; // Iterate Options, and add them if (Options != null && Options.Count > 0) { foreach (string Key in Options.Keys) { string cmdKey = MakeValidCmdStr(Key); string cmdValue = Options[Key]; CmdLine = CmdLine + FLAG_OR_OPTION_SPECIFIER[0] + cmdKey + " " + "\"" + cmdValue + "\"" + " "; } } // Iterate Flags, and add them if (Flags != null && Flags.Count > 0) { foreach (string Flag in Flags) { string cmdFlag = MakeValidCmdStr(Flag); CmdLine = CmdLine + FLAG_OR_OPTION_SPECIFIER[0] + cmdFlag + " "; } } // Return the generated Commmand Line return CmdLine; } /// /// Ensures Integrity with the Generated CMDLine string that Keys don't /// contain Illegal Characters /// /// a Key to make sure it is valid /// a valid Key private static string MakeValidCmdStr(string Key) { if (!String.IsNullOrEmpty(Key)) { //":\\ _!@#$%^&()-+{}[],.;`~"; Key = Key.Replace(" ", "_"); Key = Key.Replace(":", "_"); Key = Key.Replace("\\", "_"); Key = Key.Replace("/", "_"); Key = Key.Replace("!", "_"); Key = Key.Replace("@", "_"); Key = Key.Replace("#", "_"); Key = Key.Replace("$", "_"); Key = Key.Replace("%", "_"); Key = Key.Replace("^", "_"); Key = Key.Replace("&", "_"); Key = Key.Replace("(", "_"); Key = Key.Replace(")", "_"); Key = Key.Replace("-", "_"); Key = Key.Replace("+", "_"); Key = Key.Replace("{", "_"); Key = Key.Replace("}", "_"); Key = Key.Replace("[", "_"); Key = Key.Replace("]", "_"); Key = Key.Replace(",", "_"); Key = Key.Replace(".", "_"); Key = Key.Replace(";", "_"); Key = Key.Replace("'", "_"); Key = Key.Replace("~", "_"); return Key; } return String.Empty; } #endregion } }