/******************************************************************** * This file includes parser(s) to convert user's input from * shell interface to a data structure CommandContext * * TODO: a strong dependency is that we use VTR logging system *******************************************************************/ #include #include "vtr_assert.h" #include "vtr_log.h" #include "command_parser.h" /* Begin namespace openfpga */ namespace openfpga { /******************************************************************** * Try to find an option in the command and update the CommandContext if needed *******************************************************************/ static CommandOptionId parse_option(const std::string& argv, const Command& cmd, CommandContext& cmd_context) { CommandOptionId option_id = cmd.option(argv); /* Not found, error out */ if (CommandOptionId::INVALID() == option_id) { VTR_LOG("Detect unknown option '--%s'!\n", argv.c_str()); return CommandOptionId::INVALID(); } /* Found, update the CommandContext */ cmd_context.set_option(cmd, option_id, true); return option_id; } /******************************************************************** * Try to find a short option in the command * Update the CommandContext if needed *******************************************************************/ static CommandOptionId parse_short_option(const std::string& argv, const Command& cmd, CommandContext& cmd_context) { CommandOptionId option_id = cmd.short_option(argv); /* Not found, error out */ if (CommandOptionId::INVALID() == option_id) { VTR_LOG("Detect unknown short option '-%s'!\n", argv.c_str()); return CommandOptionId::INVALID(); } /* Found, update the CommandContext */ cmd_context.set_option(cmd, option_id, true); return option_id; } /******************************************************************** * Main parser to convert user's input from * shell interface to a data structure CommandContext *******************************************************************/ bool parse_command(const std::vector& argv, const Command& cmd, CommandContext& cmd_context) { /* We at least expect 1 arguement, which is the command name itself */ VTR_ASSERT(1 <= argv.size()); /* Validate that the command name matches argv[0] */ if (argv[0] != cmd.name()) { VTR_LOG("Unexpected command name '%s'!\n", argv[0]); return false; } /* Start from argv[1], the 1st argv is programme name */ for (size_t iarg = 1; iarg < argv.size(); ++iarg) { /* Option must start with dash */ if (0 != strncmp("-", argv[iarg].c_str(), 1)) { VTR_LOG("Invalid option '%s'!\n", argv[iarg].c_str()); return false; } /* First try to process a full option * which always starts with double dash '--' */ if (0 == strncmp("--", argv[iarg].c_str(), 2)) { /* See if there is a option defined in the command object * Note that the first two characters are skipped when searching the name */ CommandOptionId option_id = parse_option(argv[iarg].substr(2), cmd, cmd_context); if (CommandOptionId::INVALID() == option_id) { return false; } /* If the option requires a value, we visit the next argument */ if (true == cmd.option_require_value(option_id)) { ++iarg; /* If this is the last arugment, we finish */ if (iarg == argv.size()) { break; } cmd_context.set_option_value(cmd, option_id, argv[iarg]); } /* Finish this iteration here, we found something */ continue; } /* Second try to process a short option * which always starts with double dash '-' */ if (0 == strncmp("-", argv[iarg].c_str(), 1)) { /* See if there is a option defined in the command object * Note that the first two characters are skipped when searching the name */ CommandOptionId option_id = parse_short_option(argv[iarg].substr(1), cmd, cmd_context); if (CommandOptionId::INVALID() == option_id) { return false; } /* If the option requires a value, we visit the next argument */ if (true == cmd.option_require_value(option_id)) { ++iarg; /* If this is the last arugment, we finish */ if (iarg == argv.size()) { break; } cmd_context.set_option_value(cmd, option_id, argv[iarg]); } /* Finish this iteration here, we found something */ continue; } } /* Ensure that all the required options have been satisfied * If not, we echo the details about what are missing */ std::vector missing_options = cmd_context.check_required_options(cmd); if (!missing_options.empty()) { for (const CommandOptionId& missing_opt : missing_options) { VTR_LOG("Required option '%s' is missing!\n", cmd.option_name(missing_opt).c_str()); } return false; } std::vector missing_value_options = cmd_context.check_required_option_values(cmd); if (!missing_value_options.empty()) { bool parse_fail = false; for (const CommandOptionId& missing_opt : missing_value_options) { /* If the missing option is not enabled, we can skip this option */ if (false == cmd_context.option_enable(cmd, missing_opt)) { continue; } VTR_LOG("Require value for option '%s' is missing!\n", cmd.option_name(missing_opt).c_str()); parse_fail = true; } return !parse_fail; } return true; } } /* End namespace openfpga */