OpenFPGA/libopenfpga/libopenfpgashell/src/command_parser.cpp

166 lines
5.7 KiB
C++

/********************************************************************
* 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 <cstring>
#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<std::string>& 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<CommandOptionId> 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<CommandOptionId> 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 */