aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2022-01-07 23:01:10 +0100
committerJay Berkenbilt <ejb@ql.org>2022-01-30 19:11:03 +0100
commitb4bd124be496170937d19742d83c2bad7471fe81 (patch)
tree0cd998483de30c688cf5130c90fd4ee94f47833c /include
parent5303130cf920ad9242bd1bb5ad998a791eb7e205 (diff)
downloadqpdf-b4bd124be496170937d19742d83c2bad7471fe81.tar.zst
QPDFArgParser: support adding/printing help information
Diffstat (limited to 'include')
-rw-r--r--include/qpdf/QPDFArgParser.hh101
1 files changed, 99 insertions, 2 deletions
diff --git a/include/qpdf/QPDFArgParser.hh b/include/qpdf/QPDFArgParser.hh
index ea51ca67..12ade54b 100644
--- a/include/qpdf/QPDFArgParser.hh
+++ b/include/qpdf/QPDFArgParser.hh
@@ -30,6 +30,7 @@
#include <vector>
#include <functional>
#include <stdexcept>
+#include <sstream>
// This is not a general-purpose argument parser. It is tightly
// crafted to work with qpdf. qpdf's command-line syntax is very
@@ -38,7 +39,10 @@
// backward compatibility to ensure we don't break what constitutes a
// valid command. This class handles the quirks of qpdf's argument
// parsing, bash/zsh completion, and support for @argfile to read
-// arguments from a file.
+// arguments from a file. For the qpdf CLI, setup of QPDFArgParser is
+// done mostly by automatically-generated code (one-off code for
+// qpdf), though the handlers themselves are hand-coded. See
+// generate_auto_job at the top of the source tree for details.
// Note about memory: there is code that expects argv to be a char*[],
// meaning that arguments are writable. Several operations, including
@@ -119,6 +123,13 @@ class QPDFArgParser
std::string const& arg, param_arg_handler_t,
bool required, char const** choices);
+ // The default behavior when an invalid choice is specified with
+ // an option that takes choices is to list all the choices. This
+ // may not be good if there are too many choices, so you can
+ // provide your own handler in this case.
+ QPDF_DLL
+ void addInvalidChoiceHandler(std::string const& arg, param_arg_handler_t);
+
// If an option is shared among multiple tables and uses identical
// handlers, you can just copy it instead of repeating the
// registration call.
@@ -131,6 +142,67 @@ class QPDFArgParser
QPDF_DLL
void addFinalCheck(bare_arg_handler_t);
+ // Help generation methods
+
+ // Help is available on topics and options. Options may be
+ // associated with topics. Users can run --help, --help=topic, or
+ // --help=--arg to get help. The top-level help tells the user how
+ // to run help and lists available topics. Help for a topic prints
+ // a short synopsis about the topic and lists any options that may
+ // be associated with the topic. Help for an option provides a
+ // short synopsis for that option. All help output is appended
+ // with a blurb (if supplied) directing the user to the full
+ // documentation. Help is not shown for options for which help has
+ // not been added. This makes it possible to have undocumented
+ // options for testing, backward-compatibility, etc. Also, it
+ // could be quite confusing to handle appropriate help for some
+ // inner options that may be repeated with different semantics
+ // inside different option tables. There is also no checking for
+ // whether an option that has help actually exists. In other
+ // words, it's up to the caller to ensure that help actually
+ // corresponds to the program's actual options. Rather than this
+ // being an intentional design decision, it is because this class
+ // is specifically for qpdf, qpdf generates its help and has other
+ // means to ensure consistency.
+
+ // Note about newlines:
+ //
+ // short_text should fit easily after the topic/option on the same
+ // line and should not end with a newline. Keep it to around 40 to
+ // 60 characters.
+ //
+ // long_text and footer should end with a single newline. They can
+ // have embedded newlines. Keep lines to under 80 columns.
+ //
+ // QPDFArgParser does reformat the text, but it may add blank
+ // lines in some situations. Following the above conventions will
+ // keep the help looking uniform.
+
+ // If provided, this footer is appended to all help, separated by
+ // a blank line.
+ QPDF_DLL
+ void addHelpFooter(std::string const&);
+
+ // Add a help topic along with the text for that topic
+ QPDF_DLL
+ void addHelpTopic(std::string const& topic,
+ std::string const& short_text,
+ std::string const& long_text);
+
+ // Add help for an option, and associate it with a topic.
+ QPDF_DLL
+ void addOptionHelp(std::string const& option_name,
+ std::string const& topic,
+ std::string const& short_text,
+ std::string const& long_text);
+
+ // Return the help text for a topic or option. Passing a null
+ // pointer returns the top-level help information. Passing an
+ // unknown value returns a string directing the user to run the
+ // top-level --help option.
+ QPDF_DLL
+ std::string getHelp(char const* topic_or_option);
+
// Convenience methods for adding member functions of a class as
// handlers.
template <class T>
@@ -171,7 +243,8 @@ class QPDFArgParser
OptionEntry() :
parameter_needed(false),
bare_arg_handler(0),
- param_arg_handler(0)
+ param_arg_handler(0),
+ invalid_choice_handler(0)
{
}
bool parameter_needed;
@@ -179,9 +252,24 @@ class QPDFArgParser
std::set<std::string> choices;
bare_arg_handler_t bare_arg_handler;
param_arg_handler_t param_arg_handler;
+ param_arg_handler_t invalid_choice_handler;
};
typedef std::map<std::string, OptionEntry> option_table_t;
+ struct HelpTopic
+ {
+ HelpTopic() = default;
+ HelpTopic(std::string const& short_text, std::string const& long_text) :
+ short_text(short_text),
+ long_text(long_text)
+ {
+ }
+
+ std::string short_text;
+ std::string long_text;
+ std::set<std::string> options;
+ };
+
OptionEntry& registerArg(std::string const& arg);
void completionCommon(bool zsh);
@@ -189,6 +277,7 @@ class QPDFArgParser
void argCompletionBash();
void argCompletionZsh();
void argHelp(char*);
+ void invalidHelpArg(char*);
void checkCompletion();
void handleArgFileArguments();
@@ -202,6 +291,11 @@ class QPDFArgParser
option_table_t&, std::string const&, std::string const&);
void handleCompletion();
+ void getTopHelp(std::ostringstream&);
+ void getAllHelp(std::ostringstream&);
+ void getTopicHelp(
+ std::string const& name, HelpTopic const&, std::ostringstream&);
+
class Members
{
friend class QPDFArgParser;
@@ -235,6 +329,9 @@ class QPDFArgParser
std::vector<PointerHolder<char>> bash_argv;
PointerHolder<char*> argv_ph;
PointerHolder<char*> bash_argv_ph;
+ std::map<std::string, HelpTopic> help_topics;
+ std::map<std::string, HelpTopic> option_help;
+ std::string help_footer;
};
PointerHolder<Members> m;
};