示例#1
0
        public bool ParseAndContinue(string[] args)
        {
            string err = "";

            try
            {
                object[]             attribs = GetType().GetCustomAttributes(typeof(ParserUsageAttribute), true);
                ParserUsageAttribute parser  = (ParserUsageAttribute)(attribs.Length != 0 ? attribs[0] : null);

                //TODO relying on exception being generated last (i.e. after values have been read and assigned) should pass param
                //Load defaults from the environmental variable
                if (parser != null)
                {
                    if ("" != parser.EnvironmentDefaults)
                    {
                        try{ Parse(Environment.GetEnvironmentVariable(parser.EnvironmentDefaults)); }catch {}
                    }
                }
                //--------------------------------------------------------

                //Parse the command line
                Parse(args);
            }
            catch (Exception e) { err = e.Message; }
            return(Continue(err));
        }
示例#2
0
        void Parse(string[] args, bool ignoreFirstArg)
        {
            object[]             attribs = GetType().GetCustomAttributes(typeof(ParserUsageAttribute), true);
            ParserUsageAttribute parser  = (ParserUsageAttribute)(attribs.Length != 0 ? attribs[0] : null);
            bool allowArgFile            = (parser != null ? parser.AllowArgumentFile : true);

            MemberInfoUsage[] members = GetMembers();

            for (int i = (ignoreFirstArg ? 1 : 0); i != args.Length; ++i)
            {
                string arg = args[i];
                Debug.WriteLine("Processing arg: " + arg);

                MemberInfoUsage member = null;
                bool            isFlag = false;

                // It's a flag
                if ((arg.Length > 1) && ((arg[0] == '/') || (arg[0] == '-')))
                {
                    bool   hasOnOff;
                    string flagName;


                    // Flags can have a '+' or '-' suffix. If this arg has a prefix remove it,
                    // else just remove the '/' or '-'
                    hasOnOff = arg.EndsWith("-") || arg.EndsWith("+");
                    if (hasOnOff)
                    {
                        flagName = arg.Substring(1, arg.Length - 2);
                    }
                    else
                    {
                        flagName = arg.Substring(1);
                    }


                    // Flags can be passed in one of two ways
                    //  a) With a param name in 1 arg and a value in the next. e.g. "/flag myValue"
                    //  b) Using a delimiter, passed as a single argument. e.g. "/flag:myValue"
                    // If using the single arg (a) method extract the arg name
                    int delimiterPos = FindValueInlineDeliminter(flagName);


                    //default delimiter. A space which is not a delimiter (space delimted values are split into seperate args)
                    // will thus have a delimiter value of '\0'
                    char delimiter = '\0';
                    if (delimiterPos != -1)
                    {
                        delimiter = flagName[delimiterPos];
                        flagName  = flagName.Substring(0, delimiterPos);
                    }

                    // Find the argument by name
                    member = FindFlag(flagName);

                    if (member != null)
                    {
                        isFlag = true;


                        //OnOff toggle only allowed if: member.usage is FlagUsage and FlagUsage.AllowOnOff is true
                        if (hasOnOff)
                        {
                            FlagUsageAttribute flag = member.usage as FlagUsageAttribute;

                            if (null == flag)
                            {
                                throw new UsageException(arg, "Only flags support on/off toggles");
                            }
                            else if (!flag.AllowOnOff)
                            {
                                throw new UsageException(arg, "Flag does not allow on/off toggle");
                            }
                        }


                        //Check that only value args have a delimiter and that the correct delimiter has been used
                        if (member.usage is ValueUsageAttribute)
                        {
                            ValueUsageAttribute val = (ValueUsageAttribute)member.usage;

                            switch (delimiter)
                            {
                            case ':':  if (0 == (val.Delimiters & ValueDelimiters.Colon))
                                {
                                    throw new UsageException(arg, "This value param does not support a ':' delimiter");
                                }
                                break;

                            case '=':  if (0 == (val.Delimiters & ValueDelimiters.Equals))
                                {
                                    throw new UsageException(arg, "This value param does not support a '=' delimiter");
                                }
                                break;

                            case '\0': if (0 == (val.Delimiters & ValueDelimiters.Space))
                                {
                                    throw new UsageException(arg, "This value param does not support a ' ' delimiter");
                                }
                                break;

                            default: throw new UsageException(arg, "Unknown delimiter");
                            }
                        }
                        else if ('\0' != delimiter)
                        {
                            throw new UsageException(arg, "Only value params support delimiters");
                        }
                    }
                }
                // It's a file name to process parameters from
                else if ((arg.Length > 1) && (arg[0] == '@') && allowArgFile)
                {
                    ParseFromFile(arg.Substring(1));
                    continue;
                }
                // It's a parameter
                else
                {
                    // Find the argument by offset
                    member = GetNextParam();
                }

                if (member == null)
                {
                    throw new UsageException(arg, "Unrecognized argument");
                }

                // Argument with a value, e.g. /foo bar
                if (member.usage.ExpectsValue)
                {
                    string value;


                    // If the arg has an inline delimiter (e.g. "/flag:myValue")
                    // then read the value from the current arg else get the value from the next arg
                    int delimiterPos = FindValueInlineDeliminter(arg);
                    if (delimiterPos == -1)
                    {
                        if (isFlag && (++i == args.Length))
                        {
                            throw new UsageException(arg, "Argument expects a parameter");
                        }
                        value = args[i];
                    }
                    else
                    {
                        if ((arg.Length - 1) == delimiterPos)
                        {
                            throw new UsageException(arg, "Argument expects a paramter");
                        }
                        value = arg.Substring(delimiterPos + 1);
                    }

                    member.usage.ConsumeValue(value, this, member.info);
                }
                // Argument w/o a value, e.g. /foo
                else
                {
                    string value;

                    if (isFlag && arg.EndsWith("-"))
                    {
                        value = "false";
                    }
                    else
                    {
                        value = "true";
                    }

                    member.usage.ConsumeValue(value, this, member.info);
                }
            }

            // Check for missing required arguments
            foreach (MemberInfoUsage member in members)
            {
                if (!member.usage.Optional && !member.usage.IsFound)
                {
                    throw new UsageException(member.info.Name, "Required argument not found");
                }
            }
        }
