Ejemplo n.º 1
0
        private bool ParseArgument(string token, IDevCommand command, List <Argument> args, ref int argsFound)
        {
            if (argsFound < args.Count)
            {
                args[argsFound].IsPresent = true;

                Type t = args[argsFound].ArgType;

                object value = null;
                if (token.StringToValueOfType(t, ref value, true) == false)
                {
                    return(false);
                }

                args[argsFound].Value = value;

                argsFound++;
            }
            else
            {
                Debug.Log("Error:  Too many arguments (maximum " + args.Count + "), when \"" + token + "\" encountered\n");
                return(false);
            }
            return(true);
        }
Ejemplo n.º 2
0
        public void UnregisterDevCommand(IDevCommand devCmd)
        {
            var lowerCaseKey = devCmd.Name.ToLower( );

            if (!DevCommands.ContainsKey(lowerCaseKey))
            {
                throw new Exception("UnregisterDevCommand:  Dev command " + lowerCaseKey + " not registered");
            }

            DevCommands.Remove(lowerCaseKey);
        }
Ejemplo n.º 3
0
        public void RegisterDevCommand(IDevCommand devCmd)
        {
            if (!GenerateArgSpec(devCmd))
            {
                throw new Exception("Problem in dev command argument spec generation");
            }

            if (!ValidateArgumentSpec(devCmd))
            {
                throw new Exception("Problem in dev command argument spec validation");
            }

            var lowerCaseKey = devCmd.Name.ToLower( );

            if (DevCommands.ContainsKey(lowerCaseKey))
            {
                throw new Exception("RegisterDevCommand:  Dev command " + lowerCaseKey + " already registered");
            }

            DevCommands[lowerCaseKey] = devCmd;
        }
Ejemplo n.º 4
0
        private bool ValidateArgumentSpec(IDevCommand command)
        {
            bool optionalArgFound = false;

            foreach (var arg in command.Arguments)
            {
                if (!arg.IsRequired)
                {
                    optionalArgFound = true;
                }
                else if (optionalArgFound)
                {
                    Debug.Log("Error in argument specification for command \"" + command.Name + "\":  Any optional arguments must come AFTER non-optional arguments\n");
                    return(false);
                }
            }

            foreach (var option in command.Options)
            {
                optionalArgFound = false;
                foreach (var arg in option.Arguments)
                {
                    if (!arg.IsRequired)
                    {
                        optionalArgFound = true;
                    }
                    else if (optionalArgFound)
                    {
                        Debug.Log("Error in argument specification for command \"" + command.Name + "\":  Any optional arguments must come AFTER non-optional arguments\n");
                        return(false);
                    }
                }
            }

            return(true);
        }
Ejemplo n.º 5
0
        private bool ParseDevCommandArguments(IDevCommand command, string rawArgsString)
        {
            foreach (var arg in command.Arguments)
            {
                arg.Value     = null;
                arg.IsPresent = false;
            }

            foreach (var opt in command.Options)
            {
                opt.IsPresent = false;
                foreach (var optionArg in opt.Arguments)
                {
                    optionArg.Value     = null;
                    optionArg.IsPresent = false;
                }
            }

            // Break the string into individual pieces (tokens), keeping quoted strings as one piece, and convert those preceded by "-" to lower case
            // Preserve spaces within quotes, when they appear any place within a space-delimited value, so:  ABC"Max Value"DEF   ...becomes...   ABCMax ValueDEF
            var tokens          = new List <Token>( );
            var remainingString = rawArgsString;

            while (remainingString.Length > 0)
            {
                remainingString = remainingString.TrimStart( );
                if (remainingString.Length > 0)
                {
                    //    log ABC"This is good" -count 5
                    // String now starts with a non-space; Look for first quote (if any), and first space (if any)
                    var quoteIndex = remainingString.IndexOf('"');
                    var spaceIndex = remainingString.IndexOf(' ');
                    if ((quoteIndex >= 0) &&
                        (spaceIndex < 0 || quoteIndex < spaceIndex))
                    {
                        var endQuoteIndex = remainingString.IndexOf('"', quoteIndex + 1);
                        if (endQuoteIndex < 0)
                        {
                            Debug.Log("Error:  Mismatched quotes\n");
                            return(false);
                        }
                        var sansQuotes = remainingString.Substring(0, quoteIndex);                                 // Any characters before the first quote mark
                        sansQuotes += remainingString.Substring(quoteIndex + 1, (endQuoteIndex - quoteIndex) - 1); // Characters between the quotes (removing the quotes)
                        var endIndex = remainingString.IndexOf(' ', endQuoteIndex);
                        if (endIndex < 0)
                        {
                            endIndex = remainingString.Length;
                        }
                        sansQuotes += remainingString.Substring(endQuoteIndex + 1, (endIndex - endQuoteIndex) - 1);   // Any characters after the second quote mark, up to a space or end of line
                        tokens.Add(new Token(sansQuotes, true));
                        if (endIndex >= (remainingString.Length - 1))
                        {
                            remainingString = string.Empty;
                        }
                        else
                        {
                            remainingString = remainingString.Substring(endIndex + 1, (remainingString.Length - endIndex) - 1);
                        }

                        continue;
                    }

                    if (spaceIndex < 0)
                    {
                        spaceIndex = remainingString.Length;
                    }
                    var nextWord = remainingString.Substring(0, spaceIndex);
                    if (nextWord.StartsWith("-"))
                    {
                        nextWord = nextWord.ToLower( );
                    }
                    tokens.Add(new Token(nextWord, false));
                    remainingString = remainingString.Substring(spaceIndex, (remainingString.Length - spaceIndex));
                }
            }

            // Main arguments must be in spec order.  Options can be in any order...but options must appear after all the main arguments.
            //    Also, options can have their own arguments, which within themselves must appear in spec order.
            var    mainArgsFound = 0;
            var    optArgsFound  = 0;
            Option curOption     = null;
            string curOptionName = null;

            MutuallyExclusiveGroupsFound.Clear();

            foreach (var tokenItem in tokens)
            {
                var token = tokenItem.token;

                if (token.StartsWith("-") && !tokenItem.wasQuoted)   // Is it an option or an argument?
                {
                    // Option:
                    var optionText = token.Substring(1);   // Strip hypen
                    var matchList  = command.Options.Where(e => e.Name.ToLower().Equals(optionText)).ToList();
                    if (matchList.Count > 0)
                    {
                        if (!AreAllRequiredOptionArgumentsPresent(curOption, curOptionName, optArgsFound))      // Error-check for the PREVIOUS option, if any
                        {
                            return(false);
                        }

                        curOption           = matchList[0];
                        curOption.IsPresent = true;
                        curOptionName       = token;

                        optArgsFound = 0;

                        if (!String.IsNullOrEmpty(curOption.MutualGroupName))
                        {
                            if (MutuallyExclusiveGroupsFound.ContainsKey(curOption.MutualGroupName))
                            {
                                Debug.Log("Error:  Option \"" + optionText + "\" cannot be used in the same command execution as option \"" + MutuallyExclusiveGroupsFound[curOption.MutualGroupName].Name + "\"; they are mutually exclusive");
                                return(false);
                            }
                            MutuallyExclusiveGroupsFound[curOption.MutualGroupName] = curOption;
                        }
                    }
                    else
                    {
                        Debug.Log("Error:  Option \"" + optionText + "\" not recognized\n");
                        return(false);
                    }
                }
                else
                {
                    if (curOption == null)
                    {
                        // Main argument:
                        if (!ParseArgument(token, command, command.Arguments, ref mainArgsFound))
                        {
                            return(false);
                        }
                    }
                    else
                    {
                        // Option argument:
                        if (!ParseArgument(token, command, curOption.Arguments, ref optArgsFound))
                        {
                            return(false);
                        }
                    }
                }
            }

            if (!AreAllRequiredOptionArgumentsPresent(curOption, curOptionName, optArgsFound))
            {
                return(false);
            }

            if (mainArgsFound < command.Arguments.Count)
            {
                if (command.Arguments[mainArgsFound].IsRequired)
                {
                    Debug.Log("Error:  Missing required main argument:  " + ArgumentTextDescription(command.Arguments[mainArgsFound]) + "\n");
                    return(false);
                }
            }

            return(true);
        }
