value_semantic.hpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. // Copyright Vladimir Prus 2004.
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE_1_0.txt
  4. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. // This file defines template functions that are declared in
  6. // ../value_semantic.hpp.
  7. #include <boost/throw_exception.hpp>
  8. #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
  9. # include <optional>
  10. #endif
  11. // forward declaration
  12. namespace boost { template<class T> class optional; }
  13. namespace boost { namespace program_options {
  14. extern BOOST_PROGRAM_OPTIONS_DECL std::string arg;
  15. template<class T, class charT>
  16. std::string
  17. typed_value<T, charT>::name() const
  18. {
  19. std::string const& var = (m_value_name.empty() ? arg : m_value_name);
  20. if (!m_implicit_value.empty() && !m_implicit_value_as_text.empty()) {
  21. std::string msg = "[=" + var + "(=" + m_implicit_value_as_text + ")]";
  22. if (!m_default_value.empty() && !m_default_value_as_text.empty())
  23. msg += " (=" + m_default_value_as_text + ")";
  24. return msg;
  25. }
  26. else if (!m_default_value.empty() && !m_default_value_as_text.empty()) {
  27. return var + " (=" + m_default_value_as_text + ")";
  28. } else {
  29. return var;
  30. }
  31. }
  32. template<class T, class charT>
  33. void
  34. typed_value<T, charT>::notify(const boost::any& value_store) const
  35. {
  36. const T* value = boost::any_cast<T>(&value_store);
  37. if (m_store_to) {
  38. *m_store_to = *value;
  39. }
  40. if (m_notifier) {
  41. m_notifier(*value);
  42. }
  43. }
  44. namespace validators {
  45. /* If v.size() > 1, throw validation_error.
  46. If v.size() == 1, return v.front()
  47. Otherwise, returns a reference to a statically allocated
  48. empty string if 'allow_empty' and throws validation_error
  49. otherwise. */
  50. template<class charT>
  51. const std::basic_string<charT>& get_single_string(
  52. const std::vector<std::basic_string<charT> >& v,
  53. bool allow_empty = false)
  54. {
  55. static std::basic_string<charT> empty;
  56. if (v.size() > 1)
  57. boost::throw_exception(validation_error(validation_error::multiple_values_not_allowed));
  58. else if (v.size() == 1)
  59. return v.front();
  60. else if (!allow_empty)
  61. boost::throw_exception(validation_error(validation_error::at_least_one_value_required));
  62. return empty;
  63. }
  64. /* Throws multiple_occurrences if 'value' is not empty. */
  65. BOOST_PROGRAM_OPTIONS_DECL void
  66. check_first_occurrence(const boost::any& value);
  67. }
  68. using namespace validators;
  69. /** Validates 's' and updates 'v'.
  70. @pre 'v' is either empty or in the state assigned by the previous
  71. invocation of 'validate'.
  72. The target type is specified via a parameter which has the type of
  73. pointer to the desired type. This is workaround for compilers without
  74. partial template ordering, just like the last 'long/int' parameter.
  75. */
  76. template<class T, class charT>
  77. void validate(boost::any& v,
  78. const std::vector< std::basic_string<charT> >& xs,
  79. T*, long)
  80. {
  81. validators::check_first_occurrence(v);
  82. std::basic_string<charT> s(validators::get_single_string(xs));
  83. try {
  84. v = any(lexical_cast<T>(s));
  85. }
  86. catch(const bad_lexical_cast&) {
  87. boost::throw_exception(invalid_option_value(s));
  88. }
  89. }
  90. BOOST_PROGRAM_OPTIONS_DECL void validate(boost::any& v,
  91. const std::vector<std::string>& xs,
  92. bool*,
  93. int);
  94. #if !defined(BOOST_NO_STD_WSTRING)
  95. BOOST_PROGRAM_OPTIONS_DECL void validate(boost::any& v,
  96. const std::vector<std::wstring>& xs,
  97. bool*,
  98. int);
  99. #endif
  100. // For some reason, this declaration, which is require by the standard,
  101. // cause msvc 7.1 to not generate code to specialization defined in
  102. // value_semantic.cpp
  103. #if ! ( BOOST_WORKAROUND(BOOST_MSVC, == 1310) )
  104. BOOST_PROGRAM_OPTIONS_DECL void validate(boost::any& v,
  105. const std::vector<std::string>& xs,
  106. std::string*,
  107. int);
  108. #if !defined(BOOST_NO_STD_WSTRING)
  109. BOOST_PROGRAM_OPTIONS_DECL void validate(boost::any& v,
  110. const std::vector<std::wstring>& xs,
  111. std::string*,
  112. int);
  113. #endif
  114. #endif
  115. /** Validates sequences. Allows multiple values per option occurrence
  116. and multiple occurrences. */
  117. template<class T, class charT>
  118. void validate(boost::any& v,
  119. const std::vector<std::basic_string<charT> >& s,
  120. std::vector<T>*,
  121. int)
  122. {
  123. if (v.empty()) {
  124. v = boost::any(std::vector<T>());
  125. }
  126. std::vector<T>* tv = boost::any_cast< std::vector<T> >(&v);
  127. assert(NULL != tv);
  128. for (unsigned i = 0; i < s.size(); ++i)
  129. {
  130. try {
  131. /* We call validate so that if user provided
  132. a validator for class T, we use it even
  133. when parsing vector<T>. */
  134. boost::any a;
  135. std::vector<std::basic_string<charT> > cv;
  136. cv.push_back(s[i]);
  137. validate(a, cv, static_cast<T*>(nullptr), 0);
  138. tv->push_back(boost::any_cast<T>(a));
  139. }
  140. catch(const bad_lexical_cast& /*e*/) {
  141. boost::throw_exception(invalid_option_value(s[i]));
  142. }
  143. }
  144. }
  145. /** Validates optional arguments. */
  146. template<class T, class charT>
  147. void validate(boost::any& v,
  148. const std::vector<std::basic_string<charT> >& s,
  149. boost::optional<T>*,
  150. int)
  151. {
  152. validators::check_first_occurrence(v);
  153. validators::get_single_string(s);
  154. boost::any a;
  155. validate(a, s, static_cast<T*>(nullptr), 0);
  156. v = boost::any(boost::optional<T>(boost::any_cast<T>(a)));
  157. }
  158. #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
  159. /** Validates std::optional arguments. */
  160. template<class T, class charT>
  161. void validate(boost::any& v,
  162. const std::vector<std::basic_string<charT> >& s,
  163. std::optional<T>*,
  164. int)
  165. {
  166. validators::check_first_occurrence(v);
  167. validators::get_single_string(s);
  168. boost::any a;
  169. validate(a, s, static_cast<T*>(nullptr), 0);
  170. v = boost::any(std::optional<T>(boost::any_cast<T>(a)));
  171. }
  172. #endif
  173. template<class T, class charT>
  174. void
  175. typed_value<T, charT>::
  176. xparse(boost::any& value_store,
  177. const std::vector<std::basic_string<charT> >& new_tokens) const
  178. {
  179. // If no tokens were given, and the option accepts an implicit
  180. // value, then assign the implicit value as the stored value;
  181. // otherwise, validate the user-provided token(s).
  182. if (new_tokens.empty() && !m_implicit_value.empty())
  183. value_store = m_implicit_value;
  184. else
  185. validate(value_store, new_tokens, static_cast<T*>(nullptr), 0);
  186. }
  187. template<class T>
  188. typed_value<T>*
  189. value()
  190. {
  191. // Explicit qualification is vc6 workaround.
  192. return boost::program_options::value<T>(0);
  193. }
  194. template<class T>
  195. typed_value<T>*
  196. value(T* v)
  197. {
  198. typed_value<T>* r = new typed_value<T>(v);
  199. return r;
  200. }
  201. template<class T>
  202. typed_value<T, wchar_t>*
  203. wvalue()
  204. {
  205. return wvalue<T>(0);
  206. }
  207. template<class T>
  208. typed_value<T, wchar_t>*
  209. wvalue(T* v)
  210. {
  211. typed_value<T, wchar_t>* r = new typed_value<T, wchar_t>(v);
  212. return r;
  213. }
  214. }}