2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-11-02 11:46:35 +00:00

Refactor arg parsing to allow help option with parameter

This commit is contained in:
Jay Berkenbilt 2021-12-29 13:09:51 -05:00
parent 1c420e852c
commit ac0060ac38

View File

@ -926,7 +926,6 @@ class ArgParser
void usage(std::string const& message); void usage(std::string const& message);
void checkCompletion(); void checkCompletion();
void initOptionTable(); void initOptionTable();
void handleHelpArgs();
void handleArgFileArguments(); void handleArgFileArguments();
void handleBashArguments(); void handleBashArguments();
void readArgsFromFile(char const* filename); void readArgsFromFile(char const* filename);
@ -3411,37 +3410,6 @@ ArgParser::readArgsFromFile(char const* filename)
} }
} }
void
ArgParser::handleHelpArgs()
{
// Handle special-case informational options that are only
// available as the sole option.
if (argc != 2)
{
return;
}
char* arg = argv[1];
if (*arg != '-')
{
return;
}
++arg;
if (*arg == '-')
{
++arg;
}
if (! *arg)
{
return;
}
if (this->help_option_table.count(arg))
{
(this->*(this->help_option_table[arg].bare_arg_handler))();
exit(0);
}
}
void void
ArgParser::parseRotationParameter(std::string const& parameter) ArgParser::parseRotationParameter(std::string const& parameter)
{ {
@ -3601,22 +3569,23 @@ void
ArgParser::parseOptions() ArgParser::parseOptions()
{ {
checkCompletion(); checkCompletion();
if (! this->bash_completion)
{
handleHelpArgs();
}
handleArgFileArguments(); handleArgFileArguments();
for (cur_arg = 1; cur_arg < argc; ++cur_arg) for (cur_arg = 1; cur_arg < argc; ++cur_arg)
{ {
bool help_option = false;
auto oep = this->option_table->end();
char* arg = argv[cur_arg]; char* arg = argv[cur_arg];
char* parameter = nullptr;
std::string o_arg(arg);
std::string arg_s(arg);
if (strcmp(arg, "--") == 0) if (strcmp(arg, "--") == 0)
{ {
// Special case for -- option, which is used to break out // Special case for -- option, which is used to break out
// of subparsers. // of subparsers.
OptionEntry& oe = (*this->option_table)["--"]; oep = this->option_table->find("--");
if (oe.bare_arg_handler) if (oep == this->option_table->end())
{ {
(this->*(oe.bare_arg_handler))(); throw std::logic_error("ArgParser: -- handler not registered");
} }
} }
else if ((arg[0] == '-') && (strcmp(arg, "-") != 0)) else if ((arg[0] == '-') && (strcmp(arg, "-") != 0))
@ -3627,7 +3596,6 @@ ArgParser::parseOptions()
// Be lax about -arg vs --arg // Be lax about -arg vs --arg
++arg; ++arg;
} }
char* parameter = 0;
if (strlen(arg) > 0) if (strlen(arg) > 0)
{ {
// Prevent --=something from being treated as an empty // Prevent --=something from being treated as an empty
@ -3640,72 +3608,82 @@ ArgParser::parseOptions()
*parameter++ = 0; *parameter++ = 0;
} }
std::string arg_s(arg); arg_s = arg;
if (arg_s.empty() || if (! (arg_s.empty() || (arg_s.at(0) == '-')))
(arg_s.at(0) == '-') ||
(0 == this->option_table->count(arg_s)))
{ {
usage(std::string("unknown option --") + arg); oep = this->option_table->find(arg_s);
} }
OptionEntry& oe = (*this->option_table)[arg_s]; if ((! this->bash_completion) &&
if ((oe.parameter_needed && (0 == parameter)) || (argc == 2) && (cur_arg == 1) &&
((! oe.choices.empty() && (oep == this->option_table->end()))
((0 == parameter) ||
(0 == oe.choices.count(parameter))))))
{ {
std::string message = // Handle help option, which is only valid as the sole
"--" + arg_s + " must be given as --" + arg_s + "="; // option.
if (! oe.choices.empty()) oep = this->help_option_table.find(arg_s);
{ help_option = true;
QTC::TC("qpdf", "qpdf required choices");
message += "{";
for (std::set<std::string>::iterator iter =
oe.choices.begin();
iter != oe.choices.end(); ++iter)
{
if (iter != oe.choices.begin())
{
message += ",";
}
message += *iter;
}
message += "}";
}
else if (! oe.parameter_name.empty())
{
QTC::TC("qpdf", "qpdf required parameter");
message += oe.parameter_name;
}
else
{
// should not be possible
message += "option";
}
usage(message);
}
if (oe.bare_arg_handler)
{
(this->*(oe.bare_arg_handler))();
}
else if (oe.param_arg_handler)
{
(this->*(oe.param_arg_handler))(parameter);
}
}
else if (0 != this->option_table->count(""))
{
// The empty string maps to the positional argument
// handler.
OptionEntry& oe = (*this->option_table)[""];
if (oe.param_arg_handler)
{
(this->*(oe.param_arg_handler))(arg);
} }
} }
else else
{ {
usage(std::string("unknown argument ") + arg); // The empty string maps to the positional argument
// handler.
oep = this->option_table->find("");
parameter = arg;
}
if (oep == this->option_table->end())
{
usage("unrecognized argument " + o_arg);
}
OptionEntry& oe = oep->second;
if ((oe.parameter_needed && (0 == parameter)) ||
((! oe.choices.empty() &&
((0 == parameter) ||
(0 == oe.choices.count(parameter))))))
{
std::string message =
"--" + arg_s + " must be given as --" + arg_s + "=";
if (! oe.choices.empty())
{
QTC::TC("qpdf", "qpdf required choices");
message += "{";
for (std::set<std::string>::iterator iter =
oe.choices.begin();
iter != oe.choices.end(); ++iter)
{
if (iter != oe.choices.begin())
{
message += ",";
}
message += *iter;
}
message += "}";
}
else if (! oe.parameter_name.empty())
{
QTC::TC("qpdf", "qpdf required parameter");
message += oe.parameter_name;
}
else
{
// should not be possible
message += "option";
}
usage(message);
}
if (oe.bare_arg_handler)
{
(this->*(oe.bare_arg_handler))();
}
else if (oe.param_arg_handler)
{
(this->*(oe.param_arg_handler))(parameter);
}
if (help_option)
{
exit(0);
} }
} }
if (this->bash_completion) if (this->bash_completion)