Ejemplo n.º 6
0
        private bool GenerateArgSpec(IDevCommand command)
        {
            command.HelpTextFull = command.Name + " - " + command.HelpTextBrief + "\n";

            command.Arguments.Clear();
            command.Options.Clear();

            // NOTE:  Unfortunately, Microsoft says the order of members returned by "GetMembers" is indeterminate:  https://msdn.microsoft.com/en-us/library/424c79hc(v=vs.110).aspx
            // Currently I depend on the order they appear in the source file for 'order of arguments', at least for making optional arguments appear after IsRequired arguments.
            // potential solution:  Sort by 'IsRequired'.
            var argMembers = command.GetType()
                             .GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                             .Where(e => Attribute.IsDefined(e, typeof(DevCommandArgumentAttribute)));

            foreach (var m in argMembers)
            {
                if (m is PropertyInfo)
                {
                    var propertyInfo = m as PropertyInfo;
                    var argInstance  = propertyInfo.GetValue(command, null) as Argument;
                    command.Arguments.Add(argInstance);

                    command.HelpTextFull += "   " + (argInstance.IsRequired ? "" : "[") + ArgumentTextDescription(argInstance);
                    command.HelpTextFull += (argInstance.IsRequired ? "" : "]") + "\n";

                    if (argInstance.HelpText.Length > 0)
                    {
                        command.HelpTextFull += "    " + argInstance.HelpText + "\n";
                    }
                }
                else
                {
                    Debug.Log("Member found, not Property but " + m.MemberType + ": " + m.Name);
                    return(false);
                }
            }

            var optionMembers = command.GetType()
                                .GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                                .Where(e => Attribute.IsDefined(e, typeof(DevCommandOptionAttribute)));

            foreach (var m in optionMembers)
            {
                if (m is PropertyInfo)
                {
                    var propertyInfo   = m as PropertyInfo;
                    var optionInstance = propertyInfo.GetValue(command, null) as Option;
                    command.Options.Add(optionInstance);

                    command.HelpTextFull += "   -" + optionInstance.Name;

                    foreach (var optionArg in optionInstance.Arguments)
                    {
                        command.HelpTextFull += " " + (optionArg.IsRequired ? "" : "[") + ArgumentTextDescription(optionArg);
                        command.HelpTextFull += (optionArg.IsRequired ? "" : "]");
                    }
                    command.HelpTextFull += "\n";

                    if (optionInstance.HelpText.Length > 0)
                    {
                        command.HelpTextFull += "      " + optionInstance.HelpText + "\n";
                    }

                    foreach (var optionArg in optionInstance.Arguments)
                    {
                        if (optionArg.HelpText.Length > 0)
                        {
                            command.HelpTextFull += "      Note on " + optionArg.Name + ": " + optionArg.HelpText + "\n";
                        }
                    }
                }
                else
                {
                    Debug.Log("Member found, not Property but " + m.MemberType + ": " + m.Name);
                    return(false);
                }
            }

            return(true);
        }