/usr/include/simgear/misc/argparse.hxx is in libsimgear-dev 1:2018.1.1+dfsg-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 | // -*- coding: utf-8 -*-
//
// argparse.hxx --- Simple, generic parser for command-line arguments
// Copyright (C) 2017 Florent Rougon
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
// MA 02110-1301 USA.
#ifndef _SIMGEAR_ARGPARSE_HXX_
#define _SIMGEAR_ARGPARSE_HXX_
#include <string>
#include <vector>
#include <unordered_map>
#include <memory>
#include <utility> // std::pair
#include <simgear/structure/exception.hxx>
// Usage example:
//
// using simgear::argparse::OptionArgType;
//
// simgear::argparse::ArgumentParser parser;
// parser.addOption("root option", OptionArgType::MANDATORY_ARGUMENT,
// "", "--root");
// parser.addOption("test option", OptionArgType::NO_ARGUMENT, "-t", "--test");
//
// const auto res = parser.parseArgs(argc, argv);
//
// for (const auto& opt: res.first) {
// std::cerr << "Got option '" << opt.id() << "' as '" << opt.passedAs() <<
// "'" << ((opt.hasValue()) ? " with value '" + opt.value() + "'" : "") <<
// "\n";
// }
//
// for (const auto& arg: res.second) {
// std::cerr << "Got non-option argument '" << arg << "'\n";
// }
namespace simgear
{
namespace argparse
{
// Custom exception classes
class Error : public sg_exception
{
public:
explicit Error(const std::string& message,
const std::string& origin = std::string());
explicit Error(const char* message, const char* origin = nullptr);
};
class InvalidUserInput : public Error
{
using Error::Error; // inherit all constructors
};
enum class OptionArgType {
NO_ARGUMENT = 0,
OPTIONAL_ARGUMENT,
MANDATORY_ARGUMENT
};
// All strings inside this class are encoded in UTF-8.
class OptionDesc
{
public:
explicit OptionDesc(const std::string& optionId,
std::vector<char> shortAliases,
std::vector<std::string> longAliases,
OptionArgType argumentType);
// Simple getters for the private members
const std::string& id() const;
const std::vector<char>& shortAliases() const;
const std::vector<std::string>& longAliases() const;
OptionArgType argumentType() const;
private:
// Option identifier, invisible to the end user. Used to easily refer to the
// option despite the various forms it may take (short and/or long aliases).
std::string _id;
// Each element of _shortAliases must be an ASCII character. For instance,
// 'o' for an option called '-o'.
std::vector<char> _shortAliases;
// Each element of _longAliases should be the name of a long option, with
// the two leading dashes removed. For instance, 'generate-foobar' for an
// option named '--generate-foobar'.
std::vector<std::string> _longAliases;
OptionArgType _argumentType;
};
// All strings inside this class are encoded in UTF-8.
class OptionValue
{
public:
explicit OptionValue(std::shared_ptr<const OptionDesc> optionDesc,
const std::string& passedAs,
const std::string& value = std::string(),
bool hasValue = false);
// Simple getters/accessors for the private members
std::shared_ptr<const OptionDesc> optionDesc() const;
std::string passedAs() const;
std::string value() const;
bool hasValue() const;
// The corresponding setters
void setOptionDesc(std::shared_ptr<const OptionDesc>);
void setPassedAs(const std::string&);
void setValue(const std::string&);
void setHasValue(bool);
// For convenience: get the option ID from the result of optionDesc()
const std::string id() const;
private:
// Pointer to the option descriptor.
std::shared_ptr<const OptionDesc> _optionDesc;
// Exact option passed (e.g., -f or --foobar).
std::string _passedAs;
// Value given for the option, if any (otherwise, the empty string).
std::string _value;
// Tells whether the option has been given a value. This is of course mainly
// useful for options taking an *optional* argument. The value in question
// can be the empty string, if given on a separate command line argument
// from the option.
bool _hasValue;
};
// Main class for command line processing. Every string coming out of it is
// encoded in UTF-8.
class ArgumentParser
{
public:
// Register an option, with zero or more short aliases (e.g., -a, -u, - F)
// and zero or more long aliases (e.g., --foobar, --barnum, --bleh). The
// option may take no argument, or one optional argument, or one mandatory
// argument. The 'optionId' is used to refer to the option in a clear and
// simple way, even in the presence of several short or long aliases. It is
// thus visible to the programmer using this API, but not to users of the
// command line interface being implemented.
//
// Note: this method and all its overloads take options in the form "-o" or
// "--foobar" (as std::string instances). While it would be possible
// to only require a char for each short option and to take long
// option declarations without the two leading dashes, the API chosen
// here should lead to more readable and searchable user code.
//
// shortAliases: each element should consist of two characters: an ASCII
// hyphen (-) followed by an ASCII character.
// longAliases: each element should be a string in UTF-8 encoding, starting
// with two ASCII/UTF-8 hyphens (U+002D).
//
// This API could be extended to automatically generate --help output from
// strings passed to addOption().
void addOption(const std::string& optionId,
OptionArgType argumentType,
std::vector<std::string> shortAliases,
std::vector<std::string> longAliases);
// Convenience overload that should be enough for most cases. To register
// only a short option or only a long option, simply pass the empty string
// for the corresponding parameter.
void addOption(const std::string& optionId,
OptionArgType argumentType,
std::string shortOpt = std::string(),
std::string longOpt = std::string());
// Parse arguments from an argc/argv pair of variables. 'argc' should be the
// number of elements in 'argv', the first of which is ignored for the sake
// of options and arguments extraction (since it normally holds the program
// name).
//
// Note: this “number of elements” doesn't count the usual---and completely
// unneeded here---final null pointer.
//
// Short options may be grouped in the usual way. For instance, if '-x',
// '-z' and '-f' are three short options, the first two taking no argument
// and '-f' taking one mandatory argument, then both '-xzf bar' and
// '-xzfbar' are equivalent to '-x -z -f bar' as well as to '-x -z -fbar'
// ('bar' being the value taken by option '-f').
//
// Long options are handled in the usual way too:
//
// '--foobar' for an option taking no argument
//
// '--foobar=value' for an option taking an optional or mandatory
// or '--foobar value' argument (two separate command line arguments in the
// second case)
//
// Long option names may contain spaces, though this is extremely uncommon
// and inconvenient for users. Any option argument (be it for a long or a
// short option) may contain spaces, as expected.
//
// As usual too, the special '--' argument consisting of two ASCII/UTF-8
// hyphens, can be used to cause all subsequent arguments to be treated as
// non-option arguments, regardless of whether they start with a hyphen or
// not. In the absence of this special argument, the first argument that is
// not the value of an option and is either a single hyphen, or doesn't
// start with a hyphen, marks the end of options. This and all subsequent
// arguments are read as non-option arguments.
//
// Return a pair containing:
// - the list of supplied options (with their respective values, when
// applicable);
// - the list of non-option arguments that were given after the options.
//
// Both of these lists (vectors) may be empty and preserve the order used in
// 'argv'.
std::pair< std::vector<OptionValue>, std::vector<std::string> >
parseArgs(int argc, const char *const *argv) const;
private:
// Convert from the encoding used for argv (command line arguments) to
// UTF-8.
//
// This method is currently not very satisfactory (cf. comments in the
// implementation). The Windows code path is untested; the non-Windows code
// path assumes command line arguments are encoded in UTF-8 (in other words,
// it's a no-op).
static std::string cmdEncToUtf8(const std::string& stringInCmdLineEncoding);
// Remove leading dashes and do sanity checks. 'longAliases' is modified
// in-place. 'shortAliases' is not, because we build an std::vector<char>
// from an std::vector<std::string>.
static std::vector<char> removeHyphens(
const std::vector<std::string>& shortAliases,
std::vector<std::string>& longAliases);
// Read a long option and its value, if any (in total: one or two command
// line arguments).
//
// Return the number of arguments consumed by this process after
// 'currentArg' (i.e., 0 or 1 depending on whether the last option in
// 'currentArg' has been given a value).
//
// 'currentArg' comes from argv[nextArgIdx-1], after decoding by
// cmdEncToUtf8(). Thus, argv[nextArgIdx] is the command-line argument
// coming after 'currentArg'.
int readLongOption(
int argc, const char *const *argv, const std::string& currentArg,
int nextArgIdx, std::vector<OptionValue>& optsWithValues) const;
// Read all short options in a command line argument, plus the option value
// of the last one of these, if any (even if the option value is in the next
// command line argument).
//
// See readLongOption() for the return value and meaning of parameters.
int readShortOptions(
int argc, const char *const *argv, const std::string& currentArg,
int nextArgIdx, std::vector<OptionValue>& optsWithValues) const;
// Keys are short option names without the leading dash
std::unordered_map< char,
std::shared_ptr<const OptionDesc> > _shortOptionMap;
// Keys are long option names without the two leading dashes
std::unordered_map< std::string,
std::shared_ptr<const OptionDesc> > _longOptionMap;
};
} // of namespace argparse
} // of namespace simgear
#endif // _SIMGEAR_ARGPARSE_HXX_
|