#include #include #include #include #include "components/command_line.hpp" POLYBAR_NS /** * Create instance */ cliparser::make_type cliparser::make(string&& scriptname, const clioptions&& opts) { return factory_util::unique( "Usage: " + scriptname + " bar_name [OPTION...]", forward(opts)); } /** * Construct parser */ cliparser::parser(string&& synopsis, const options&& opts) : m_synopsis(forward(synopsis)), m_opts(forward(opts)) {} /** * Print application usage message */ void cliparser::usage() const { std::cout << m_synopsis << "\n" << std::endl; // get the length of the longest string in the flag column // which is used to align the description fields size_t maxlen{0}; for (const auto& m_opt : m_opts) { size_t len{m_opt.flag_long.length() + m_opt.flag.length() + 4}; maxlen = len > maxlen ? len : maxlen; } for (auto& opt : m_opts) { size_t pad = maxlen - opt.flag_long.length() - opt.token.length(); std::cout << " " << opt.flag << ", " << opt.flag_long; if (!opt.token.empty()) { std::cout << "=" << opt.token; pad--; } // output the list with accepted values if (!opt.values.empty()) { std::cout << std::setw(pad + opt.desc.length()) << std::setfill(' ') << opt.desc << std::endl; pad = pad + opt.flag_long.length() + opt.token.length() + 7; std::cout << string(pad, ' ') << opt.token << " is one of: "; for (auto& v : opt.values) { std::cout << v << (v != opt.values.back() ? ", " : ""); } } else { std::cout << std::setw(pad + opt.desc.length()) << std::setfill(' ') << opt.desc; } std::cout << std::endl; } } /** * Process input values */ void cliparser::process_input(const vector& values) { for (size_t i = 0; i < values.size(); i++) { parse(values[i], values.size() > i + 1 ? values[i + 1] : ""); } } /** * Test if the passed option was provided */ bool cliparser::has(const string& option) const { return m_optvalues.find(option) != m_optvalues.end(); } /** * Gets the value defined for given option */ string cliparser::get(string opt) const { if (has(forward(opt))) { return m_optvalues.find(opt)->second; } return ""; } /** * Compare option value with given string */ bool cliparser::compare(string opt, const string& val) const { return get(move(opt)) == val; } /** * Compare option with its short version */ auto cliparser::is_short(const string& option, const string& opt_short) const { return option.compare(0, opt_short.length(), opt_short) == 0; } /** * Compare option with its long version */ auto cliparser::is_long(const string& option, const string& opt_long) const { return option.compare(0, opt_long.length(), opt_long) == 0; } /** * Compare option with both versions */ auto cliparser::is(const string& option, string opt_short, string opt_long) const { return is_short(option, move(opt_short)) || is_long(option, move(opt_long)); } /** * Parse option value */ auto cliparser::parse_value(string input, const string& input_next, choices values) const { string opt = move(input); size_t pos; string value; if (input_next.empty() && opt.compare(0, 2, "--") != 0) { throw value_error("Missing value for " + opt); } else if ((pos = opt.find('=')) == string::npos && opt.compare(0, 2, "--") == 0) { throw value_error("Missing value for " + opt); } else if (pos == string::npos && !input_next.empty()) { value = input_next; } else { value = opt.substr(pos + 1); opt = opt.substr(0, pos); } if (!values.empty() && std::find(values.begin(), values.end(), value) == values.end()) { throw value_error("Invalid value '" + value + "' for argument " + string{opt}); } return value; } /** * Parse and validate passed arguments and flags */ void cliparser::parse(const string& input, const string& input_next) { if (m_skipnext) { m_skipnext = false; if (!input_next.empty()) { return; } } for (auto&& opt : m_opts) { if (is(input, opt.flag, opt.flag_long)) { if (opt.token.empty()) { m_optvalues.insert(make_pair(opt.flag_long.substr(2), "")); } else { auto value = parse_value(input, input_next, opt.values); m_skipnext = (value == input_next); m_optvalues.insert(make_pair(opt.flag_long.substr(2), value)); } return; } } if (input.compare(0, 1, "-") == 0) { throw argument_error("Unrecognized option " + input); } } POLYBAR_NS_END