// Here we set default commands, they do nothing since we quit with them // Quitting behaviour is hardcoded in readLine() Console::Console(std::string const& greeting) : pimpl_{ new Impl{ greeting } } { // Init readline basics rl_attempted_completion_function = &Console::getCommandCompletions; // These are other two hardcoded commands, but they are more readable // here rather than in the initialization list. // Help command lists available commands. pimpl_->commands_["help"] = [this](const std::vector<std::string>&){ auto commands = getRegisteredCommands(); std::cout << "Available commands are:\n"; for ( auto & command : commands ) std::cout << "\t" << command << "\n"; return 0; }; // Run command executes all commands in an external file. pimpl_->commands_["run"] = [this](const std::vector<std::string>& input) { if ( input.size() < 2 ) { std::cout << "Usage: " << input[0] << " script_filename\n"; return 1; } return executeFile(input[1]); }; }
/* * Execute is the main entry point for the framework. It parses the user's input, matches it * to the appropriate CommandSpec/Feature and then runs the feature, returning the Result from * the feature. */ cli::framework::ResultBase* cli::framework::Framework::execute(int argCount, const char* args[]) { Trace trace(__FILE__, __FUNCTION__, __LINE__); ResultBase *pResult = NULL; if (argCount > 0) { logger << "Executing: " << tokenArrayToString(argCount, args) << std::endl; // add help and output options CommandSpecList commands = getRegisteredCommands(); logger << "Commands to consider: " << commands.size() << std::endl; // convert user input into recognized tokens. Command List is needed because // it is used to know what verbs, targets, and properties are supported TokenList tokens = tokenize(argCount, args, commands); logger << "Tokenized input is: " << tokenArrayToString(tokens) << std::endl; SyntaxErrorResult *pError = NULL; // The parser will convert the list of tokens into a parsed command. It validates that the tokens // are in the proper order and will assign values to options, targets, and properties. Parser parser; pError = parser.parse(tokens); ParsedCommand parsedCommand = parser.getParsedCommand(); // The filter will take the parsedCommand and filter the possible commands, hopefully // leaving only one left to execute. UnknownProperty unknownProperty = parser.getUnknownProperty(); CommandFilter commandFilter(parsedCommand, unknownProperty); commandFilter.filter(commands); if (pError != NULL) { pResult = pError; if (parser.includePotentialCommandsIsRequested()) { pError->setPotentialCommands(commandFilter.getLastErasedCommands()); } } else { if (commands.size() == 1) // success ... 1 command to run { CommandVerify verify; pResult = verify.verify(parsedCommand, commands[0]); if (pResult == NULL) { // All good ... go, fight, win!! FeatureBase *pFeature = NULL; if (parsedCommand.options.find(OPTION_HELP.name) != parsedCommand.options.end()) { // Intercept feature if asking for help pFeature = new HelpFeature(commands[0]); } else { pFeature = getCommandFeature(commands[0]); } logger << "Executing: " << commands[0].asStr() << std::endl; pResult = pFeature->run(commands[0].id, parsedCommand); } } else if (commands.empty()) { logger << "No commands left. Setting potential commands with " << commandFilter.getLastErasedCommands().size() << " commands" << std::endl; pError = new ParseErrorResult(); pError->setPotentialCommands(commandFilter.getLastErasedCommands()); pResult = pError; } else if (commands.size() > 1) { // this only happens if there are two CommandSpecs with the same syntax pResult = new ErrorResult(ErrorResult::ERRORCODE_UNKNOWN, "The command list had more than one after filtering. This means that there might be more than one CommandSpec with the same required syntax."); logger << "The conflicting commands are: "; CommandSpecList::const_iterator iter = commands.begin(); for (; iter != commands.end(); iter++) { logger << "\"" + iter->asStr() << "\" "; } logger << std::endl; } } if (pResult != NULL) { pResult->setOutputOption(parser.getParsedCommand().options); } } else { pResult = HelpFeature().run(HelpFeature::HELP, (ParsedCommand){VERB_HELP}); } return pResult; }