// Begin License: // Copyright (C) 2006-2008 Tobias Sargeant (tobias.sargeant@gmail.com). // All rights reserved. // // This file is part of the Carve CSG Library (http://carve-csg.com/) // // This file may be used under the terms of the GNU General Public // License version 2.0 as published by the Free Software Foundation // and appearing in the file LICENSE.GPL2 included in the packaging of // this file. // // This file is provided "AS IS" with NO WARRANTY OF ANY KIND, // INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE. // End: #pragma once #include #include #include #include #include #include "stringfuncs.hpp" namespace opt { struct Help { std::string long_opt; std::string short_opt; bool arg; std::string text; Help(const std::string &_long_opt, const std::string &_short_opt, bool _arg, const std::string &_text) : long_opt(_long_opt), short_opt(_short_opt), arg(_arg), text(_text) { } }; struct Short { char ch; bool arg; std::string help; Short(char _ch, bool _arg, const std::string &_help) : ch(_ch), arg(_arg), help(_help) {} }; struct Long { std::string str; bool arg; std::string help; Long(const std::string &_str, bool _arg, const std::string &_help) : str(_str), arg(_arg), help(_help) {} }; struct exception { private: mutable std::string err; mutable std::ostringstream accum; public: exception(const std::string &e) : err(e), accum() { } exception() : err(), accum() { } exception(const exception &e) : err(e.str()), accum() { } const std::string &str() const { if (accum.tellp()) { err = accum.str(); accum.str(""); } return err; } template exception &operator<<(const T &t) { accum << t; return *this; } }; class Parser { protected: std::list short_opts; std::list long_opts; std::list help_text; std::string progname; virtual void help(std::ostream &out) { size_t max_long = 0; size_t max_short = 0; for (std::list::iterator i = help_text.begin(); i != help_text.end(); ++i) { max_long = std::max(max_long, (*i).long_opt.size()); max_short = std::max(max_short, (*i).short_opt.size()); } out << usageStr() << std::endl; out << std::setfill(' '); for (std::list::iterator i = help_text.begin(); i != help_text.end(); ++i) { out.setf(std::ios::left); out << std::setw(max_long + 1) << (*i).long_opt << std::setw(max_short + 1) << (*i).short_opt; if ((*i).arg) { out << "{arg} "; } else { out << " "; } out << (*i).text << std::endl; } } virtual std::string usageStr() { return std::string ("Usage: ") + progname + std::string(" [options] [args]"); }; virtual void optval(const std::string &o, const std::string &v) { } virtual void arg(const std::string &a) { } void long_opt(std::vector::const_iterator &i, const std::vector::const_iterator &e) { const std::string &a(*i); std::string opt, val; bool has_argopt; std::string::size_type eq = a.find('='); has_argopt = eq != std::string::npos; if (has_argopt) { opt = a.substr(2, eq - 2); val = a.substr(eq + 1); } else { opt = a.substr(2); val = ""; } for (std::list::iterator j = long_opts.begin(), je = long_opts.end(); j != je; ++j) { if ((*j).str == opt) { if (!(*j).arg && has_argopt) throw exception() << "unexpected argument for option --" << (*j).str << "."; if ((*j).arg) { if (++i == e) throw exception() << "missing argument for option --" << (*j).str << "."; val = *i; } optval("--" + opt, val); ++i; return; } } throw exception() << "unrecognised option --" << opt << "."; } void short_opt(std::vector::const_iterator &i, const std::vector::const_iterator &e) { const std::string &a(*i); for (std::string::size_type j = 1; j < a.size(); ++j) { for (std::list::iterator k = short_opts.begin(), ke = short_opts.end(); k != ke; ++k) { if ((*k).ch == a[j]) { if ((*k).arg) { if (j < a.size() - 1) { optval("-" + a.substr(j, 1), a.substr(j + 1)); j = a.size() - 1; } else { if (++i == e) throw exception() << "missing argument for option -" << a[j] << "."; optval("-" + a.substr(j, 1), *i); } } else { optval("-" + a.substr(j, 1), ""); } goto found; } } throw exception() << "unrecognised option -" << a[j] << "."; found:; } ++i; } public: Parser() { } virtual ~Parser() { } Parser &option(const std::string &str, char ch, bool arg, const std::string &help) { long_opts.push_back(Long(str, arg, help)); short_opts.push_back(Short(ch, arg, help)); help_text.push_back(Help("--" + str, std::string("-") + ch, arg, help)); return *this; } Parser &option(const std::string &str, bool arg, const std::string &help) { long_opts.push_back(Long(str, arg, help)); help_text.push_back(Help("--" + str, "", arg, help)); return *this; } Parser &option(char ch, bool arg, const std::string &help) { short_opts.push_back(Short(ch, arg, help)); help_text.push_back(Help("", std::string("-") + ch, arg, help)); return *this; } bool parse(const std::string &pn, const std::vector &opts) { try { progname = pn; std::vector::const_iterator i = opts.begin(); std::vector::const_iterator e = opts.end(); while (i != e) { const std::string &a(*i); if (a[0] == '-') { if (a == "-" || a == "--") { ++i; break; } if (a[1] == '-') { long_opt(i, e); } else { short_opt(i, e); } } else { break; } } while (i != e) { arg(*i++); } return true; } catch (exception e) { std::cerr << e.str() << std::endl; help(std::cerr); return false; } } bool parse(int argc, char **argv) { std::vector opts(argc-1); for (int i = 1; i < argc; ++i) { opts[i-1] = argv[i]; } return parse(argv[0], opts); } }; }