The edited code is a descriptive text only, just intended to be printed as usage instructions. It doesn't encode a grammar or anything. So any changes to it don't matter.
The commenter has a good point that might get you half-way: the [] characters will often be special to the shell you're using. Wrap them in quotes e.g.:
./mycli --setclient '[192.68.1.1]:8888:ui'
or
./mycli --setclient "[192.68.1.1]:8888:ui"
Now, to actually support the additional characters you need to have a parser that expects the [ and ] characters added. If that's not yet the case, please update with a self-contained example (that correctly handles the old syntax) and we can tell you what is missing.
Live Demo
With the simplest form:
Live On Coliru
#include <boost/program_options.hpp> #include <iostream> namespace po = boost::program_options; int main(int argc, char** argv) { po::options_description desc; desc.add_options() // ("setclient", po::value<std::string>(), "<awsipaddress>[:awsport[:mystring]] Change the settings.") // ; // po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); std::cout << "Got: '" << vm["setclient"].as<std::string>() <<"'\n"; }
Prints
./a.out --setclient 192.68.1.1:8888:ui Got: '192.68.1.1:8888:ui' ./a.out --setclient [192.68.1.1]:8888:ui Got: '[192.68.1.1]:8888:ui'
BONUS: Ipv6?
Guessing that you MIGHT require [] to allow ipv6 addresses (as they contain : characters), have a look at What is the nicest way to parse this in C++?, and a new live demo integrating that in your program-options:
Live On Coliru
#include <boost/asio/ip/address.hpp> #include <boost/program_options.hpp> #include <iomanip> #include <iostream> namespace po = boost::program_options; using boost::asio::ip::address; struct Endpoint { address address_; uint16_t port_; std::string name_; static Endpoint parse_endpoint(std::string_view); }; int main(int argc, char** argv) { po::options_description desc; std::string setclient; desc.add_options() // ("setclient", po::value<std::string>(&setclient), "<awsipaddress>[:awsport[:mystring]] Change the settings."); po::variables_map vm; store(po::parse_command_line(argc, argv, desc), vm); notify(vm); auto ep = Endpoint::parse_endpoint(setclient); std::cout << std::left << "\t" << "Ip address: " << std::setw(12) << ep.address_ // << "Port: " << std::setw(12) << ep.port_ // << "Name: " << std::setw(12) << ep.name_ // << "\n"; } #include <boost/spirit/home/x3.hpp> #include <boost/fusion/adapted/struct.hpp> namespace x3 = boost::spirit::x3; BOOST_FUSION_ADAPT_STRUCT(Endpoint, address_, port_, name_) Endpoint Endpoint::parse_endpoint(std::string_view text) { // auto to_address = [](auto const& ctx) { auto& r = _attr(ctx); _val(ctx) = address::from_string({r.begin(), r.end()}); }; auto octet = x3::uint8; auto ipv46 = x3::rule<void, address>{} = x3::raw[+~x3::char_("]")][to_address]; auto ipv4 = x3::rule<void, address>{} = x3::raw[octet >> '.' >> octet >> '.' >> octet >> '.' >> octet][to_address]; auto port = (':' >> x3::uint16) | x3::attr(443); auto name = (':' >> +x3::char_) | x3::attr(std::string("ui")); auto spec = ('[' >> ipv46 >> ']' >> port >> name | // ipv4 >> port >> name) // >> x3::eoi; Endpoint ep; parse(begin(text), end(text), x3::expect[spec], ep); return ep; }
Printing for various test inputs:
+ ./a.out --setclient 192.68.1.1 Ip address: 192.68.1.1 Port: 443 Name: ui + ./a.out --setclient 192.68.1.1:backend Ip address: 192.68.1.1 Port: 443 Name: backend + ./a.out --setclient 192.68.1.1:8443 Ip address: 192.68.1.1 Port: 8443 Name: ui + ./a.out --setclient 192.68.1.1:8443:backend Ip address: 192.68.1.1 Port: 8443 Name: backend + ./a.out --setclient '[::1]' Ip address: ::1 Port: 443 Name: ui + ./a.out --setclient '[::1]:backend' Ip address: ::1 Port: 443 Name: backend + ./a.out --setclient '[::1]:8443' Ip address: ::1 Port: 8443 Name: ui + ./a.out --setclient '[::1]:8443:backend' Ip address: ::1 Port: 8443 Name: backend + ./a.out --setclient 127.0.0.1 Ip address: 127.0.0.1 Port: 443 Name: ui + ./a.out --setclient 127.0.0.1:backend Ip address: 127.0.0.1 Port: 443 Name: backend + ./a.out --setclient 127.0.0.1:8443 Ip address: 127.0.0.1 Port: 8443 Name: ui + ./a.out --setclient 127.0.0.1:8443:backend Ip address: 127.0.0.1 Port: 8443 Name: backend
BONUS 2: Converting Inside Program-Options
Live On Coliru
struct Endpoint { address address_; uint16_t port_; std::string name_; static Endpoint parse_endpoint(std::string_view); friend std::ostream& operator<<(std::ostream& os, Endpoint const& ep) { return os << "[" << ep.address_ << "]:" << ep.port_ << ":" << ep.name_; } friend void validate(boost::any& value, std::vector<std::string> const& tt, Endpoint*, int) { if (tt.size() != 1) throw po::invalid_option_value("too many tokens"); value = parse_endpoint(tt.front()); } }; int main(int argc, char** argv) { po::options_description desc; Endpoint ep{boost::asio::ip::address_v4::loopback(), 443, "ui"}; desc.add_options() // ("setclient", po::value<Endpoint>(&ep), "<awsipaddress>[:awsport[:mystring]] Change the settings."); po::variables_map vm; store(po::parse_command_line(argc, argv, desc), vm); notify(vm); std::cout << "\tparsed: " << ep << "\n"; }
[and]are treated special by your shell?—is special, because that's U+2014("setclient"either.