mirror of
https://github.com/qpdf/qpdf.git
synced 2024-09-28 21:19:06 +00:00
232 lines
7.6 KiB
C++
232 lines
7.6 KiB
C++
// Copyright (c) 2005-2021 Jay Berkenbilt
|
|
//
|
|
// This file is part of qpdf.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
// Versions of qpdf prior to version 7 were released under the terms
|
|
// of version 2.0 of the Artistic License. At your option, you may
|
|
// continue to consider qpdf to be licensed under those terms. Please
|
|
// see the manual for additional information.
|
|
|
|
#ifndef QPDFARGPARSER_HH
|
|
#define QPDFARGPARSER_HH
|
|
|
|
#include <qpdf/DLL.h>
|
|
#include <qpdf/PointerHolder.hh>
|
|
#include <string>
|
|
#include <set>
|
|
#include <map>
|
|
#include <vector>
|
|
#include <functional>
|
|
#include <stdexcept>
|
|
|
|
// This is not a general-purpose argument parser. It is tightly
|
|
// crafted to work with qpdf. qpdf's command-line syntax is very
|
|
// complex because of its long history, and it doesn't really follow
|
|
// any kind of normal standard for arguments, but it's important for
|
|
// backward compatibility not 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.
|
|
|
|
// Note about memory: there is code that expects argv to be a char*[],
|
|
// meaning that arguments are writable. Several operations, including
|
|
// reading arguments from a file or parsing a line for bash
|
|
// completion, involve fabricating an argv array. To ensure that the
|
|
// memory is valid and is cleaned up properly, we keep various vectors
|
|
// of smart character pointers that argv points into. In order for
|
|
// those pointers to remain valid, the QPDFArgParser instance must
|
|
// remain in scope for the life of any code that may reference
|
|
// anything from argv.
|
|
class QPDFArgParser
|
|
{
|
|
public:
|
|
// Usage exception is thrown if there are any errors parsing
|
|
// arguments
|
|
class QPDF_DLL_CLASS Usage: public std::runtime_error
|
|
{
|
|
public:
|
|
QPDF_DLL
|
|
Usage(std::string const&);
|
|
};
|
|
|
|
// progname_env is used to override argv[0] when figuring out the
|
|
// name of the executable for setting up completion. This may be
|
|
// needed if the program is invoked by a wrapper.
|
|
QPDF_DLL
|
|
QPDFArgParser(int argc, char* argv[], char const* progname_env);
|
|
|
|
// Calls exit(0) if a help option is given or if in completion
|
|
// mode. If there are argument parsing errors,
|
|
// QPDFArgParser::Usage is thrown.
|
|
QPDF_DLL
|
|
void parseArgs();
|
|
|
|
// Return the program name as the last path element of the program
|
|
// executable.
|
|
QPDF_DLL
|
|
std::string getProgname();
|
|
|
|
// Methods for registering arguments. QPDFArgParser starts off
|
|
// with the main option table selected. You can add handlers for
|
|
// arguments in the current option table, and you can select which
|
|
// option table is current. The help option table is special and
|
|
// contains arguments that are only valid as the first and only
|
|
// option. Named option tables are for subparsers and always start
|
|
// a series of options that end with `--`.
|
|
|
|
typedef std::function<void()> bare_arg_handler_t;
|
|
typedef std::function<void(char*)> param_arg_handler_t;
|
|
|
|
QPDF_DLL
|
|
void selectMainOptionTable();
|
|
QPDF_DLL
|
|
void selectHelpOptionTable();
|
|
QPDF_DLL
|
|
void selectOptionTable(std::string const& name);
|
|
|
|
// Register a new options table. This also selects the option table.
|
|
QPDF_DLL
|
|
void registerOptionTable(
|
|
std::string const& name, bare_arg_handler_t end_handler);
|
|
|
|
// Add handlers for options in the current table
|
|
|
|
QPDF_DLL
|
|
void addPositional(param_arg_handler_t);
|
|
QPDF_DLL
|
|
void addBare(std::string const& arg, bare_arg_handler_t);
|
|
QPDF_DLL
|
|
void addRequiredParameter(
|
|
std::string const& arg,
|
|
param_arg_handler_t,
|
|
char const* parameter_name);
|
|
QPDF_DLL
|
|
void addOptionalParameter(std::string const& arg, param_arg_handler_t);
|
|
QPDF_DLL
|
|
void addRequiredChoices(
|
|
std::string const& arg, param_arg_handler_t, char const** choices);
|
|
// The final check handler is called at the very end of argument
|
|
// parsing.
|
|
QPDF_DLL
|
|
void addFinalCheck(bare_arg_handler_t);
|
|
|
|
// Convenience methods for adding member functions of a class as
|
|
// handlers.
|
|
template <class T>
|
|
static bare_arg_handler_t bindBare(void (T::*f)(), T* o)
|
|
{
|
|
return std::bind(std::mem_fn(f), o);
|
|
}
|
|
template <class T>
|
|
static param_arg_handler_t bindParam(void (T::*f)(char *), T* o)
|
|
{
|
|
return std::bind(std::mem_fn(f), o, std::placeholders::_1);
|
|
}
|
|
|
|
// When processing arguments, indicate how many arguments remain
|
|
// after the one whose handler is being called.
|
|
QPDF_DLL
|
|
int argsLeft() const;
|
|
|
|
// Indicate whether we are in completion mode.
|
|
QPDF_DLL
|
|
bool isCompleting() const;
|
|
|
|
// Insert a completion during argument parsing; useful for
|
|
// customizing completion in the position argument handler. Should
|
|
// only be used in completion mode.
|
|
QPDF_DLL
|
|
void insertCompletion(std::string const&);
|
|
|
|
// Throw a Usage exception with the given message. In completion
|
|
// mode, this just exits to prevent errors from partial commands
|
|
// or other error messages from messing up completion.
|
|
QPDF_DLL
|
|
void usage(std::string const& message);
|
|
|
|
private:
|
|
struct OptionEntry
|
|
{
|
|
OptionEntry() :
|
|
parameter_needed(false),
|
|
bare_arg_handler(0),
|
|
param_arg_handler(0)
|
|
{
|
|
}
|
|
bool parameter_needed;
|
|
std::string parameter_name;
|
|
std::set<std::string> choices;
|
|
bare_arg_handler_t bare_arg_handler;
|
|
param_arg_handler_t param_arg_handler;
|
|
};
|
|
friend struct OptionEntry;
|
|
|
|
OptionEntry& registerArg(std::string const& arg);
|
|
|
|
void completionCommon(bool zsh);
|
|
|
|
void argCompletionBash();
|
|
void argCompletionZsh();
|
|
|
|
void checkCompletion();
|
|
void handleArgFileArguments();
|
|
void handleBashArguments();
|
|
void readArgsFromFile(char const* filename);
|
|
void doFinalChecks();
|
|
void addOptionsToCompletions();
|
|
void addChoicesToCompletions(std::string const&, std::string const&);
|
|
void handleCompletion();
|
|
|
|
typedef std::map<std::string, OptionEntry> option_table_t;
|
|
|
|
class Members
|
|
{
|
|
friend class QPDFArgParser;
|
|
|
|
public:
|
|
QPDF_DLL
|
|
~Members() = default;
|
|
|
|
private:
|
|
Members(int argc, char* argv[], char const* progname_env);
|
|
Members(Members const&) = delete;
|
|
|
|
int argc;
|
|
char** argv;
|
|
char const* whoami;
|
|
std::string progname_env;
|
|
int cur_arg;
|
|
bool bash_completion;
|
|
bool zsh_completion;
|
|
std::string bash_prev;
|
|
std::string bash_cur;
|
|
std::string bash_line;
|
|
std::set<std::string> completions;
|
|
std::map<std::string, option_table_t> option_tables;
|
|
option_table_t main_option_table;
|
|
option_table_t help_option_table;
|
|
option_table_t* option_table;
|
|
std::string option_table_name;
|
|
bare_arg_handler_t final_check_handler;
|
|
std::vector<PointerHolder<char>> new_argv;
|
|
std::vector<PointerHolder<char>> bash_argv;
|
|
PointerHolder<char*> argv_ph;
|
|
PointerHolder<char*> bash_argv_ph;
|
|
};
|
|
PointerHolder<Members> m;
|
|
};
|
|
|
|
#endif // QPDFARGPARSER_HH
|