diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/qpdf/QPDFArgParser.hh | 101 |
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; }; |