示例#3
0
        public string GetUsage(string err)
        {
            StringBuilder usage = new StringBuilder();

            // Logo
            string logo = GetLogo(true);

            if (logo.Length != 0)
            {
                usage.Append(logo).Append(Environment.NewLine);
            }

            // Parser prefs, e.g. preferred prefix
            object[]             attribs = GetType().GetCustomAttributes(typeof(ParserUsageAttribute), true);
            ParserUsageAttribute parser  = (ParserUsageAttribute)(attribs.Length != 0 ? attribs[0] : null);
            string preferredPrefix       = (parser != null ? parser.PreferredPrefix : "/");
            bool   allowArgFile          = (parser != null ? parser.AllowArgumentFile : true);

            // Error string
            if (err.Length != 0)
            {
                usage.Append(err).Append(Environment.NewLine).Append(Environment.NewLine);
            }

            // Short (name and value name only)
            StringBuilder shortUsage = new StringBuilder();

            shortUsage.Append("Usage: ").Append(GetModuleName()).Append(" ");

            // Long (name and description only)
            StringBuilder longUsage = new StringBuilder();

            // TODO there must be a better way of doing this than looping through the MemberInfo...
            // Find the right-most tab char.
            int maxTabPos = 0;

            foreach (MemberInfoUsage member in GetMembers())
            {
                string prefix       = (member.usage.MatchPosition ? "" : preferredPrefix);
                string tmpLongUsage = member.usage.GetLongUsage(prefix, member.info.Name, this, member.info);
                maxTabPos = Math.Max(maxTabPos, tmpLongUsage.IndexOf("\t"));
            }

            // There should be 2 chars after the longest usage, before its description
            maxTabPos += 2;

            // Max length for the descriptions
            int maxLen = ((null != parser) ? parser.MaxHelpLineLength : 79) - maxTabPos;

            if (allowArgFile)
            {
                shortUsage.Append("[@argfile]");
                //TODO format line using FormatSingleLineMaxChars
                longUsage.AppendFormat("{0,-" + maxTabPos + ":S}{1}", "@argfile", "Read arguments from a file.").Append(Environment.NewLine);
            }

            //Regex to split line into usage and description
            Regex regexUsage = new Regex(@"(?s)^(?<usage>[^\t]+)(\t)(?<desc>.*)$");

            string lastCategory = "";

            foreach (MemberInfoUsage member in GetMembers())
            {
                // NOTE: When matching by position, only the value will be present
                // on the commandline, e.g. "fooness"
                string prefix = (member.usage.MatchPosition ? "" : preferredPrefix);

                shortUsage.Append(" ").Append(member.usage.GetShortUsage(prefix, member.info.Name, this, member.info));

                // Get the long usage, which must be of the format usage\tdescription
                // Where
                //   1) usage may not contain any tabs
                //   2) description can be any length and may contain \n or \r\n chars to indicate a newline
                string tmpLongUsage = member.usage.GetLongUsage(prefix, member.info.Name, this, member.info);

                // Replace all \r chars
                Match m = regexUsage.Match(tmpLongUsage);

                if (null != m)
                {
                    // If categories are being displayed and the category has changed then display the category
                    // An empty category is not concidered to be a category change
                    if ((null != parser) && (parser.ShowCategories) && (0 != member.usage.Category.Length) && (member.usage.Category != lastCategory))
                    {
                        longUsage.Append(Environment.NewLine).AppendFormat("{0,-" + maxTabPos + ":S}- {1} -", "", member.usage.Category).Append(Environment.NewLine);
                        lastCategory = member.usage.Category;
                    }

                    // Usage
                    longUsage.AppendFormat("{0,-" + maxTabPos + ":S}", m.Groups["usage"].Value);

                    // Format the string to fit the max line length
                    string[] formattedLines = FormatMultiLineMaxChars(maxLen, m.Groups["desc"].Value);

                    if (formattedLines.Length > 0)
                    {
                        longUsage.Append(formattedLines[0]).Append(Environment.NewLine);
                    }
                    else
                    {
                        longUsage.Append(Environment.NewLine);
                    }

                    for (int g = 1; g < formattedLines.Length; ++g)
                    {
                        longUsage.AppendFormat("{0,-" + maxTabPos + ":S}{1}", "", formattedLines[g]).Append(Environment.NewLine);
                    }
                }
            }

            //Format the short usage
            string[] shortLines = FormatMultiLineMaxChars(((null != parser) ? parser.MaxHelpLineLength : 79), shortUsage.ToString());
            shortUsage.Length = 0;

            if (shortLines.Length > 0)
            {
                shortUsage.Append(shortLines[0]).Append(Environment.NewLine);
            }
            else
            {
                shortUsage.Append(Environment.NewLine);
            }

            //subsequent short usage lines to align up under "Usage: " string
            for (int g = 1; g < shortLines.Length; ++g)
            {
                shortUsage.AppendFormat("{0,-7:S}{1}", "", shortLines[g]).Append(Environment.NewLine);
            }

            usage.Append(shortUsage).Append(Environment.NewLine).Append(Environment.NewLine).Append(longUsage).Append(Environment.NewLine);

            if ((null != parser) && ("" != parser.EnvironmentDefaults))
            {
                usage.Append(Environment.NewLine);
                usage.AppendFormat("Switches may be preset in the {0} environment variable.", parser.EnvironmentDefaults).Append(Environment.NewLine);
                usage.Append("Override preset switches by prefixing switches with a - (hyphen)").Append(Environment.NewLine);
                usage.Append(" for example, /W-").Append(Environment.NewLine);
            }
            return(usage.ToString());
        }
