text: // 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;
      }
  
  }}
  
  