/************************************************************************* ** CLOption.hpp ** ** ** ** This file is part of dvisvgm -- a fast DVI to SVG converter ** ** Copyright (C) 2005-2024 Martin Gieseking ** ** ** ** This program is free software; you can redistribute it and/or ** ** modify it under the terms of the GNU General Public License as ** ** published by the Free Software Foundation; either version 3 of ** ** the License, or (at your option) any later version. ** ** ** ** This program 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 General Public License for more details. ** ** ** ** You should have received a copy of the GNU General Public License ** ** along with this program; if not, see . ** *************************************************************************/ #ifndef CL_OPTION_HPP #define CL_OPTION_HPP #include #include #include namespace CL { class Option { friend class CommandLine; public: enum class ArgMode {NONE, OPTIONAL, REQUIRED}; public: Option (const char *longname, char shortname, const char *summary) : _shortName(shortname), _longName(longname), _summary(summary), _given(false) {} virtual ~Option () = default; virtual std::string typeString () const {return "";} virtual ArgMode argMode () const {return ArgMode::NONE;} virtual bool given () const {return _given;} virtual char shortName () const {return _shortName;} virtual std::string longName () const {return _longName;} virtual std::string summary () const {return _summary;} virtual std::string argName () const {return "";} virtual std::string valueString () const {return "";} virtual std::string helpline () const { std::string line; if (_shortName != '\0') line = std::string("-") + _shortName + ", "; else line = " "; line += "--" + std::string(_longName); if (!argName().empty()) { if (argMode() == ArgMode::OPTIONAL) line += '['; line += '='; line += argName(); if (argMode() == ArgMode::OPTIONAL) line += ']'; } if (_summary) { line += '\t'; line += _summary; } if (argMode() != ArgMode::NONE && !valueString().empty()) line += std::string(" [") + valueString() + "]"; return line; } protected: virtual bool parse (std::istream &is, bool longopt) { if (is.eof()) return given(argMode() != ArgMode::REQUIRED); if (argMode() == ArgMode::OPTIONAL && is.peek() == ' ') return given(false); if (longopt && is.get() != '=') return given(false); return given(parseValue(is)); } virtual bool parseValue (std::istream &is) { return is.peek() == EOF || argMode() == ArgMode::NONE; } bool given (bool val) {return _given = val;} private: char _shortName; const char *_longName; const char*_summary; bool _given; }; template constexpr const char* typeString () {return "unknown";} template<> constexpr const char* typeString () {return "boolean";} template<> constexpr const char* typeString () {return "integer";} template<> constexpr const char* typeString () {return "non-negative integer";} template<> constexpr const char* typeString () {return "floating point";} template<> constexpr const char* typeString () {return "string";} template inline T parseValue (std::istream &is) { T value; is >> value; return value; } template<> inline std::string parseValue (std::istream &is) { is >> std::ws; std::string str; std::getline(is, str); return str; } template class TypedOption : public Option { public: TypedOption (const char *longName, char shortName, const char *argName, T val, const char *summary) : Option(longName, shortName, summary), _argName(argName), _value(val) {} TypedOption (const char *longName, char shortName, const char *argName, const char *summary) : Option(longName, shortName, summary), _argName(argName), _value() {} T value () const {return _value;} std::string typeString () const override {return CL::typeString();} std::string argName() const override {return _argName ? _argName : "";} std::string valueString () const override { std::ostringstream oss; oss << _value; return oss.str(); } ArgMode argMode () const override {return mode;} protected: bool parseValue (std::istream &is) override { T value = CL::parseValue(is); if (!is.fail()) _value = std::move(value); return !is.fail() || (argMode() == ArgMode::OPTIONAL && is.eof()); } private: const char *_argName; T _value; }; template class TypedOption : public Option { public: TypedOption (const char *longName, char shortName, const char *argName, bool val, const char *summary) : Option(longName, shortName, summary), _argName(argName), _value(val) {} TypedOption (const char *longName, char shortName, const char *argName, const char *summary) : Option(longName, shortName, summary), _argName(argName), _value(false) {} bool value () const {return _value;} std::string valueString () const override {return _value ? "yes" : "no";} ArgMode argMode () const override {return mode;} std::string typeString () const override {return CL::typeString();} std::string argName() const override {return _argName ? _argName : "";} protected: bool parseValue (std::istream &is) override { std::string str; is >> str; if (is.fail()) return argMode() != ArgMode::REQUIRED; if (str == "yes" || str == "y" || str == "true" || str == "1") _value = true; else if (str == "no" || str == "n" || str == "false" || str == "0") _value = false; else return false; return true; } private: const char *_argName; bool _value; }; } // namespace CL #endif