示例#4
0
        protected virtual string GetLogo(bool includeDescription)
        {
            // TODO: Refactor this ugly code!
            StringBuilder logo = new StringBuilder();
            string        nl   = Environment.NewLine;

            object[] attribs = null;

            Assembly assem = Assembly.GetEntryAssembly();

            if (null == assem)
            {
                assem = System.Reflection.Assembly.GetExecutingAssembly();
            }
            AssemblyName assemName = assem.GetName();

            // Title: try AssemblyTitle first, use module name if AssemblyTitle is missing
            attribs = assem.GetCustomAttributes(typeof(AssemblyTitleAttribute), true);
            string title = (attribs.Length != 0 ? ((AssemblyTitleAttribute)attribs[0]).Title : "");

            if (title.Length == 0)
            {
                title = GetModuleName();
            }

            // Version
            string version = assem.GetName().Version.ToString();

            // Copyright
            attribs = assem.GetCustomAttributes(typeof(AssemblyCopyrightAttribute), true);
            string copyright = (attribs.Length != 0 ? ((AssemblyCopyrightAttribute)attribs[0]).Copyright : "");

            // Description: Try ParserUsage.Description first, use AssemblyDescription otherwise
            string description = "";

            attribs = GetType().GetCustomAttributes(typeof(ParserUsageAttribute), true);
            ParserUsageAttribute parser = (ParserUsageAttribute)(attribs.Length != 0 ? attribs[0] : null);

            if ((parser != null) && (parser.Description != null) && (parser.Description.Length != 0))
            {
                description = parser.Description;
            }
            else
            {
                attribs     = assem.GetCustomAttributes(typeof(AssemblyDescriptionAttribute), true);
                description = (attribs.Length != 0 ? ((AssemblyDescriptionAttribute)attribs[0]).Description : "");
            }

            // Layout
            logo.Append(title).Append(" v").Append(version).Append(nl);

            if (copyright.Length != 0)
            {
                logo.Append(copyright).Append(nl);
            }

            if (!string.IsNullOrEmpty(description) && includeDescription)
            {
                logo.Append(description).Append(nl);
            }

            return(logo.ToString());
        }