blob: f5770f1d0884bc195ac0d98ff46601307bedd36a [file] [log] [blame]
// 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 <cctype>
namespace boost { namespace program_options {
using namespace std;
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(validation_error(validation_error::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(validation_error(validation_error::invalid_bool_value));
}
#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, bad_value)
{}
#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>";
}
}
}
invalid_option_value::
invalid_option_value(const std::wstring& bad_value)
: validation_error(validation_error::invalid_option_value, convert_value(bad_value))
{}
#endif
const std::string&
unknown_option::get_option_name() const throw()
{
return m_option_name;
}
const std::string&
ambiguous_option::get_option_name() const throw()
{
return m_option_name;
}
const std::vector<std::string>&
ambiguous_option::alternatives() const throw()
{
return m_alternatives;
}
void
multiple_values::set_option_name(const std::string& option_name)
{
m_option_name = option_name;
}
const std::string&
multiple_values::get_option_name() const throw()
{
return m_option_name;
}
void
multiple_occurrences::set_option_name(const std::string& option_name)
{
m_option_name = option_name;
}
const std::string&
multiple_occurrences::get_option_name() const throw()
{
return m_option_name;
}
validation_error::
validation_error(kind_t kind,
const std::string& option_value,
const std::string& option_name)
: error("")
, m_kind(kind)
, m_option_name(option_name)
, m_option_value(option_value)
, m_message(error_message(kind))
{
if (!option_value.empty())
{
m_message.append(std::string("'") + option_value + std::string("'"));
}
}
void
validation_error::set_option_name(const std::string& option_name)
{
m_option_name = option_name;
}
const std::string&
validation_error::get_option_name() const throw()
{
return m_option_name;
}
std::string
validation_error::error_message(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 multiple_values_not_allowed:
msg = "multiple values not allowed";
break;
case at_least_one_value_required:
msg = "at least one value required";
break;
case invalid_bool_value:
msg = "invalid bool value";
break;
case invalid_option_value:
msg = "invalid option value";
break;
case invalid_option:
msg = "invalid option";
break;
default:
msg = "unknown error";
}
return msg;
}
const char*
validation_error::what() const throw()
{
if (!m_option_name.empty())
{
m_message = "in option '" + m_option_name + "': "
+ error_message(m_kind);
}
return m_message.c_str();
}
const std::string&
required_option::get_option_name() const throw()
{
return m_option_name;
}
}}