diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b9bce8223..4e1a9d1d98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -567,6 +567,8 @@ include_directories(Externals/Bochs_disasm) add_subdirectory(Externals/glslang) +add_subdirectory(Externals/cpp-optparse) + if(USE_SHARED_ENET) check_lib(ENET libenet enet enet/enet.h QUIET) include(CheckSymbolExists) diff --git a/Externals/cpp-optparse/CMakeLists.txt b/Externals/cpp-optparse/CMakeLists.txt new file mode 100644 index 0000000000..f5d05fa2f3 --- /dev/null +++ b/Externals/cpp-optparse/CMakeLists.txt @@ -0,0 +1,6 @@ +check_and_add_flag(CXX11 -std=c++11) + +set(SRCS OptionParser.cpp OptionParser.h) + +add_library(cpp-optparse STATIC ${SRCS}) +target_include_directories(cpp-optparse PUBLIC .) diff --git a/Externals/cpp-optparse/OptionParser.cpp b/Externals/cpp-optparse/OptionParser.cpp new file mode 100644 index 0000000000..799ffdcbd0 --- /dev/null +++ b/Externals/cpp-optparse/OptionParser.cpp @@ -0,0 +1,593 @@ +/** + * Copyright (C) 2010 Johannes Weißl + * License: MIT License + * URL: https://github.com/weisslj/cpp-optparse + */ + +#include "OptionParser.h" + +#include +#include +#include +#include + +#if defined(ENABLE_NLS) && ENABLE_NLS +# include +# define _(s) gettext(s) +#else +# define _(s) ((const char *) (s)) +#endif + +using namespace std; + +namespace optparse { + +////////// auxiliary (string) functions { ////////// +class str_wrap { +public: + str_wrap(const string& l, const string& r) : lwrap(l), rwrap(r) {} + str_wrap(const string& w) : lwrap(w), rwrap(w) {} + string operator() (const string& s) { return lwrap + s + rwrap; } + const string lwrap, rwrap; +}; +template +static string str_join_trans(const string& sep, InputIterator begin, InputIterator end, UnaryOperator op) { + string buf; + for (InputIterator it = begin; it != end; ++it) { + if (it != begin) + buf += sep; + buf += op(*it); + } + return buf; +} +template +static string str_join(const string& sep, InputIterator begin, InputIterator end) { + return str_join_trans(sep, begin, end, str_wrap("")); +} +static string& str_replace(string& s, const string& patt, const string& repl) { + size_t pos = 0, n = patt.length(); + while (true) { + pos = s.find(patt, pos); + if (pos == string::npos) + break; + s.replace(pos, n, repl); + pos += repl.size(); + } + return s; +} +static string str_replace(const string& s, const string& patt, const string& repl) { + string tmp = s; + str_replace(tmp, patt, repl); + return tmp; +} +static string str_format(const string& str, size_t pre, size_t len, bool running_text = true, bool indent_first = true) { + string s = str; + stringstream ss; + string p; + len -= 2; // Python seems to not use full length + if (running_text) + replace(s.begin(), s.end(), '\n', ' '); + if (indent_first) + p = string(pre, ' '); + + size_t pos = 0, linestart = 0; + size_t line = 0; + while (true) { + bool wrap = false; + + size_t new_pos = s.find_first_of(" \n\t", pos); + if (new_pos == string::npos) + break; + if (s[new_pos] == '\n') { + pos = new_pos + 1; + wrap = true; + } + if (line == 1) + p = string(pre, ' '); + if (wrap || new_pos + pre > linestart + len) { + ss << p << s.substr(linestart, pos - linestart - 1) << endl; + linestart = pos; + line++; + } + pos = new_pos + 1; + } + ss << p << s.substr(linestart) << endl; + return ss.str(); +} +static string str_inc(const string& s) { + stringstream ss; + string v = (s != "") ? s : "0"; + long i; + istringstream(v) >> i; + ss << i+1; + return ss.str(); +} +static unsigned int cols() { + unsigned int n = 80; +#ifndef _WIN32 + const char *s = getenv("COLUMNS"); + if (s) + istringstream(s) >> n; +#endif + return n; +} +static string basename(const string& s) { + string b = s; + size_t i = b.find_last_not_of('/'); + if (i == string::npos) { + if (b[0] == '/') + b.erase(1); + return b; + } + b.erase(i+1, b.length()-i-1); + i = b.find_last_of("/"); + if (i != string::npos) + b.erase(0, i+1); + return b; +} +////////// } auxiliary (string) functions ////////// + + +////////// class OptionContainer { ////////// +Option& OptionContainer::add_option(const string& opt) { + const string tmp[1] = { opt }; + return add_option(vector(&tmp[0], &tmp[1])); +} +Option& OptionContainer::add_option(const string& opt1, const string& opt2) { + const string tmp[2] = { opt1, opt2 }; + return add_option(vector(&tmp[0], &tmp[2])); +} +Option& OptionContainer::add_option(const string& opt1, const string& opt2, const string& opt3) { + const string tmp[3] = { opt1, opt2, opt3 }; + return add_option(vector(&tmp[0], &tmp[3])); +} +Option& OptionContainer::add_option(const vector& v) { + _opts.resize(_opts.size()+1, Option(get_parser())); + Option& option = _opts.back(); + string dest_fallback; + for (vector::const_iterator it = v.begin(); it != v.end(); ++it) { + if (it->substr(0,2) == "--") { + const string s = it->substr(2); + if (option.dest() == "") + option.dest(str_replace(s, "-", "_")); + option._long_opts.insert(s); + _optmap_l[s] = &option; + } else { + const string s = it->substr(1,1); + if (dest_fallback == "") + dest_fallback = s; + option._short_opts.insert(s); + _optmap_s[s] = &option; + } + } + if (option.dest() == "") + option.dest(dest_fallback); + return option; +} +string OptionContainer::format_option_help(unsigned int indent /* = 2 */) const { + stringstream ss; + + if (_opts.empty()) + return ss.str(); + + for (list