Squashed 'boost/' content from commit b4feb19f2

git-subtree-dir: boost
git-subtree-split: b4feb19f287ee92d87a9624b5d36b7cf46aeadeb
This commit is contained in:
Bill Somerville
2018-06-09 21:48:32 +01:00
commit 4ebe6417a5
12444 changed files with 2327021 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
project boost/program_options
: source-location ../src
;
SOURCES =
cmdline config_file options_description parsers variables_map
value_semantic positional_options utf8_codecvt_facet
convert winmain split
;
lib boost_program_options
: $(SOURCES).cpp
: <link>shared:<define>BOOST_PROGRAM_OPTIONS_DYN_LINK=1 # tell source we're building dll's
# See https://svn.boost.org/trac/boost/ticket/5049
<target-os>hpux,<toolset>gcc:<define>_INCLUDE_STDC__SOURCE_199901
:
: <link>shared:<define>BOOST_PROGRAM_OPTIONS_DYN_LINK=1
;
boost-install boost_program_options ;
+719
View File
@@ -0,0 +1,719 @@
// Copyright Vladimir Prus 2002-2004.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/config.hpp>
#include <boost/config.hpp>
#include <boost/program_options/detail/cmdline.hpp>
#include <boost/program_options/errors.hpp>
#include <boost/program_options/value_semantic.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/positional_options.hpp>
#include <boost/throw_exception.hpp>
#include <boost/bind.hpp>
#include <string>
#include <utility>
#include <vector>
#include <cassert>
#include <cstring>
#include <cctype>
#include <climits>
#include <cstdio>
#include <iostream>
namespace boost { namespace program_options {
using namespace std;
using namespace boost::program_options::command_line_style;
string
invalid_syntax::get_template(kind_t kind)
{
// Initially, store the message in 'const char*' variable,
// to avoid conversion to string in all cases.
const char* msg;
switch(kind)
{
case empty_adjacent_parameter:
msg = "the argument for option '%canonical_option%' should follow immediately after the equal sign";
break;
case missing_parameter:
msg = "the required argument for option '%canonical_option%' is missing";
break;
case unrecognized_line:
msg = "the options configuration file contains an invalid line '%invalid_line%'";
break;
// none of the following are currently used:
case long_not_allowed:
msg = "the unabbreviated option '%canonical_option%' is not valid";
break;
case long_adjacent_not_allowed:
msg = "the unabbreviated option '%canonical_option%' does not take any arguments";
break;
case short_adjacent_not_allowed:
msg = "the abbreviated option '%canonical_option%' does not take any arguments";
break;
case extra_parameter:
msg = "option '%canonical_option%' does not take any arguments";
break;
default:
msg = "unknown command line syntax error for '%s'";
}
return msg;
}
}}
namespace boost { namespace program_options { namespace detail {
// vc6 needs this, but borland chokes when this is added.
#if BOOST_WORKAROUND(_MSC_VER, < 1300)
using namespace std;
using namespace program_options;
#endif
cmdline::cmdline(const vector<string>& args)
{
init(args);
}
cmdline::cmdline(int argc, const char*const * argv)
{
#if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)
vector<string> args;
copy(argv+1, argv+argc+!argc, inserter(args, args.end()));
init(args);
#else
init(vector<string>(argv+1, argv+argc+!argc));
#endif
}
void
cmdline::init(const vector<string>& args)
{
this->args = args;
m_style = command_line_style::default_style;
m_desc = 0;
m_positional = 0;
m_allow_unregistered = false;
}
void
cmdline::style(int style)
{
if (style == 0)
style = default_style;
check_style(style);
this->m_style = style_t(style);
}
void
cmdline::allow_unregistered()
{
this->m_allow_unregistered = true;
}
void
cmdline::check_style(int style) const
{
bool allow_some_long =
(style & allow_long) || (style & allow_long_disguise);
const char* error = 0;
if (allow_some_long &&
!(style & long_allow_adjacent) && !(style & long_allow_next))
error = "boost::program_options misconfiguration: "
"choose one or other of 'command_line_style::long_allow_next' "
"(whitespace separated arguments) or "
"'command_line_style::long_allow_adjacent' ('=' separated arguments) for "
"long options.";
if (!error && (style & allow_short) &&
!(style & short_allow_adjacent) && !(style & short_allow_next))
error = "boost::program_options misconfiguration: "
"choose one or other of 'command_line_style::short_allow_next' "
"(whitespace separated arguments) or "
"'command_line_style::short_allow_adjacent' ('=' separated arguments) for "
"short options.";
if (!error && (style & allow_short) &&
!(style & allow_dash_for_short) && !(style & allow_slash_for_short))
error = "boost::program_options misconfiguration: "
"choose one or other of 'command_line_style::allow_slash_for_short' "
"(slashes) or 'command_line_style::allow_dash_for_short' (dashes) for "
"short options.";
if (error)
boost::throw_exception(invalid_command_line_style(error));
// Need to check that if guessing and long disguise are enabled
// -f will mean the same as -foo
}
bool
cmdline::is_style_active(style_t style) const
{
return ((m_style & style) ? true : false);
}
void
cmdline::set_options_description(const options_description& desc)
{
m_desc = &desc;
}
void
cmdline::set_positional_options(
const positional_options_description& positional)
{
m_positional = &positional;
}
int
cmdline::get_canonical_option_prefix()
{
if (m_style & allow_long)
return allow_long;
if (m_style & allow_long_disguise)
return allow_long_disguise;
if ((m_style & allow_short) && (m_style & allow_dash_for_short))
return allow_dash_for_short;
if ((m_style & allow_short) && (m_style & allow_slash_for_short))
return allow_slash_for_short;
return 0;
}
vector<option>
cmdline::run()
{
// The parsing is done by having a set of 'style parsers'
// and trying then in order. Each parser is passed a vector
// of unparsed tokens and can consume some of them (by
// removing elements on front) and return a vector of options.
//
// We try each style parser in turn, untill some input
// is consumed. The returned vector of option may contain the
// result of just syntactic parsing of token, say --foo will
// be parsed as option with name 'foo', and the style parser
// is not required to care if that option is defined, and how
// many tokens the value may take.
// So, after vector is returned, we validate them.
assert(m_desc);
vector<style_parser> style_parsers;
if (m_style_parser)
style_parsers.push_back(m_style_parser);
if (m_additional_parser)
style_parsers.push_back(
boost::bind(&cmdline::handle_additional_parser, this, _1));
if (m_style & allow_long)
style_parsers.push_back(
boost::bind(&cmdline::parse_long_option, this, _1));
if ((m_style & allow_long_disguise))
style_parsers.push_back(
boost::bind(&cmdline::parse_disguised_long_option, this, _1));
if ((m_style & allow_short) && (m_style & allow_dash_for_short))
style_parsers.push_back(
boost::bind(&cmdline::parse_short_option, this, _1));
if ((m_style & allow_short) && (m_style & allow_slash_for_short))
style_parsers.push_back(boost::bind(&cmdline::parse_dos_option, this, _1));
style_parsers.push_back(boost::bind(&cmdline::parse_terminator, this, _1));
vector<option> result;
while(!args.empty())
{
bool ok = false;
for(unsigned i = 0; i < style_parsers.size(); ++i)
{
unsigned current_size = static_cast<unsigned>(args.size());
vector<option> next = style_parsers[i](args);
// Check that option names
// are valid, and that all values are in place.
if (!next.empty())
{
vector<string> e;
for(unsigned k = 0; k < next.size()-1; ++k) {
finish_option(next[k], e, style_parsers);
}
// For the last option, pass the unparsed tokens
// so that they can be added to next.back()'s values
// if appropriate.
finish_option(next.back(), args, style_parsers);
for (unsigned j = 0; j < next.size(); ++j)
result.push_back(next[j]);
}
if (args.size() != current_size) {
ok = true;
break;
}
}
if (!ok) {
option opt;
opt.value.push_back(args[0]);
opt.original_tokens.push_back(args[0]);
result.push_back(opt);
args.erase(args.begin());
}
}
/* If an key option is followed by a positional option,
can can consume more tokens (e.g. it's multitoken option),
give those tokens to it. */
vector<option> result2;
for (unsigned i = 0; i < result.size(); ++i)
{
result2.push_back(result[i]);
option& opt = result2.back();
if (opt.string_key.empty())
continue;
const option_description* xd;
try
{
xd = m_desc->find_nothrow(opt.string_key,
is_style_active(allow_guessing),
is_style_active(long_case_insensitive),
is_style_active(short_case_insensitive));
}
catch(error_with_option_name& e)
{
// add context and rethrow
e.add_context(opt.string_key, opt.original_tokens[0], get_canonical_option_prefix());
throw;
}
if (!xd)
continue;
if (xd->semantic()->adjacent_tokens_only())
continue;
unsigned min_tokens = xd->semantic()->min_tokens();
unsigned max_tokens = xd->semantic()->max_tokens();
if (min_tokens < max_tokens && opt.value.size() < max_tokens)
{
// This option may grab some more tokens.
// We only allow to grab tokens that are not already
// recognized as key options.
int can_take_more = max_tokens - static_cast<int>(opt.value.size());
unsigned j = i+1;
for (; can_take_more && j < result.size(); --can_take_more, ++j)
{
option& opt2 = result[j];
if (!opt2.string_key.empty())
break;
if (opt2.position_key == INT_MAX)
{
// We use INT_MAX to mark positional options that
// were found after the '--' terminator and therefore
// should stay positional forever.
break;
}
assert(opt2.value.size() == 1);
opt.value.push_back(opt2.value[0]);
assert(opt2.original_tokens.size() == 1);
opt.original_tokens.push_back(opt2.original_tokens[0]);
}
i = j-1;
}
}
result.swap(result2);
// Assign position keys to positional options.
int position_key = 0;
for(unsigned i = 0; i < result.size(); ++i) {
if (result[i].string_key.empty())
result[i].position_key = position_key++;
}
if (m_positional)
{
unsigned position = 0;
for (unsigned i = 0; i < result.size(); ++i) {
option& opt = result[i];
if (opt.position_key != -1) {
if (position >= m_positional->max_total_count())
{
boost::throw_exception(too_many_positional_options_error());
}
opt.string_key = m_positional->name_for_position(position);
++position;
}
}
}
// set case sensitive flag
for (unsigned i = 0; i < result.size(); ++i) {
if (result[i].string_key.size() > 2 ||
(result[i].string_key.size() > 1 && result[i].string_key[0] != '-'))
{
// it is a long option
result[i].case_insensitive = is_style_active(long_case_insensitive);
}
else
{
// it is a short option
result[i].case_insensitive = is_style_active(short_case_insensitive);
}
}
return result;
}
void
cmdline::finish_option(option& opt,
vector<string>& other_tokens,
const vector<style_parser>& style_parsers)
{
if (opt.string_key.empty())
return;
//
// Be defensive:
// will have no original token if option created by handle_additional_parser()
std::string original_token_for_exceptions = opt.string_key;
if (opt.original_tokens.size())
original_token_for_exceptions = opt.original_tokens[0];
try
{
// First check that the option is valid, and get its description.
const option_description* xd = m_desc->find_nothrow(opt.string_key,
is_style_active(allow_guessing),
is_style_active(long_case_insensitive),
is_style_active(short_case_insensitive));
if (!xd)
{
if (m_allow_unregistered) {
opt.unregistered = true;
return;
} else {
boost::throw_exception(unknown_option());
}
}
const option_description& d = *xd;
// Canonize the name
opt.string_key = d.key(opt.string_key);
// We check that the min/max number of tokens for the option
// agrees with the number of tokens we have. The 'adjacent_value'
// (the value in --foo=1) counts as a separate token, and if present
// must be consumed. The following tokens on the command line may be
// left unconsumed.
// We don't check if those tokens look like option, or not!
unsigned min_tokens = d.semantic()->min_tokens();
unsigned max_tokens = d.semantic()->max_tokens();
unsigned present_tokens = static_cast<unsigned>(opt.value.size() + other_tokens.size());
if (present_tokens >= min_tokens)
{
if (!opt.value.empty() && max_tokens == 0)
{
boost::throw_exception(
invalid_command_line_syntax(invalid_command_line_syntax::extra_parameter));
}
// If an option wants, at minimum, N tokens, we grab them there,
// when adding these tokens as values to current option we check
// if they look like options
if (opt.value.size() <= min_tokens)
{
min_tokens -= static_cast<unsigned>(opt.value.size());
}
else
{
min_tokens = 0;
}
// Everything's OK, move the values to the result.
for(;!other_tokens.empty() && min_tokens--; )
{
// check if extra parameter looks like a known option
// we use style parsers to check if it is syntactically an option,
// additionally we check if an option_description exists
vector<option> followed_option;
vector<string> next_token(1, other_tokens[0]);
for (unsigned i = 0; followed_option.empty() && i < style_parsers.size(); ++i)
{
followed_option = style_parsers[i](next_token);
}
if (!followed_option.empty())
{
original_token_for_exceptions = other_tokens[0];
const option_description* od = m_desc->find_nothrow(other_tokens[0],
is_style_active(allow_guessing),
is_style_active(long_case_insensitive),
is_style_active(short_case_insensitive));
if (od)
boost::throw_exception(
invalid_command_line_syntax(invalid_command_line_syntax::missing_parameter));
}
opt.value.push_back(other_tokens[0]);
opt.original_tokens.push_back(other_tokens[0]);
other_tokens.erase(other_tokens.begin());
}
}
else
{
boost::throw_exception(
invalid_command_line_syntax(invalid_command_line_syntax::missing_parameter));
}
}
// use only original token for unknown_option / ambiguous_option since by definition
// they are unrecognised / unparsable
catch(error_with_option_name& e)
{
// add context and rethrow
e.add_context(opt.string_key, original_token_for_exceptions, get_canonical_option_prefix());
throw;
}
}
vector<option>
cmdline::parse_long_option(vector<string>& args)
{
vector<option> result;
const string& tok = args[0];
if (tok.size() >= 3 && tok[0] == '-' && tok[1] == '-')
{
string name, adjacent;
string::size_type p = tok.find('=');
if (p != tok.npos)
{
name = tok.substr(2, p-2);
adjacent = tok.substr(p+1);
if (adjacent.empty())
boost::throw_exception( invalid_command_line_syntax(
invalid_command_line_syntax::empty_adjacent_parameter,
name,
name,
get_canonical_option_prefix()) );
}
else
{
name = tok.substr(2);
}
option opt;
opt.string_key = name;
if (!adjacent.empty())
opt.value.push_back(adjacent);
opt.original_tokens.push_back(tok);
result.push_back(opt);
args.erase(args.begin());
}
return result;
}
vector<option>
cmdline::parse_short_option(vector<string>& args)
{
const string& tok = args[0];
if (tok.size() >= 2 && tok[0] == '-' && tok[1] != '-')
{
vector<option> result;
string name = tok.substr(0,2);
string adjacent = tok.substr(2);
// Short options can be 'grouped', so that
// "-d -a" becomes "-da". Loop, processing one
// option at a time. We exit the loop when either
// we've processed all the token, or when the remainder
// of token is considered to be value, not further grouped
// option.
for(;;) {
const option_description* d;
try
{
d = m_desc->find_nothrow(name, false, false,
is_style_active(short_case_insensitive));
}
catch(error_with_option_name& e)
{
// add context and rethrow
e.add_context(name, name, get_canonical_option_prefix());
throw;
}
// FIXME: check for 'allow_sticky'.
if (d && (m_style & allow_sticky) &&
d->semantic()->max_tokens() == 0 && !adjacent.empty()) {
// 'adjacent' is in fact further option.
option opt;
opt.string_key = name;
result.push_back(opt);
if (adjacent.empty())
{
args.erase(args.begin());
break;
}
name = string("-") + adjacent[0];
adjacent.erase(adjacent.begin());
} else {
option opt;
opt.string_key = name;
opt.original_tokens.push_back(tok);
if (!adjacent.empty())
opt.value.push_back(adjacent);
result.push_back(opt);
args.erase(args.begin());
break;
}
}
return result;
}
return vector<option>();
}
vector<option>
cmdline::parse_dos_option(vector<string>& args)
{
vector<option> result;
const string& tok = args[0];
if (tok.size() >= 2 && tok[0] == '/')
{
string name = "-" + tok.substr(1,1);
string adjacent = tok.substr(2);
option opt;
opt.string_key = name;
if (!adjacent.empty())
opt.value.push_back(adjacent);
opt.original_tokens.push_back(tok);
result.push_back(opt);
args.erase(args.begin());
}
return result;
}
vector<option>
cmdline::parse_disguised_long_option(vector<string>& args)
{
const string& tok = args[0];
if (tok.size() >= 2 &&
((tok[0] == '-' && tok[1] != '-') ||
((m_style & allow_slash_for_short) && tok[0] == '/')))
{
try
{
if (m_desc->find_nothrow(tok.substr(1, tok.find('=')-1),
is_style_active(allow_guessing),
is_style_active(long_case_insensitive),
is_style_active(short_case_insensitive)))
{
args[0].insert(0, "-");
if (args[0][1] == '/')
args[0][1] = '-';
return parse_long_option(args);
}
}
catch(error_with_option_name& e)
{
// add context and rethrow
e.add_context(tok, tok, get_canonical_option_prefix());
throw;
}
}
return vector<option>();
}
vector<option>
cmdline::parse_terminator(vector<string>& args)
{
vector<option> result;
const string& tok = args[0];
if (tok == "--")
{
for(unsigned i = 1; i < args.size(); ++i)
{
option opt;
opt.value.push_back(args[i]);
opt.original_tokens.push_back(args[i]);
opt.position_key = INT_MAX;
result.push_back(opt);
}
args.clear();
}
return result;
}
vector<option>
cmdline::handle_additional_parser(vector<string>& args)
{
vector<option> result;
pair<string, string> r = m_additional_parser(args[0]);
if (!r.first.empty()) {
option next;
next.string_key = r.first;
if (!r.second.empty())
next.value.push_back(r.second);
result.push_back(next);
args.erase(args.begin());
}
return result;
}
void
cmdline::set_additional_parser(additional_parser p)
{
m_additional_parser = p;
}
void
cmdline::extra_style_parser(style_parser s)
{
m_style_parser = s;
}
}}}
+198
View File
@@ -0,0 +1,198 @@
// Copyright Vladimir Prus 2002-2004.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/config.hpp>
#include <boost/program_options/detail/config_file.hpp>
#include <boost/program_options/errors.hpp>
#include <boost/program_options/detail/convert.hpp>
#include <boost/throw_exception.hpp>
#include <iostream>
#include <fstream>
#include <cassert>
namespace boost { namespace program_options { namespace detail {
using namespace std;
common_config_file_iterator::common_config_file_iterator(
const std::set<std::string>& allowed_options,
bool allow_unregistered)
: allowed_options(allowed_options),
m_allow_unregistered(allow_unregistered)
{
for(std::set<std::string>::const_iterator i = allowed_options.begin();
i != allowed_options.end();
++i)
{
add_option(i->c_str());
}
}
void
common_config_file_iterator::add_option(const char* name)
{
string s(name);
assert(!s.empty());
if (*s.rbegin() == '*') {
s.resize(s.size()-1);
bool bad_prefixes(false);
// If 's' is a prefix of one of allowed suffix, then
// lower_bound will return that element.
// If some element is prefix of 's', then lower_bound will
// return the next element.
set<string>::iterator i = allowed_prefixes.lower_bound(s);
if (i != allowed_prefixes.end()) {
if (i->find(s) == 0)
bad_prefixes = true;
}
if (i != allowed_prefixes.begin()) {
--i;
if (s.find(*i) == 0)
bad_prefixes = true;
}
if (bad_prefixes)
boost::throw_exception(error("options '" + string(name) + "' and '" +
*i + "*' will both match the same "
"arguments from the configuration file"));
allowed_prefixes.insert(s);
}
}
namespace {
string trim_ws(const string& s)
{
string::size_type n, n2;
n = s.find_first_not_of(" \t\r\n");
if (n == string::npos)
return string();
else {
n2 = s.find_last_not_of(" \t\r\n");
return s.substr(n, n2-n+1);
}
}
}
void common_config_file_iterator::get()
{
string s;
string::size_type n;
bool found = false;
while(this->getline(s)) {
// strip '#' comments and whitespace
if ((n = s.find('#')) != string::npos)
s = s.substr(0, n);
s = trim_ws(s);
if (!s.empty()) {
// Handle section name
if (*s.begin() == '[' && *s.rbegin() == ']') {
m_prefix = s.substr(1, s.size()-2);
if (*m_prefix.rbegin() != '.')
m_prefix += '.';
}
else if ((n = s.find('=')) != string::npos) {
string name = m_prefix + trim_ws(s.substr(0, n));
string value = trim_ws(s.substr(n+1));
bool registered = allowed_option(name);
if (!registered && !m_allow_unregistered)
boost::throw_exception(unknown_option(name));
found = true;
this->value().string_key = name;
this->value().value.clear();
this->value().value.push_back(value);
this->value().unregistered = !registered;
this->value().original_tokens.clear();
this->value().original_tokens.push_back(name);
this->value().original_tokens.push_back(value);
break;
} else {
boost::throw_exception(invalid_config_file_syntax(s, invalid_syntax::unrecognized_line));
}
}
}
if (!found)
found_eof();
}
bool
common_config_file_iterator::allowed_option(const std::string& s) const
{
set<string>::const_iterator i = allowed_options.find(s);
if (i != allowed_options.end())
return true;
// If s is "pa" where "p" is allowed prefix then
// lower_bound should find the element after "p".
// This depends on 'allowed_prefixes' invariant.
i = allowed_prefixes.lower_bound(s);
if (i != allowed_prefixes.begin() && s.find(*--i) == 0)
return true;
return false;
}
#if BOOST_WORKAROUND(__COMO_VERSION__, BOOST_TESTED_AT(4303)) || \
(defined(__sgi) && BOOST_WORKAROUND(_COMPILER_VERSION, BOOST_TESTED_AT(741)))
template<>
bool
basic_config_file_iterator<wchar_t>::getline(std::string& s)
{
std::wstring ws;
// On Comeau, using two-argument version causes
// call to some internal function with std::wstring, and '\n'
// (not L'\n') and compile can't resolve that call.
if (std::getline(*is, ws, L'\n')) {
s = to_utf8(ws);
return true;
} else {
return false;
}
}
#endif
}}}
#if 0
using boost::program_options::config_file;
#include <sstream>
#include <cassert>
int main()
{
try {
stringstream s(
"a = 1\n"
"b = 2\n");
config_file cf(s);
cf.add_option("a");
cf.add_option("b");
assert(++cf);
assert(cf.name() == "a");
assert(cf.value() == "1");
assert(++cf);
assert(cf.name() == "b");
assert(cf.value() == "2");
assert(!++cf);
}
catch(exception& e)
{
cout << e.what() << "\n";
}
}
#endif
+161
View File
@@ -0,0 +1,161 @@
// Copyright Vladimir Prus 2004.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <fstream>
#include <locale.h>
#include <locale>
#include <iostream>
#include <string>
#include <locale>
#include <stdexcept>
#include <boost/config.hpp>
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/config.hpp>
#include <boost/program_options/detail/convert.hpp>
#include <boost/program_options/detail/utf8_codecvt_facet.hpp>
#include <boost/throw_exception.hpp>
#include <boost/bind.hpp>
using namespace std;
namespace boost { namespace detail {
/* Internal function to actually perform conversion.
The logic in from_8_bit and to_8_bit function is exactly
the same, except that one calls 'in' method of codecvt and another
calls the 'out' method, and that syntax difference makes straightforward
template implementation impossible.
This functions takes a 'fun' argument, which should have the same
parameters and return type and the in/out methods. The actual converting
function will pass functional objects created with boost::bind.
Experiments show that the performance loss is less than 10%.
*/
template<class ToChar, class FromChar, class Fun>
std::basic_string<ToChar>
convert(const std::basic_string<FromChar>& s, Fun fun)
{
std::basic_string<ToChar> result;
std::mbstate_t state = std::mbstate_t();
const FromChar* from = s.data();
const FromChar* from_end = s.data() + s.size();
// The interface of cvt is not really iterator-like, and it's
// not possible the tell the required output size without the conversion.
// All we can is convert data by pieces.
while(from != from_end) {
// std::basic_string does not provide non-const pointers to the data,
// so converting directly into string is not possible.
ToChar buffer[32];
ToChar* to_next = buffer;
// Need variable because boost::bind doesn't work with rvalues.
ToChar* to_end = buffer + 32;
std::codecvt_base::result r =
fun(state, from, from_end, from, buffer, to_end, to_next);
if (r == std::codecvt_base::error)
boost::throw_exception(
std::logic_error("character conversion failed"));
// 'partial' is not an error, it just means not all source
// characters were converted. However, we need to check that at
// least one new target character was produced. If not, it means
// the source data is incomplete, and since we don't have extra
// data to add to source, it's error.
if (to_next == buffer)
boost::throw_exception(
std::logic_error("character conversion failed"));
// Add converted characters
result.append(buffer, to_next);
}
return result;
}
}}
namespace boost {
#ifndef BOOST_NO_STD_WSTRING
BOOST_PROGRAM_OPTIONS_DECL std::wstring
from_8_bit(const std::string& s,
const std::codecvt<wchar_t, char, std::mbstate_t>& cvt)
{
return detail::convert<wchar_t>(
s,
boost::bind(&std::codecvt<wchar_t, char, mbstate_t>::in,
&cvt,
_1, _2, _3, _4, _5, _6, _7));
}
BOOST_PROGRAM_OPTIONS_DECL std::string
to_8_bit(const std::wstring& s,
const std::codecvt<wchar_t, char, std::mbstate_t>& cvt)
{
return detail::convert<char>(
s,
boost::bind(&codecvt<wchar_t, char, mbstate_t>::out,
&cvt,
_1, _2, _3, _4, _5, _6, _7));
}
namespace {
boost::program_options::detail::utf8_codecvt_facet
utf8_facet;
}
BOOST_PROGRAM_OPTIONS_DECL std::wstring
from_utf8(const std::string& s)
{
return from_8_bit(s, utf8_facet);
}
BOOST_PROGRAM_OPTIONS_DECL std::string
to_utf8(const std::wstring& s)
{
return to_8_bit(s, utf8_facet);
}
BOOST_PROGRAM_OPTIONS_DECL std::wstring
from_local_8_bit(const std::string& s)
{
typedef codecvt<wchar_t, char, mbstate_t> facet_type;
return from_8_bit(s,
BOOST_USE_FACET(facet_type, locale()));
}
BOOST_PROGRAM_OPTIONS_DECL std::string
to_local_8_bit(const std::wstring& s)
{
typedef codecvt<wchar_t, char, mbstate_t> facet_type;
return to_8_bit(s,
BOOST_USE_FACET(facet_type, locale()));
}
#endif
namespace program_options
{
BOOST_PROGRAM_OPTIONS_DECL std::string to_internal(const std::string& s)
{
return s;
}
#ifndef BOOST_NO_STD_WSTRING
BOOST_PROGRAM_OPTIONS_DECL std::string to_internal(const std::wstring& s)
{
return to_utf8(s);
}
#endif
}
}
@@ -0,0 +1,664 @@
// Copyright Vladimir Prus 2002-2004.
// Copyright Bertolt Mildner 2004.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/config.hpp>
#include <boost/program_options/options_description.hpp>
// FIXME: this is only to get multiple_occurrences class
// should move that to a separate headers.
#include <boost/program_options/parsers.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/throw_exception.hpp>
#include <cassert>
#include <climits>
#include <cstring>
#include <cstdarg>
#include <sstream>
#include <iterator>
using namespace std;
namespace boost { namespace program_options {
namespace {
template< class charT >
std::basic_string< charT > tolower_(const std::basic_string< charT >& str)
{
std::basic_string< charT > result;
for (typename std::basic_string< charT >::size_type i = 0; i < str.size(); ++i)
{
result.append(1, static_cast< charT >(std::tolower(str[i])));
}
return result;
}
} // unnamed namespace
option_description::option_description()
{
}
option_description::
option_description(const char* name,
const value_semantic* s)
: m_value_semantic(s)
{
this->set_name(name);
}
option_description::
option_description(const char* name,
const value_semantic* s,
const char* description)
: m_description(description), m_value_semantic(s)
{
this->set_name(name);
}
option_description::~option_description()
{
}
option_description::match_result
option_description::match(const std::string& option,
bool approx,
bool long_ignore_case,
bool short_ignore_case) const
{
match_result result = no_match;
std::string local_long_name((long_ignore_case ? tolower_(m_long_name) : m_long_name));
if (!local_long_name.empty()) {
std::string local_option = (long_ignore_case ? tolower_(option) : option);
if (*local_long_name.rbegin() == '*')
{
// The name ends with '*'. Any specified name with the given
// prefix is OK.
if (local_option.find(local_long_name.substr(0, local_long_name.length()-1))
== 0)
result = approximate_match;
}
if (local_long_name == local_option)
{
result = full_match;
}
else if (approx)
{
if (local_long_name.find(local_option) == 0)
{
result = approximate_match;
}
}
}
if (result != full_match)
{
std::string local_option(short_ignore_case ? tolower_(option) : option);
std::string local_short_name(short_ignore_case ? tolower_(m_short_name) : m_short_name);
if (local_short_name == local_option)
{
result = full_match;
}
}
return result;
}
const std::string&
option_description::key(const std::string& option) const
{
if (!m_long_name.empty())
if (m_long_name.find('*') != string::npos)
// The '*' character means we're long_name
// matches only part of the input. So, returning
// long name will remove some of the information,
// and we have to return the option as specified
// in the source.
return option;
else
return m_long_name;
else
return m_short_name;
}
std::string
option_description::canonical_display_name(int prefix_style) const
{
if (!m_long_name.empty())
{
if (prefix_style == command_line_style::allow_long)
return "--" + m_long_name;
if (prefix_style == command_line_style::allow_long_disguise)
return "-" + m_long_name;
}
// sanity check: m_short_name[0] should be '-' or '/'
if (m_short_name.length() == 2)
{
if (prefix_style == command_line_style::allow_slash_for_short)
return string("/") + m_short_name[1];
if (prefix_style == command_line_style::allow_dash_for_short)
return string("-") + m_short_name[1];
}
if (!m_long_name.empty())
return m_long_name;
else
return m_short_name;
}
const std::string&
option_description::long_name() const
{
return m_long_name;
}
option_description&
option_description::set_name(const char* _name)
{
std::string name(_name);
string::size_type n = name.find(',');
if (n != string::npos) {
assert(n == name.size()-2);
m_long_name = name.substr(0, n);
m_short_name = '-' + name.substr(n+1,1);
} else {
m_long_name = name;
}
return *this;
}
const std::string&
option_description::description() const
{
return m_description;
}
shared_ptr<const value_semantic>
option_description::semantic() const
{
return m_value_semantic;
}
std::string
option_description::format_name() const
{
if (!m_short_name.empty())
{
return m_long_name.empty()
? m_short_name
: string(m_short_name).append(" [ --").
append(m_long_name).append(" ]");
}
return string("--").append(m_long_name);
}
std::string
option_description::format_parameter() const
{
if (m_value_semantic->max_tokens() != 0)
return m_value_semantic->name();
else
return "";
}
options_description_easy_init::
options_description_easy_init(options_description* owner)
: owner(owner)
{}
options_description_easy_init&
options_description_easy_init::
operator()(const char* name,
const char* description)
{
// Create untypes semantic which accepts zero tokens: i.e.
// no value can be specified on command line.
// FIXME: does not look exception-safe
shared_ptr<option_description> d(
new option_description(name, new untyped_value(true), description));
owner->add(d);
return *this;
}
options_description_easy_init&
options_description_easy_init::
operator()(const char* name,
const value_semantic* s)
{
shared_ptr<option_description> d(new option_description(name, s));
owner->add(d);
return *this;
}
options_description_easy_init&
options_description_easy_init::
operator()(const char* name,
const value_semantic* s,
const char* description)
{
shared_ptr<option_description> d(new option_description(name, s, description));
owner->add(d);
return *this;
}
const unsigned options_description::m_default_line_length = 80;
options_description::options_description(unsigned line_length,
unsigned min_description_length)
: m_line_length(line_length)
, m_min_description_length(min_description_length)
{
// we require a space between the option and description parts, so add 1.
assert(m_min_description_length < m_line_length - 1);
}
options_description::options_description(const std::string& caption,
unsigned line_length,
unsigned min_description_length)
: m_caption(caption)
, m_line_length(line_length)
, m_min_description_length(min_description_length)
{
// we require a space between the option and description parts, so add 1.
assert(m_min_description_length < m_line_length - 1);
}
void
options_description::add(shared_ptr<option_description> desc)
{
m_options.push_back(desc);
belong_to_group.push_back(false);
}
options_description&
options_description::add(const options_description& desc)
{
shared_ptr<options_description> d(new options_description(desc));
groups.push_back(d);
for (size_t i = 0; i < desc.m_options.size(); ++i) {
add(desc.m_options[i]);
belong_to_group.back() = true;
}
return *this;
}
options_description_easy_init
options_description::add_options()
{
return options_description_easy_init(this);
}
const option_description&
options_description::find(const std::string& name,
bool approx,
bool long_ignore_case,
bool short_ignore_case) const
{
const option_description* d = find_nothrow(name, approx,
long_ignore_case, short_ignore_case);
if (!d)
boost::throw_exception(unknown_option());
return *d;
}
const std::vector< shared_ptr<option_description> >&
options_description::options() const
{
return m_options;
}
const option_description*
options_description::find_nothrow(const std::string& name,
bool approx,
bool long_ignore_case,
bool short_ignore_case) const
{
shared_ptr<option_description> found;
bool had_full_match = false;
vector<string> approximate_matches;
vector<string> full_matches;
// We use linear search because matching specified option
// name with the declared option name need to take care about
// case sensitivity and trailing '*' and so we can't use simple map.
for(unsigned i = 0; i < m_options.size(); ++i)
{
option_description::match_result r =
m_options[i]->match(name, approx, long_ignore_case, short_ignore_case);
if (r == option_description::no_match)
continue;
if (r == option_description::full_match)
{
full_matches.push_back(m_options[i]->key(name));
found = m_options[i];
had_full_match = true;
}
else
{
// FIXME: the use of 'key' here might not
// be the best approach.
approximate_matches.push_back(m_options[i]->key(name));
if (!had_full_match)
found = m_options[i];
}
}
if (full_matches.size() > 1)
boost::throw_exception(ambiguous_option(full_matches));
// If we have a full match, and an approximate match,
// ignore approximate match instead of reporting error.
// Say, if we have options "all" and "all-chroots", then
// "--all" on the command line should select the first one,
// without ambiguity.
if (full_matches.empty() && approximate_matches.size() > 1)
boost::throw_exception(ambiguous_option(approximate_matches));
return found.get();
}
BOOST_PROGRAM_OPTIONS_DECL
std::ostream& operator<<(std::ostream& os, const options_description& desc)
{
desc.print(os);
return os;
}
namespace {
/* Given a string 'par', that contains no newline characters
outputs it to 'os' with wordwrapping, that is, as several
line.
Each output line starts with 'indent' space characters,
following by characters from 'par'. The total length of
line is no longer than 'line_length'.
*/
void format_paragraph(std::ostream& os,
std::string par,
unsigned indent,
unsigned line_length)
{
// Through reminder of this function, 'line_length' will
// be the length available for characters, not including
// indent.
assert(indent < line_length);
line_length -= indent;
// index of tab (if present) is used as additional indent relative
// to first_column_width if paragrapth is spanned over multiple
// lines if tab is not on first line it is ignored
string::size_type par_indent = par.find('\t');
if (par_indent == string::npos)
{
par_indent = 0;
}
else
{
// only one tab per paragraph allowed
if (count(par.begin(), par.end(), '\t') > 1)
{
boost::throw_exception(program_options::error(
"Only one tab per paragraph is allowed in the options description"));
}
// erase tab from string
par.erase(par_indent, 1);
// this assert may fail due to user error or
// environment conditions!
assert(par_indent < line_length);
// ignore tab if not on first line
if (par_indent >= line_length)
{
par_indent = 0;
}
}
if (par.size() < line_length)
{
os << par;
}
else
{
string::const_iterator line_begin = par.begin();
const string::const_iterator par_end = par.end();
bool first_line = true; // of current paragraph!
while (line_begin < par_end) // paragraph lines
{
if (!first_line)
{
// If line starts with space, but second character
// is not space, remove the leading space.
// We don't remove double spaces because those
// might be intentianal.
if ((*line_begin == ' ') &&
((line_begin + 1 < par_end) &&
(*(line_begin + 1) != ' ')))
{
line_begin += 1; // line_begin != line_end
}
}
// Take care to never increment the iterator past
// the end, since MSVC 8.0 (brokenly), assumes that
// doing that, even if no access happens, is a bug.
unsigned remaining = static_cast<unsigned>(std::distance(line_begin, par_end));
string::const_iterator line_end = line_begin +
((remaining < line_length) ? remaining : line_length);
// prevent chopped words
// Is line_end between two non-space characters?
if ((*(line_end - 1) != ' ') &&
((line_end < par_end) && (*line_end != ' ')))
{
// find last ' ' in the second half of the current paragraph line
string::const_iterator last_space =
find(reverse_iterator<string::const_iterator>(line_end),
reverse_iterator<string::const_iterator>(line_begin),
' ')
.base();
if (last_space != line_begin)
{
// is last_space within the second half ot the
// current line
if (static_cast<unsigned>(std::distance(last_space, line_end)) <
(line_length / 2))
{
line_end = last_space;
}
}
} // prevent chopped words
// write line to stream
copy(line_begin, line_end, ostream_iterator<char>(os));
if (first_line)
{
indent += static_cast<unsigned>(par_indent);
line_length -= static_cast<unsigned>(par_indent); // there's less to work with now
first_line = false;
}
// more lines to follow?
if (line_end != par_end)
{
os << '\n';
for(unsigned pad = indent; pad > 0; --pad)
{
os.put(' ');
}
}
// next line starts after of this line
line_begin = line_end;
} // paragraph lines
}
}
void format_description(std::ostream& os,
const std::string& desc,
unsigned first_column_width,
unsigned line_length)
{
// we need to use one char less per line to work correctly if actual
// console has longer lines
assert(line_length > 1);
if (line_length > 1)
{
--line_length;
}
// line_length must be larger than first_column_width
// this assert may fail due to user error or environment conditions!
assert(line_length > first_column_width);
// Note: can't use 'tokenizer' as name of typedef -- borland
// will consider uses of 'tokenizer' below as uses of
// boost::tokenizer, not typedef.
typedef boost::tokenizer<boost::char_separator<char> > tok;
tok paragraphs(
desc,
char_separator<char>("\n", "", boost::keep_empty_tokens));
tok::const_iterator par_iter = paragraphs.begin();
const tok::const_iterator par_end = paragraphs.end();
while (par_iter != par_end) // paragraphs
{
format_paragraph(os, *par_iter, first_column_width,
line_length);
++par_iter;
// prepair next line if any
if (par_iter != par_end)
{
os << '\n';
for(unsigned pad = first_column_width; pad > 0; --pad)
{
os.put(' ');
}
}
} // paragraphs
}
void format_one(std::ostream& os, const option_description& opt,
unsigned first_column_width, unsigned line_length)
{
stringstream ss;
ss << " " << opt.format_name() << ' ' << opt.format_parameter();
// Don't use ss.rdbuf() since g++ 2.96 is buggy on it.
os << ss.str();
if (!opt.description().empty())
{
if (ss.str().size() >= first_column_width)
{
os.put('\n'); // first column is too long, lets put description in new line
for (unsigned pad = first_column_width; pad > 0; --pad)
{
os.put(' ');
}
} else {
for(unsigned pad = first_column_width - static_cast<unsigned>(ss.str().size()); pad > 0; --pad)
{
os.put(' ');
}
}
format_description(os, opt.description(),
first_column_width, line_length);
}
}
}
unsigned
options_description::get_option_column_width() const
{
/* Find the maximum width of the option column */
unsigned width(23);
unsigned i; // vc6 has broken for loop scoping
for (i = 0; i < m_options.size(); ++i)
{
const option_description& opt = *m_options[i];
stringstream ss;
ss << " " << opt.format_name() << ' ' << opt.format_parameter();
width = (max)(width, static_cast<unsigned>(ss.str().size()));
}
/* Get width of groups as well*/
for (unsigned j = 0; j < groups.size(); ++j)
width = max(width, groups[j]->get_option_column_width());
/* this is the column were description should start, if first
column is longer, we go to a new line */
const unsigned start_of_description_column = m_line_length - m_min_description_length;
width = (min)(width, start_of_description_column-1);
/* add an additional space to improve readability */
++width;
return width;
}
void
options_description::print(std::ostream& os, unsigned width) const
{
if (!m_caption.empty())
os << m_caption << ":\n";
if (!width)
width = get_option_column_width();
/* The options formatting style is stolen from Subversion. */
for (unsigned i = 0; i < m_options.size(); ++i)
{
if (belong_to_group[i])
continue;
const option_description& opt = *m_options[i];
format_one(os, opt, width, m_line_length);
os << "\n";
}
for (unsigned j = 0; j < groups.size(); ++j) {
os << "\n";
groups[j]->print(os, width);
}
}
}}
+249
View File
@@ -0,0 +1,249 @@
// Copyright Vladimir Prus 2002-2004.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/config.hpp>
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/config.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/positional_options.hpp>
#include <boost/program_options/detail/cmdline.hpp>
#include <boost/program_options/detail/config_file.hpp>
#include <boost/program_options/environment_iterator.hpp>
#include <boost/program_options/detail/convert.hpp>
#include <boost/bind.hpp>
#include <boost/throw_exception.hpp>
#include <cctype>
#include <fstream>
#if !defined(__GNUC__) || __GNUC__ < 3
#include <iostream>
#else
#include <istream>
#endif
#ifdef _WIN32
#include <stdlib.h>
#else
#include <unistd.h>
#endif
// The 'environ' should be declared in some cases. E.g. Linux man page says:
// (This variable must be declared in the user program, but is declared in
// the header file unistd.h in case the header files came from libc4 or libc5,
// and in case they came from glibc and _GNU_SOURCE was defined.)
// To be safe, declare it here.
// It appears that on Mac OS X the 'environ' variable is not
// available to dynamically linked libraries.
// See: http://article.gmane.org/gmane.comp.lib.boost.devel/103843
// See: http://lists.gnu.org/archive/html/bug-guile/2004-01/msg00013.html
#if defined(__APPLE__) && defined(__DYNAMIC__)
// The proper include for this is crt_externs.h, however it's not
// available on iOS. The right replacement is not known. See
// https://svn.boost.org/trac/boost/ticket/5053
extern "C" { extern char ***_NSGetEnviron(void); }
#define environ (*_NSGetEnviron())
#else
#if defined(__MWERKS__)
#include <crtl.h>
#else
#if !defined(_WIN32) || defined(__COMO_VERSION__)
extern char** environ;
#endif
#endif
#endif
using namespace std;
namespace boost { namespace program_options {
#ifndef BOOST_NO_STD_WSTRING
namespace {
woption woption_from_option(const option& opt)
{
woption result;
result.string_key = opt.string_key;
result.position_key = opt.position_key;
result.unregistered = opt.unregistered;
std::transform(opt.value.begin(), opt.value.end(),
back_inserter(result.value),
boost::bind(from_utf8, _1));
std::transform(opt.original_tokens.begin(),
opt.original_tokens.end(),
back_inserter(result.original_tokens),
boost::bind(from_utf8, _1));
return result;
}
}
basic_parsed_options<wchar_t>
::basic_parsed_options(const parsed_options& po)
: description(po.description),
utf8_encoded_options(po),
m_options_prefix(po.m_options_prefix)
{
for (unsigned i = 0; i < po.options.size(); ++i)
options.push_back(woption_from_option(po.options[i]));
}
#endif
template<class charT>
basic_parsed_options<charT>
parse_config_file(std::basic_istream<charT>& is,
const options_description& desc,
bool allow_unregistered)
{
set<string> allowed_options;
const vector<shared_ptr<option_description> >& options = desc.options();
for (unsigned i = 0; i < options.size(); ++i)
{
const option_description& d = *options[i];
if (d.long_name().empty())
boost::throw_exception(
error("abbreviated option names are not permitted in options configuration files"));
allowed_options.insert(d.long_name());
}
// Parser return char strings
parsed_options result(&desc);
copy(detail::basic_config_file_iterator<charT>(
is, allowed_options, allow_unregistered),
detail::basic_config_file_iterator<charT>(),
back_inserter(result.options));
// Convert char strings into desired type.
return basic_parsed_options<charT>(result);
}
template
BOOST_PROGRAM_OPTIONS_DECL basic_parsed_options<char>
parse_config_file(std::basic_istream<char>& is,
const options_description& desc,
bool allow_unregistered);
#ifndef BOOST_NO_STD_WSTRING
template
BOOST_PROGRAM_OPTIONS_DECL basic_parsed_options<wchar_t>
parse_config_file(std::basic_istream<wchar_t>& is,
const options_description& desc,
bool allow_unregistered);
#endif
template<class charT>
basic_parsed_options<charT>
parse_config_file(const char* filename,
const options_description& desc,
bool allow_unregistered)
{
// Parser return char strings
std::basic_ifstream< charT > strm(filename);
if (!strm)
{
boost::throw_exception(reading_file(filename));
}
return parse_config_file(strm, desc, allow_unregistered);
}
template
BOOST_PROGRAM_OPTIONS_DECL basic_parsed_options<char>
parse_config_file(const char* filename,
const options_description& desc,
bool allow_unregistered);
#ifndef BOOST_NO_STD_WSTRING
template
BOOST_PROGRAM_OPTIONS_DECL basic_parsed_options<wchar_t>
parse_config_file(const char* filename,
const options_description& desc,
bool allow_unregistered);
#endif
// This versio, which accepts any options without validation, is disabled,
// in the hope that nobody will need it and we cant drop it altogether.
// Besides, probably the right way to handle all options is the '*' name.
#if 0
BOOST_PROGRAM_OPTIONS_DECL parsed_options
parse_config_file(std::istream& is)
{
detail::config_file_iterator cf(is, false);
parsed_options result(0);
copy(cf, detail::config_file_iterator(),
back_inserter(result.options));
return result;
}
#endif
BOOST_PROGRAM_OPTIONS_DECL parsed_options
parse_environment(const options_description& desc,
const function1<std::string, std::string>& name_mapper)
{
parsed_options result(&desc);
for(environment_iterator i(environ), e; i != e; ++i) {
string option_name = name_mapper(i->first);
if (!option_name.empty()) {
option n;
n.string_key = option_name;
n.value.push_back(i->second);
result.options.push_back(n);
}
}
return result;
}
namespace detail {
class prefix_name_mapper {
public:
prefix_name_mapper(const std::string& prefix)
: prefix(prefix)
{}
std::string operator()(const std::string& s)
{
string result;
if (s.find(prefix) == 0) {
for(string::size_type n = prefix.size(); n < s.size(); ++n)
{
// Intel-Win-7.1 does not understand
// push_back on string.
result += static_cast<char>(tolower(s[n]));
}
}
return result;
}
private:
std::string prefix;
};
}
BOOST_PROGRAM_OPTIONS_DECL parsed_options
parse_environment(const options_description& desc,
const std::string& prefix)
{
return parse_environment(desc, detail::prefix_name_mapper(prefix));
}
BOOST_PROGRAM_OPTIONS_DECL parsed_options
parse_environment(const options_description& desc, const char* prefix)
{
return parse_environment(desc, string(prefix));
}
}}
@@ -0,0 +1,53 @@
// Copyright Vladimir Prus 2004.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/config.hpp>
#include <boost/program_options/positional_options.hpp>
#include <boost/limits.hpp>
#include <cassert>
namespace boost { namespace program_options {
positional_options_description::positional_options_description()
{}
positional_options_description&
positional_options_description::add(const char* name, int max_count)
{
assert(max_count != -1 || m_trailing.empty());
if (max_count == -1)
m_trailing = name;
else {
m_names.resize(m_names.size() + max_count, name);
}
return *this;
}
unsigned
positional_options_description::max_total_count() const
{
return m_trailing.empty() ?
static_cast<unsigned>(m_names.size()) : (std::numeric_limits<unsigned>::max)();
}
const std::string&
positional_options_description::name_for_position(unsigned position) const
{
assert(position < max_total_count());
if (position < m_names.size())
return m_names[position];
else
return m_trailing;
}
}}
+62
View File
@@ -0,0 +1,62 @@
// Copyright Sascha Ochsenknecht 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/parsers.hpp>
#include <boost/tokenizer.hpp>
#include <string>
#include <vector>
namespace boost { namespace program_options { namespace detail {
template< class charT >
std::vector<std::basic_string<charT> >
split_unix(
const std::basic_string<charT>& cmdline,
const std::basic_string<charT>& seperator,
const std::basic_string<charT>& quote,
const std::basic_string<charT>& escape)
{
typedef boost::tokenizer< boost::escaped_list_separator<charT>,
typename std::basic_string<charT>::const_iterator,
std::basic_string<charT> > tokenizerT;
tokenizerT tok(cmdline.begin(), cmdline.end(),
boost::escaped_list_separator< charT >(escape, seperator, quote));
std::vector< std::basic_string<charT> > result;
for (typename tokenizerT::iterator cur_token(tok.begin()), end_token(tok.end()); cur_token != end_token; ++cur_token) {
if (!cur_token->empty())
result.push_back(*cur_token);
}
return result;
}
}}} // namespace
namespace boost { namespace program_options {
// Take a command line string and splits in into tokens, according
// to the given collection of seperators chars.
BOOST_PROGRAM_OPTIONS_DECL std::vector<std::string>
split_unix(const std::string& cmdline, const std::string& seperator,
const std::string& quote, const std::string& escape)
{
return detail::split_unix< char >(cmdline, seperator, quote, escape);
}
#ifndef BOOST_NO_STD_WSTRING
BOOST_PROGRAM_OPTIONS_DECL std::vector<std::wstring>
split_unix(const std::wstring& cmdline, const std::wstring& seperator,
const std::wstring& quote, const std::wstring& escape)
{
return detail::split_unix< wchar_t >(cmdline, seperator, quote, escape);
}
#endif
}} // namespace
@@ -0,0 +1,21 @@
// Copyright Vladimir Prus 2004.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/config.hpp>
#define BOOST_UTF8_BEGIN_NAMESPACE \
namespace boost { namespace program_options { namespace detail {
#define BOOST_UTF8_END_NAMESPACE }}}
#define BOOST_UTF8_DECL BOOST_PROGRAM_OPTIONS_DECL
#include <boost/detail/utf8_codecvt_facet.ipp>
#undef BOOST_UTF8_BEGIN_NAMESPACE
#undef BOOST_UTF8_END_NAMESPACE
#undef BOOST_UTF8_DECL
+428
View File
@@ -0,0 +1,428 @@
// Copyright Vladimir Prus 2004.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/config.hpp>
#include <boost/program_options/value_semantic.hpp>
#include <boost/program_options/detail/convert.hpp>
#include <boost/program_options/detail/cmdline.hpp>
#include <set>
#include <cctype>
namespace boost { namespace program_options {
using namespace std;
#ifndef BOOST_NO_STD_WSTRING
namespace
{
std::string convert_value(const std::wstring& s)
{
try {
return to_local_8_bit(s);
}
catch(const std::exception&) {
return "<unrepresentable unicode string>";
}
}
}
#endif
void
value_semantic_codecvt_helper<char>::
parse(boost::any& value_store,
const std::vector<std::string>& new_tokens,
bool utf8) const
{
if (utf8) {
#ifndef BOOST_NO_STD_WSTRING
// Need to convert to local encoding.
std::vector<string> local_tokens;
for (unsigned i = 0; i < new_tokens.size(); ++i) {
std::wstring w = from_utf8(new_tokens[i]);
local_tokens.push_back(to_local_8_bit(w));
}
xparse(value_store, local_tokens);
#else
boost::throw_exception(
std::runtime_error("UTF-8 conversion not supported."));
#endif
} else {
// Already in local encoding, pass unmodified
xparse(value_store, new_tokens);
}
}
#ifndef BOOST_NO_STD_WSTRING
void
value_semantic_codecvt_helper<wchar_t>::
parse(boost::any& value_store,
const std::vector<std::string>& new_tokens,
bool utf8) const
{
std::vector<wstring> tokens;
if (utf8) {
// Convert from utf8
for (unsigned i = 0; i < new_tokens.size(); ++i) {
tokens.push_back(from_utf8(new_tokens[i]));
}
} else {
// Convert from local encoding
for (unsigned i = 0; i < new_tokens.size(); ++i) {
tokens.push_back(from_local_8_bit(new_tokens[i]));
}
}
xparse(value_store, tokens);
}
#endif
BOOST_PROGRAM_OPTIONS_DECL std::string arg("arg");
std::string
untyped_value::name() const
{
return arg;
}
unsigned
untyped_value::min_tokens() const
{
if (m_zero_tokens)
return 0;
else
return 1;
}
unsigned
untyped_value::max_tokens() const
{
if (m_zero_tokens)
return 0;
else
return 1;
}
void
untyped_value::xparse(boost::any& value_store,
const std::vector<std::string>& new_tokens) const
{
if (!value_store.empty())
boost::throw_exception(
multiple_occurrences());
if (new_tokens.size() > 1)
boost::throw_exception(multiple_values());
value_store = new_tokens.empty() ? std::string("") : new_tokens.front();
}
BOOST_PROGRAM_OPTIONS_DECL typed_value<bool>*
bool_switch()
{
return bool_switch(0);
}
BOOST_PROGRAM_OPTIONS_DECL typed_value<bool>*
bool_switch(bool* v)
{
typed_value<bool>* r = new typed_value<bool>(v);
r->default_value(0);
r->zero_tokens();
return r;
}
/* Validates bool value.
Any of "1", "true", "yes", "on" will be converted to "1".<br>
Any of "0", "false", "no", "off" will be converted to "0".<br>
Case is ignored. The 'xs' vector can either be empty, in which
case the value is 'true', or can contain explicit value.
*/
BOOST_PROGRAM_OPTIONS_DECL void validate(any& v, const vector<string>& xs,
bool*, int)
{
check_first_occurrence(v);
string s(get_single_string(xs, true));
for (size_t i = 0; i < s.size(); ++i)
s[i] = char(tolower(s[i]));
if (s.empty() || s == "on" || s == "yes" || s == "1" || s == "true")
v = any(true);
else if (s == "off" || s == "no" || s == "0" || s == "false")
v = any(false);
else
boost::throw_exception(invalid_bool_value(s));
}
// This is blatant copy-paste. However, templating this will cause a problem,
// since wstring can't be constructed/compared with char*. We'd need to
// create auxiliary 'widen' routine to convert from char* into
// needed string type, and that's more work.
#if !defined(BOOST_NO_STD_WSTRING)
BOOST_PROGRAM_OPTIONS_DECL
void validate(any& v, const vector<wstring>& xs, bool*, int)
{
check_first_occurrence(v);
wstring s(get_single_string(xs, true));
for (size_t i = 0; i < s.size(); ++i)
s[i] = wchar_t(tolower(s[i]));
if (s.empty() || s == L"on" || s == L"yes" || s == L"1" || s == L"true")
v = any(true);
else if (s == L"off" || s == L"no" || s == L"0" || s == L"false")
v = any(false);
else
boost::throw_exception(invalid_bool_value(convert_value(s)));
}
#endif
BOOST_PROGRAM_OPTIONS_DECL
void validate(any& v, const vector<string>& xs, std::string*, int)
{
check_first_occurrence(v);
v = any(get_single_string(xs));
}
#if !defined(BOOST_NO_STD_WSTRING)
BOOST_PROGRAM_OPTIONS_DECL
void validate(any& v, const vector<wstring>& xs, std::string*, int)
{
check_first_occurrence(v);
v = any(get_single_string(xs));
}
#endif
namespace validators {
BOOST_PROGRAM_OPTIONS_DECL
void check_first_occurrence(const boost::any& value)
{
if (!value.empty())
boost::throw_exception(
multiple_occurrences());
}
}
invalid_option_value::
invalid_option_value(const std::string& bad_value)
: validation_error(validation_error::invalid_option_value)
{
set_substitute("value", bad_value);
}
#ifndef BOOST_NO_STD_WSTRING
invalid_option_value::
invalid_option_value(const std::wstring& bad_value)
: validation_error(validation_error::invalid_option_value)
{
set_substitute("value", convert_value(bad_value));
}
#endif
invalid_bool_value::
invalid_bool_value(const std::string& bad_value)
: validation_error(validation_error::invalid_bool_value)
{
set_substitute("value", bad_value);
}
error_with_option_name::error_with_option_name( const std::string& template_,
const std::string& option_name,
const std::string& original_token,
int option_style) :
error(template_),
m_option_style(option_style),
m_error_template(template_)
{
// parameter | placeholder | value
// --------- | ----------- | -----
set_substitute_default("canonical_option", "option '%canonical_option%'", "option");
set_substitute_default("value", "argument ('%value%')", "argument");
set_substitute_default("prefix", "%prefix%", "");
m_substitutions["option"] = option_name;
m_substitutions["original_token"] = original_token;
}
const char* error_with_option_name::what() const throw()
{
// will substitute tokens each time what is run()
substitute_placeholders(m_error_template);
return m_message.c_str();
}
void error_with_option_name::replace_token(const string& from, const string& to) const
{
for (;;)
{
std::size_t pos = m_message.find(from.c_str(), 0, from.length());
// not found: all replaced
if (pos == std::string::npos)
return;
m_message.replace(pos, from.length(), to);
}
}
string error_with_option_name::get_canonical_option_prefix() const
{
switch (m_option_style)
{
case command_line_style::allow_dash_for_short:
return "-";
case command_line_style::allow_slash_for_short:
return "/";
case command_line_style::allow_long_disguise:
return "-";
case command_line_style::allow_long:
return "--";
case 0:
return "";
}
throw std::logic_error("error_with_option_name::m_option_style can only be "
"one of [0, allow_dash_for_short, allow_slash_for_short, "
"allow_long_disguise or allow_long]");
}
string error_with_option_name::get_canonical_option_name() const
{
if (!m_substitutions.find("option")->second.length())
return m_substitutions.find("original_token")->second;
string original_token = strip_prefixes(m_substitutions.find("original_token")->second);
string option_name = strip_prefixes(m_substitutions.find("option")->second);
// For long options, use option name
if (m_option_style == command_line_style::allow_long ||
m_option_style == command_line_style::allow_long_disguise)
return get_canonical_option_prefix() + option_name;
// For short options use first letter of original_token
if (m_option_style && original_token.length())
return get_canonical_option_prefix() + original_token[0];
// no prefix
return option_name;
}
void error_with_option_name::substitute_placeholders(const string& error_template) const
{
m_message = error_template;
std::map<std::string, std::string> substitutions(m_substitutions);
substitutions["canonical_option"] = get_canonical_option_name();
substitutions["prefix"] = get_canonical_option_prefix();
//
// replace placeholder with defaults if values are missing
//
for (map<string, string_pair>::const_iterator iter = m_substitution_defaults.begin();
iter != m_substitution_defaults.end(); ++iter)
{
// missing parameter: use default
if (substitutions.count(iter->first) == 0 ||
substitutions[iter->first].length() == 0)
replace_token(iter->second.first, iter->second.second);
}
//
// replace placeholder with values
// placeholder are denoted by surrounding '%'
//
for (map<string, string>::iterator iter = substitutions.begin();
iter != substitutions.end(); ++iter)
replace_token('%' + iter->first + '%', iter->second);
}
void ambiguous_option::substitute_placeholders(const string& original_error_template) const
{
// For short forms, all alternatives must be identical, by
// definition, to the specified option, so we don't need to
// display alternatives
if (m_option_style == command_line_style::allow_dash_for_short ||
m_option_style == command_line_style::allow_slash_for_short)
{
error_with_option_name::substitute_placeholders(original_error_template);
return;
}
string error_template = original_error_template;
// remove duplicates using std::set
std::set<std::string> alternatives_set (m_alternatives.begin(), m_alternatives.end());
std::vector<std::string> alternatives_vec (alternatives_set.begin(), alternatives_set.end());
error_template += " and matches ";
// Being very cautious: should be > 1 alternative!
if (alternatives_vec.size() > 1)
{
for (unsigned i = 0; i < alternatives_vec.size() - 1; ++i)
error_template += "'%prefix%" + alternatives_vec[i] + "', ";
error_template += "and ";
}
// there is a programming error if multiple options have the same name...
if (m_alternatives.size() > 1 && alternatives_vec.size() == 1)
error_template += "different versions of ";
error_template += "'%prefix%" + alternatives_vec.back() + "'";
// use inherited logic
error_with_option_name::substitute_placeholders(error_template);
}
string
validation_error::get_template(kind_t kind)
{
// Initially, store the message in 'const char*' variable,
// to avoid conversion to std::string in all cases.
const char* msg;
switch(kind)
{
case invalid_bool_value:
msg = "the argument ('%value%') for option '%canonical_option%' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'";
break;
case invalid_option_value:
msg = "the argument ('%value%') for option '%canonical_option%' is invalid";
break;
case multiple_values_not_allowed:
msg = "option '%canonical_option%' only takes a single argument";
break;
case at_least_one_value_required:
msg = "option '%canonical_option%' requires at least one argument";
break;
// currently unused
case invalid_option:
msg = "option '%canonical_option%' is not valid";
break;
default:
msg = "unknown error";
}
return msg;
}
}}
+249
View File
@@ -0,0 +1,249 @@
// Copyright Vladimir Prus 2002-2004.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/config.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/value_semantic.hpp>
#include <boost/program_options/variables_map.hpp>
#include <cassert>
namespace boost { namespace program_options {
using namespace std;
// First, performs semantic actions for 'oa'.
// Then, stores in 'm' all options that are defined in 'desc'.
BOOST_PROGRAM_OPTIONS_DECL
void store(const parsed_options& options, variables_map& xm,
bool utf8)
{
// TODO: what if we have different definition
// for the same option name during different calls
// 'store'.
assert(options.description);
const options_description& desc = *options.description;
// We need to access map's operator[], not the overriden version
// variables_map. Ehmm.. messy.
std::map<std::string, variable_value>& m = xm;
std::set<std::string> new_final;
// Declared once, to please Intel in VC++ mode;
unsigned i;
// Declared here so can be used to provide context for exceptions
string option_name;
string original_token;
try
{
// First, convert/store all given options
for (i = 0; i < options.options.size(); ++i) {
option_name = options.options[i].string_key;
original_token = options.options[i].original_tokens.size() ?
options.options[i].original_tokens[0] :
option_name;
// Skip positional options without name
if (option_name.empty())
continue;
// Ignore unregistered option. The 'unregistered'
// field can be true only if user has explicitly asked
// to allow unregistered options. We can't store them
// to variables map (lacking any information about paring),
// so just ignore them.
if (options.options[i].unregistered)
continue;
// If option has final value, skip this assignment
if (xm.m_final.count(option_name))
continue;
string original_token = options.options[i].original_tokens.size() ?
options.options[i].original_tokens[0] : "";
const option_description& d = desc.find(option_name, false,
false, false);
variable_value& v = m[option_name];
if (v.defaulted()) {
// Explicit assignment here erases defaulted value
v = variable_value();
}
d.semantic()->parse(v.value(), options.options[i].value, utf8);
v.m_value_semantic = d.semantic();
// The option is not composing, and the value is explicitly
// provided. Ignore values of this option for subsequent
// calls to 'store'. We store this to a temporary set,
// so that several assignment inside *this* 'store' call
// are allowed.
if (!d.semantic()->is_composing())
new_final.insert(option_name);
}
}
#ifndef BOOST_NO_EXCEPTIONS
catch(error_with_option_name& e)
{
// add context and rethrow
e.add_context(option_name, original_token, options.m_options_prefix);
throw;
}
#endif
xm.m_final.insert(new_final.begin(), new_final.end());
// Second, apply default values and store required options.
const vector<shared_ptr<option_description> >& all = desc.options();
for(i = 0; i < all.size(); ++i)
{
const option_description& d = *all[i];
string key = d.key("");
// FIXME: this logic relies on knowledge of option_description
// internals.
// The 'key' is empty if options description contains '*'.
// In that
// case, default value makes no sense at all.
if (key.empty())
{
continue;
}
if (m.count(key) == 0) {
boost::any def;
if (d.semantic()->apply_default(def)) {
m[key] = variable_value(def, true);
m[key].m_value_semantic = d.semantic();
}
}
// add empty value if this is an required option
if (d.semantic()->is_required()) {
// For option names specified in multiple ways, e.g. on the command line,
// config file etc, the following precedence rules apply:
// "--" > ("-" or "/") > ""
// Precedence is set conveniently by a single call to length()
string canonical_name = d.canonical_display_name(options.m_options_prefix);
if (canonical_name.length() > xm.m_required[key].length())
xm.m_required[key] = canonical_name;
}
}
}
BOOST_PROGRAM_OPTIONS_DECL
void store(const wparsed_options& options, variables_map& m)
{
store(options.utf8_encoded_options, m, true);
}
BOOST_PROGRAM_OPTIONS_DECL
void notify(variables_map& vm)
{
vm.notify();
}
abstract_variables_map::abstract_variables_map()
: m_next(0)
{}
abstract_variables_map::
abstract_variables_map(const abstract_variables_map* next)
: m_next(next)
{}
const variable_value&
abstract_variables_map::operator[](const std::string& name) const
{
const variable_value& v = get(name);
if (v.empty() && m_next)
return (*m_next)[name];
else if (v.defaulted() && m_next) {
const variable_value& v2 = (*m_next)[name];
if (!v2.empty() && !v2.defaulted())
return v2;
else return v;
} else {
return v;
}
}
void
abstract_variables_map::next(abstract_variables_map* next)
{
m_next = next;
}
variables_map::variables_map()
{}
variables_map::variables_map(const abstract_variables_map* next)
: abstract_variables_map(next)
{}
void variables_map::clear()
{
std::map<std::string, variable_value>::clear();
m_final.clear();
m_required.clear();
}
const variable_value&
variables_map::get(const std::string& name) const
{
static variable_value empty;
const_iterator i = this->find(name);
if (i == this->end())
return empty;
else
return i->second;
}
void
variables_map::notify()
{
// This checks if all required options occur
for (map<string, string>::const_iterator r = m_required.begin();
r != m_required.end();
++r)
{
const string& opt = r->first;
const string& display_opt = r->second;
map<string, variable_value>::const_iterator iter = find(opt);
if (iter == end() || iter->second.empty())
{
boost::throw_exception(required_option(display_opt));
}
}
// Lastly, run notify actions.
for (map<string, variable_value>::iterator k = begin();
k != end();
++k)
{
/* Users might wish to use variables_map to store their own values
that are not parsed, and therefore will not have value_semantics
defined. Do not crash on such values. In multi-module programs,
one module might add custom values, and the 'notify' function
will be called after that, so we check that value_sematics is
not NULL. See:
https://svn.boost.org/trac/boost/ticket/2782
*/
if (k->second.m_value_semantic)
k->second.m_value_semantic->notify(k->second.value());
}
}
}}
+102
View File
@@ -0,0 +1,102 @@
// Copyright Vladimir Prus 2002-2004.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/parsers.hpp>
#include <cctype>
using std::size_t;
#ifdef _WIN32
namespace boost { namespace program_options {
// Take a command line string and splits in into tokens, according
// to the rules windows command line processor uses.
//
// The rules are pretty funny, see
// http://article.gmane.org/gmane.comp.lib.boost.user/3005
// http://msdn.microsoft.com/library/en-us/vccelng/htm/progs_12.asp
BOOST_PROGRAM_OPTIONS_DECL
std::vector<std::string> split_winmain(const std::string& input)
{
std::vector<std::string> result;
std::string::const_iterator i = input.begin(), e = input.end();
for(;i != e; ++i)
if (!isspace((unsigned char)*i))
break;
if (i != e) {
std::string current;
bool inside_quoted = false;
bool empty_quote = false;
int backslash_count = 0;
for(; i != e; ++i) {
if (*i == '"') {
// '"' preceded by even number (n) of backslashes generates
// n/2 backslashes and is a quoted block delimiter
if (backslash_count % 2 == 0) {
current.append(backslash_count / 2, '\\');
empty_quote = inside_quoted && current.empty();
inside_quoted = !inside_quoted;
// '"' preceded by odd number (n) of backslashes generates
// (n-1)/2 backslashes and is literal quote.
} else {
current.append(backslash_count / 2, '\\');
current += '"';
}
backslash_count = 0;
} else if (*i == '\\') {
++backslash_count;
} else {
// Not quote or backslash. All accumulated backslashes should be
// added
if (backslash_count) {
current.append(backslash_count, '\\');
backslash_count = 0;
}
if (isspace((unsigned char)*i) && !inside_quoted) {
// Space outside quoted section terminate the current argument
result.push_back(current);
current.resize(0);
empty_quote = false;
for(;i != e && isspace((unsigned char)*i); ++i)
;
--i;
} else {
current += *i;
}
}
}
// If we have trailing backslashes, add them
if (backslash_count)
current.append(backslash_count, '\\');
// If we have non-empty 'current' or we're still in quoted
// section (even if 'current' is empty), add the last token.
if (!current.empty() || inside_quoted || empty_quote)
result.push_back(current);
}
return result;
}
#ifndef BOOST_NO_STD_WSTRING
BOOST_PROGRAM_OPTIONS_DECL std::vector<std::wstring>
split_winmain(const std::wstring& cmdline)
{
std::vector<std::wstring> result;
std::vector<std::string> aux = split_winmain(to_internal(cmdline));
for (size_t i = 0, e = aux.size(); i < e; ++i)
result.push_back(from_utf8(aux[i]));
return result;
}
#endif
}}
#endif