config_file_types.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. // Copyright Thomas Kent 2016
  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 example shows a config file (in ini format) being parsed by the
  6. // program_options library. It includes a numebr of different value types.
  7. #include <boost/program_options.hpp>
  8. namespace po = boost::program_options;
  9. #include <assert.h>
  10. #include <iostream>
  11. #include <sstream>
  12. using namespace std;
  13. const double FLOAT_SEPERATION = 0.00000000001;
  14. bool check_float(double test, double expected)
  15. {
  16. double seperation = expected * (1 + FLOAT_SEPERATION) / expected;
  17. if ((test < expected + seperation) && (test > expected - seperation))
  18. {
  19. return true;
  20. }
  21. return false;
  22. }
  23. stringstream make_file()
  24. {
  25. stringstream ss;
  26. ss << "# This file checks parsing of various types of config values\n";
  27. //FAILS: ss << "; a windows style comment\n";
  28. ss << "global_string = global value\n";
  29. ss << "unregistered_entry = unregistered value\n";
  30. ss << "\n[strings]\n";
  31. ss << "word = word\n";
  32. ss << "phrase = this is a phrase\n";
  33. ss << "quoted = \"quotes are in result\"\n";
  34. ss << "\n[ints]\n";
  35. ss << "positive = 41\n";
  36. ss << "negative = -42\n";
  37. //FAILS: Lexical cast doesn't support hex, oct, or bin
  38. //ss << "hex = 0x43\n";
  39. //ss << "oct = 044\n";
  40. //ss << "bin = 0b101010\n";
  41. ss << "\n[floats]\n";
  42. ss << "positive = 51.1\n";
  43. ss << "negative = -52.1\n";
  44. ss << "double = 53.1234567890\n";
  45. ss << "int = 54\n";
  46. ss << "int_dot = 55.\n";
  47. ss << "dot = .56\n";
  48. ss << "exp_lower = 57.1e5\n";
  49. ss << "exp_upper = 58.1E5\n";
  50. ss << "exp_decimal = .591e5\n";
  51. ss << "exp_negative = 60.1e-5\n";
  52. ss << "exp_negative_val = -61.1e5\n";
  53. ss << "exp_negative_negative_val = -62.1e-5\n";
  54. ss << "\n[booleans]\n";
  55. ss << "number_true = 1\n";
  56. ss << "number_false = 0\n";
  57. ss << "yn_true = yes\n";
  58. ss << "yn_false = no\n";
  59. ss << "tf_true = true\n";
  60. ss << "tf_false = false\n";
  61. ss << "onoff_true = on\n";
  62. ss << "onoff_false = off\n";
  63. ss << "present_equal_true = \n";
  64. //FAILS: Must be an =
  65. //ss << "present_no_equal_true\n";
  66. ss.seekp(ios_base::beg);
  67. return ss;
  68. }
  69. po::options_description set_options()
  70. {
  71. po::options_description opts;
  72. opts.add_options()
  73. ("global_string", po::value<string>())
  74. ("strings.word", po::value<string>())
  75. ("strings.phrase", po::value<string>())
  76. ("strings.quoted", po::value<string>())
  77. ("ints.positive", po::value<int>())
  78. ("ints.negative", po::value<int>())
  79. ("ints.hex", po::value<int>())
  80. ("ints.oct", po::value<int>())
  81. ("ints.bin", po::value<int>())
  82. ("floats.positive", po::value<float>())
  83. ("floats.negative", po::value<float>())
  84. ("floats.double", po::value<double>())
  85. ("floats.int", po::value<float>())
  86. ("floats.int_dot", po::value<float>())
  87. ("floats.dot", po::value<float>())
  88. ("floats.exp_lower", po::value<float>())
  89. ("floats.exp_upper", po::value<float>())
  90. ("floats.exp_decimal", po::value<float>())
  91. ("floats.exp_negative", po::value<float>())
  92. ("floats.exp_negative_val", po::value<float>())
  93. ("floats.exp_negative_negative_val", po::value<float>())
  94. // Load booleans as value<bool>, so they will require a --option=value on the command line
  95. //("booleans.number_true", po::value<bool>())
  96. //("booleans.number_false", po::value<bool>())
  97. //("booleans.yn_true", po::value<bool>())
  98. //("booleans.yn_false", po::value<bool>())
  99. //("booleans.tf_true", po::value<bool>())
  100. //("booleans.tf_false", po::value<bool>())
  101. //("booleans.onoff_true", po::value<bool>())
  102. //("booleans.onoff_false", po::value<bool>())
  103. //("booleans.present_equal_true", po::value<bool>())
  104. //("booleans.present_no_equal_true", po::value<bool>())
  105. // Load booleans as bool_switch, so that a --option will set it true on the command line
  106. // The difference between these two types does not show up when parsing a file
  107. ("booleans.number_true", po::bool_switch())
  108. ("booleans.number_false", po::bool_switch())
  109. ("booleans.yn_true", po::bool_switch())
  110. ("booleans.yn_false", po::bool_switch())
  111. ("booleans.tf_true", po::bool_switch())
  112. ("booleans.tf_false", po::bool_switch())
  113. ("booleans.onoff_true", po::bool_switch())
  114. ("booleans.onoff_false", po::bool_switch())
  115. ("booleans.present_equal_true", po::bool_switch())
  116. ("booleans.present_no_equal_true", po::bool_switch())
  117. ;
  118. return opts;
  119. }
  120. vector<string> parse_file(stringstream &file, po::options_description &opts, po::variables_map &vm)
  121. {
  122. const bool ALLOW_UNREGISTERED = true;
  123. cout << file.str() << endl;
  124. po::parsed_options parsed = parse_config_file(file, opts, ALLOW_UNREGISTERED);
  125. store(parsed, vm);
  126. vector<string> unregistered = po::collect_unrecognized(parsed.options, po::exclude_positional);
  127. notify(vm);
  128. return unregistered;
  129. }
  130. void check_results(po::variables_map &vm, vector<string> unregistered)
  131. {
  132. // Check that we got the correct values back
  133. string expected_global_string = "global value";
  134. string expected_unreg_option = "unregistered_entry";
  135. string expected_unreg_value = "unregistered value";
  136. string expected_strings_word = "word";
  137. string expected_strings_phrase = "this is a phrase";
  138. string expected_strings_quoted = "\"quotes are in result\"";
  139. int expected_int_postitive = 41;
  140. int expected_int_negative = -42;
  141. int expected_int_hex = 0x43;
  142. int expected_int_oct = 044;
  143. int expected_int_bin = 0b101010;
  144. float expected_float_positive = 51.1f;
  145. float expected_float_negative = -52.1f;
  146. double expected_float_double = 53.1234567890;
  147. float expected_float_int = 54.0f;
  148. float expected_float_int_dot = 55.0f;
  149. float expected_float_dot = .56f;
  150. float expected_float_exp_lower = 57.1e5f;
  151. float expected_float_exp_upper = 58.1E5f;
  152. float expected_float_exp_decimal = .591e5f;
  153. float expected_float_exp_negative = 60.1e-5f;
  154. float expected_float_exp_negative_val = -61.1e5f;
  155. float expected_float_exp_negative_negative_val = -62.1e-5f;
  156. bool expected_number_true = true;
  157. bool expected_number_false = false;
  158. bool expected_yn_true = true;
  159. bool expected_yn_false = false;
  160. bool expected_tf_true = true;
  161. bool expected_tf_false = false;
  162. bool expected_onoff_true = true;
  163. bool expected_onoff_false = false;
  164. bool expected_present_equal_true = true;
  165. bool expected_present_no_equal_true = true;
  166. assert(vm["global_string"].as<string>() == expected_global_string);
  167. assert(unregistered[0] == expected_unreg_option);
  168. assert(unregistered[1] == expected_unreg_value);
  169. assert(vm["strings.word"].as<string>() == expected_strings_word);
  170. assert(vm["strings.phrase"].as<string>() == expected_strings_phrase);
  171. assert(vm["strings.quoted"].as<string>() == expected_strings_quoted);
  172. assert(vm["ints.positive"].as<int>() == expected_int_postitive);
  173. assert(vm["ints.negative"].as<int>() == expected_int_negative);
  174. //assert(vm["ints.hex"].as<int>() == expected_int_hex);
  175. //assert(vm["ints.oct"].as<int>() == expected_int_oct);
  176. //assert(vm["ints.bin"].as<int>() == expected_int_bin);
  177. assert(check_float(vm["floats.positive"].as<float>(), expected_float_positive));
  178. assert(check_float(vm["floats.negative"].as<float>(), expected_float_negative));
  179. assert(check_float(vm["floats.double"].as<double>(), expected_float_double));
  180. assert(check_float(vm["floats.int"].as<float>(), expected_float_int));
  181. assert(check_float(vm["floats.int_dot"].as<float>(), expected_float_int_dot));
  182. assert(check_float(vm["floats.dot"].as<float>(), expected_float_dot));
  183. assert(check_float(vm["floats.exp_lower"].as<float>(), expected_float_exp_lower));
  184. assert(check_float(vm["floats.exp_upper"].as<float>(), expected_float_exp_upper));
  185. assert(check_float(vm["floats.exp_decimal"].as<float>(), expected_float_exp_decimal));
  186. assert(check_float(vm["floats.exp_negative"].as<float>(), expected_float_exp_negative));
  187. assert(check_float(vm["floats.exp_negative_val"].as<float>(), expected_float_exp_negative_val));
  188. assert(check_float(vm["floats.exp_negative_negative_val"].as<float>(), expected_float_exp_negative_negative_val));
  189. assert(vm["booleans.number_true"].as<bool>() == expected_number_true);
  190. assert(vm["booleans.number_false"].as<bool>() == expected_number_false);
  191. assert(vm["booleans.yn_true"].as<bool>() == expected_yn_true);
  192. assert(vm["booleans.yn_false"].as<bool>() == expected_yn_false);
  193. assert(vm["booleans.tf_true"].as<bool>() == expected_tf_true);
  194. assert(vm["booleans.tf_false"].as<bool>() == expected_tf_false);
  195. assert(vm["booleans.onoff_true"].as<bool>() == expected_onoff_true);
  196. assert(vm["booleans.onoff_false"].as<bool>() == expected_onoff_false);
  197. assert(vm["booleans.present_equal_true"].as<bool>() == expected_present_equal_true);
  198. //assert(vm["booleans.present_no_equal_true"].as<bool>() == expected_present_no_equal_true);
  199. }
  200. int main(int ac, char* av[])
  201. {
  202. auto file = make_file();
  203. auto opts = set_options();
  204. po::variables_map vars;
  205. auto unregistered = parse_file(file, opts, vars);
  206. check_results(vars, unregistered);
  207. return 0;
  208. }