aboutsummaryrefslogtreecommitdiffstats
path: root/libqpdf
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2022-01-07 21:29:27 +0100
committerJay Berkenbilt <ejb@ql.org>2022-01-30 19:11:03 +0100
commit53ba65eb59d0bced37e73d8bf96a0d7a7285f662 (patch)
tree29049c9c37ba25ea22313b83ac93e20a0a48b74b /libqpdf
parenta301cc5373f14fd03e51619b0bd5fad22b84e115 (diff)
downloadqpdf-53ba65eb59d0bced37e73d8bf96a0d7a7285f662.tar.zst
QPDFArgParser: handle optional choices including help
Handle optional choices in addition to required choices. Refactor the way help options are added to completion to make it work with optional help choices.
Diffstat (limited to 'libqpdf')
-rw-r--r--libqpdf/QPDFArgParser.cc84
-rw-r--r--libqpdf/QPDFJob_argv.cc3
-rw-r--r--libqpdf/qpdf/auto_job_decl.hh1
-rw-r--r--libqpdf/qpdf/auto_job_init.hh47
4 files changed, 74 insertions, 61 deletions
diff --git a/libqpdf/QPDFArgParser.cc b/libqpdf/QPDFArgParser.cc
index a24b00eb..f32b8759 100644
--- a/libqpdf/QPDFArgParser.cc
+++ b/libqpdf/QPDFArgParser.cc
@@ -35,6 +35,9 @@ QPDFArgParser::QPDFArgParser(int argc, char* argv[], char const* progname_env) :
m(new Members(argc, argv, progname_env))
{
selectHelpOptionTable();
+ char const* help_choices[] = {"all", 0};
+ addChoices(
+ "help", bindParam(&QPDFArgParser::argHelp, this), false, help_choices);
addBare("completion-bash",
std::bind(std::mem_fn(&QPDFArgParser::argCompletionBash), this));
addBare("completion-zsh",
@@ -139,13 +142,14 @@ QPDFArgParser::addOptionalParameter(
}
void
-QPDFArgParser::addRequiredChoices(
+QPDFArgParser::addChoices(
std::string const& arg,
param_arg_handler_t handler,
+ bool required,
char const** choices)
{
OptionEntry& oe = registerArg(arg);
- oe.parameter_needed = true;
+ oe.parameter_needed = required;
oe.param_arg_handler = handler;
for (char const** i = choices; *i; ++i)
{
@@ -254,6 +258,12 @@ QPDFArgParser::argCompletionZsh()
}
void
+QPDFArgParser::argHelp(char*)
+{
+ // QXXXQ
+}
+
+void
QPDFArgParser::handleArgFileArguments()
{
// Support reading arguments from files. Create a new argv. Ensure
@@ -624,10 +634,9 @@ QPDFArgParser::parseArgs()
}
OptionEntry& oe = oep->second;
- if ((oe.parameter_needed && (0 == parameter)) ||
- ((! oe.choices.empty() &&
- ((0 == parameter) ||
- (0 == oe.choices.count(parameter))))))
+ if ((oe.parameter_needed && (nullptr == parameter)) ||
+ ((! oe.choices.empty() && (nullptr != parameter) &&
+ (0 == oe.choices.count(parameter)))))
{
std::string message =
"--" + arg_s + " must be given as --" + arg_s + "=";
@@ -708,12 +717,13 @@ QPDFArgParser::doFinalChecks()
}
void
-QPDFArgParser::addChoicesToCompletions(std::string const& option,
+QPDFArgParser::addChoicesToCompletions(option_table_t& option_table,
+ std::string const& option,
std::string const& extra_prefix)
{
- if (this->m->option_table->count(option) != 0)
+ if (option_table.count(option) != 0)
{
- OptionEntry& oe = (*this->m->option_table)[option];
+ OptionEntry& oe = option_table[option];
for (std::set<std::string>::iterator iter = oe.choices.begin();
iter != oe.choices.end(); ++iter)
{
@@ -724,18 +734,16 @@ QPDFArgParser::addChoicesToCompletions(std::string const& option,
}
void
-QPDFArgParser::addOptionsToCompletions()
+QPDFArgParser::addOptionsToCompletions(option_table_t& option_table)
{
- for (std::map<std::string, OptionEntry>::iterator iter =
- this->m->option_table->begin();
- iter != this->m->option_table->end(); ++iter)
+ for (auto& iter: option_table)
{
- std::string const& arg = (*iter).first;
+ std::string const& arg = iter.first;
if (arg == "--")
{
continue;
}
- OptionEntry& oe = (*iter).second;
+ OptionEntry& oe = iter.second;
std::string base = "--" + arg;
if (oe.param_arg_handler)
{
@@ -743,7 +751,7 @@ QPDFArgParser::addOptionsToCompletions()
{
// zsh doesn't treat = as a word separator, so add all
// the options so we don't get a space after the =.
- addChoicesToCompletions(arg, base + "=");
+ addChoicesToCompletions(option_table, arg, base + "=");
}
this->m->completions.insert(base + "=");
}
@@ -755,6 +763,22 @@ QPDFArgParser::addOptionsToCompletions()
}
void
+QPDFArgParser::insertCompletions(option_table_t& option_table,
+ std::string const& choice_option,
+ std::string const& extra_prefix)
+{
+ if (! choice_option.empty())
+ {
+ addChoicesToCompletions(option_table, choice_option, extra_prefix);
+ }
+ else if ((! this->m->bash_cur.empty()) &&
+ (this->m->bash_cur.at(0) == '-'))
+ {
+ addOptionsToCompletions(option_table);
+ }
+}
+
+void
QPDFArgParser::handleCompletion()
{
std::string extra_prefix;
@@ -795,29 +819,17 @@ QPDFArgParser::handleCompletion()
}
}
}
- if (! choice_option.empty())
+ if (this->m->zsh_completion && (! choice_option.empty()))
{
- if (this->m->zsh_completion)
- {
- // zsh wants --option=choice rather than just choice
- extra_prefix = "--" + choice_option + "=";
- }
- addChoicesToCompletions(choice_option, extra_prefix);
+ // zsh wants --option=choice rather than just choice
+ extra_prefix = "--" + choice_option + "=";
}
- else if ((! this->m->bash_cur.empty()) &&
- (this->m->bash_cur.at(0) == '-'))
+ insertCompletions(*this->m->option_table, choice_option, extra_prefix);
+ if (this->m->argc == 1)
{
- addOptionsToCompletions();
- if (this->m->argc == 1)
- {
- // Help options are valid only by themselves.
- for (std::map<std::string, OptionEntry>::iterator iter =
- this->m->help_option_table.begin();
- iter != this->m->help_option_table.end(); ++iter)
- {
- this->m->completions.insert("--" + (*iter).first);
- }
- }
+ // Help options are valid only by themselves.
+ insertCompletions(
+ this->m->help_option_table, choice_option, extra_prefix);
}
}
std::string prefix = extra_prefix + this->m->bash_cur;
diff --git a/libqpdf/QPDFJob_argv.cc b/libqpdf/QPDFJob_argv.cc
index 0cf12cd4..9b678257 100644
--- a/libqpdf/QPDFJob_argv.cc
+++ b/libqpdf/QPDFJob_argv.cc
@@ -127,9 +127,11 @@ ArgParser::argCopyright()
<< std::endl;
}
+#if 0
void
ArgParser::argHelp()
{
+ // QXXXQ
std::cout
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
<< "Usage: qpdf [options] {infile | --empty} [page_selection_options] outfile\n"
@@ -630,6 +632,7 @@ ArgParser::argHelp()
<< "qpdf to completely ignore warnings. qpdf does not use exit status 1,\n"
<< "since that is used by the shell if it can't execute qpdf.\n";
}
+#endif
void
ArgParser::argJsonHelp()
diff --git a/libqpdf/qpdf/auto_job_decl.hh b/libqpdf/qpdf/auto_job_decl.hh
index 076a8f68..1f2b4263 100644
--- a/libqpdf/qpdf/auto_job_decl.hh
+++ b/libqpdf/qpdf/auto_job_decl.hh
@@ -12,7 +12,6 @@ static constexpr char const* O_UNDERLAY_OVERLAY = "underlay/overlay";
static constexpr char const* O_ATTACHMENT = "attachment";
static constexpr char const* O_COPY_ATTACHMENT = "copy attachment";
-void argHelp();
void argVersion();
void argCopyright();
void argJsonHelp();
diff --git a/libqpdf/qpdf/auto_job_init.hh b/libqpdf/qpdf/auto_job_init.hh
index 8566312f..3d7cdd7b 100644
--- a/libqpdf/qpdf/auto_job_init.hh
+++ b/libqpdf/qpdf/auto_job_init.hh
@@ -22,7 +22,6 @@ char const* print128_choices[] = {"full", "low", "none", 0};
char const* modify128_choices[] = {"all", "annotate", "form", "assembly", "none", 0};
this->ap.selectHelpOptionTable();
-this->ap.addBare("help", b(&ArgParser::argHelp));
this->ap.addBare("version", b(&ArgParser::argVersion));
this->ap.addBare("copyright", b(&ArgParser::argCopyright));
this->ap.addBare("json-help", b(&ArgParser::argJsonHelp));
@@ -99,38 +98,38 @@ this->ap.addRequiredParameter("remove-attachment", p(&ArgParser::argRemoveAttach
this->ap.addRequiredParameter("rotate", p(&ArgParser::argRotate), "[+|-]angle");
this->ap.addRequiredParameter("show-attachment", p(&ArgParser::argShowAttachment), "attachment");
this->ap.addRequiredParameter("show-object", p(&ArgParser::argShowObject), "trailer");
-this->ap.addRequiredChoices("compress-streams", p(&ArgParser::argCompressStreams), yn_choices);
-this->ap.addRequiredChoices("decode-level", p(&ArgParser::argDecodeLevel), decode_level_choices);
-this->ap.addRequiredChoices("flatten-annotations", p(&ArgParser::argFlattenAnnotations), flatten_choices);
-this->ap.addRequiredChoices("json-key", p(&ArgParser::argJsonKey), json_key_choices);
-this->ap.addRequiredChoices("keep-files-open", p(&ArgParser::argKeepFilesOpen), yn_choices);
-this->ap.addRequiredChoices("normalize-content", p(&ArgParser::argNormalizeContent), yn_choices);
-this->ap.addRequiredChoices("object-streams", p(&ArgParser::argObjectStreams), object_streams_choices);
-this->ap.addRequiredChoices("password-mode", p(&ArgParser::argPasswordMode), password_mode_choices);
-this->ap.addRequiredChoices("remove-unreferenced-resources", p(&ArgParser::argRemoveUnreferencedResources), remove_unref_choices);
-this->ap.addRequiredChoices("stream-data", p(&ArgParser::argStreamData), stream_data_choices);
+this->ap.addChoices("compress-streams", p(&ArgParser::argCompressStreams), true, yn_choices);
+this->ap.addChoices("decode-level", p(&ArgParser::argDecodeLevel), true, decode_level_choices);
+this->ap.addChoices("flatten-annotations", p(&ArgParser::argFlattenAnnotations), true, flatten_choices);
+this->ap.addChoices("json-key", p(&ArgParser::argJsonKey), true, json_key_choices);
+this->ap.addChoices("keep-files-open", p(&ArgParser::argKeepFilesOpen), true, yn_choices);
+this->ap.addChoices("normalize-content", p(&ArgParser::argNormalizeContent), true, yn_choices);
+this->ap.addChoices("object-streams", p(&ArgParser::argObjectStreams), true, object_streams_choices);
+this->ap.addChoices("password-mode", p(&ArgParser::argPasswordMode), true, password_mode_choices);
+this->ap.addChoices("remove-unreferenced-resources", p(&ArgParser::argRemoveUnreferencedResources), true, remove_unref_choices);
+this->ap.addChoices("stream-data", p(&ArgParser::argStreamData), true, stream_data_choices);
this->ap.registerOptionTable("pages", b(&ArgParser::argEndPages));
this->ap.addPositional(p(&ArgParser::argPagesPositional));
this->ap.addRequiredParameter("password", p(&ArgParser::argPagesPassword), "password");
this->ap.registerOptionTable("encryption", b(&ArgParser::argEndEncryption));
this->ap.addPositional(p(&ArgParser::argEncPositional));
this->ap.registerOptionTable("40-bit encryption", b(&ArgParser::argEnd40BitEncryption));
-this->ap.addRequiredChoices("extract", p(&ArgParser::argEnc40Extract), yn_choices);
-this->ap.addRequiredChoices("annotate", p(&ArgParser::argEnc40Annotate), yn_choices);
-this->ap.addRequiredChoices("print", p(&ArgParser::argEnc40Print), yn_choices);
-this->ap.addRequiredChoices("modify", p(&ArgParser::argEnc40Modify), yn_choices);
+this->ap.addChoices("extract", p(&ArgParser::argEnc40Extract), true, yn_choices);
+this->ap.addChoices("annotate", p(&ArgParser::argEnc40Annotate), true, yn_choices);
+this->ap.addChoices("print", p(&ArgParser::argEnc40Print), true, yn_choices);
+this->ap.addChoices("modify", p(&ArgParser::argEnc40Modify), true, yn_choices);
this->ap.registerOptionTable("128-bit encryption", b(&ArgParser::argEnd128BitEncryption));
this->ap.addBare("cleartext-metadata", b(&ArgParser::argEnc128CleartextMetadata));
this->ap.addBare("force-V4", b(&ArgParser::argEnc128ForceV4));
-this->ap.addRequiredChoices("accessibility", p(&ArgParser::argEnc128Accessibility), yn_choices);
-this->ap.addRequiredChoices("extract", p(&ArgParser::argEnc128Extract), yn_choices);
-this->ap.addRequiredChoices("print", p(&ArgParser::argEnc128Print), print128_choices);
-this->ap.addRequiredChoices("assemble", p(&ArgParser::argEnc128Assemble), yn_choices);
-this->ap.addRequiredChoices("annotate", p(&ArgParser::argEnc128Annotate), yn_choices);
-this->ap.addRequiredChoices("form", p(&ArgParser::argEnc128Form), yn_choices);
-this->ap.addRequiredChoices("modify-other", p(&ArgParser::argEnc128ModifyOther), yn_choices);
-this->ap.addRequiredChoices("modify", p(&ArgParser::argEnc128Modify), modify128_choices);
-this->ap.addRequiredChoices("use-aes", p(&ArgParser::argEnc128UseAes), yn_choices);
+this->ap.addChoices("accessibility", p(&ArgParser::argEnc128Accessibility), true, yn_choices);
+this->ap.addChoices("extract", p(&ArgParser::argEnc128Extract), true, yn_choices);
+this->ap.addChoices("print", p(&ArgParser::argEnc128Print), true, print128_choices);
+this->ap.addChoices("assemble", p(&ArgParser::argEnc128Assemble), true, yn_choices);
+this->ap.addChoices("annotate", p(&ArgParser::argEnc128Annotate), true, yn_choices);
+this->ap.addChoices("form", p(&ArgParser::argEnc128Form), true, yn_choices);
+this->ap.addChoices("modify-other", p(&ArgParser::argEnc128ModifyOther), true, yn_choices);
+this->ap.addChoices("modify", p(&ArgParser::argEnc128Modify), true, modify128_choices);
+this->ap.addChoices("use-aes", p(&ArgParser::argEnc128UseAes), true, yn_choices);
this->ap.registerOptionTable("256-bit encryption", b(&ArgParser::argEnd256BitEncryption));
this->ap.addBare("force-R5", b(&ArgParser::argEnc256ForceR5));
this->ap.addBare("allow-insecure", b(&ArgParser::argEnc256AllowInsecure));