0.9.8.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Properties.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007-2015 Hypertable, Inc.
3  *
4  * This file is part of Hypertable.
5  *
6  * Hypertable is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 3
9  * of the License, or any later version.
10  *
11  * Hypertable is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301, USA.
20  */
21 
27 #include <Common/Compat.h>
28 #include <Common/Properties.h>
29 #include <Common/Logger.h>
30 
31 #include <errno.h>
32 #include <fstream>
33 
34 using namespace Hypertable;
35 using namespace Property;
36 using namespace boost::program_options;
37 
38 // Custom validator defintions
39 namespace boost { namespace program_options {
40 
41 void validate(boost::any &v, const Strings &values, ::int64_t *, int) {
42  validators::check_first_occurrence(v);
43  const std::string &s = validators::get_single_string(values);
44  char *last;
45  int64_t result = strtoll(s.c_str(), &last, 0);
46 
47  if (s.c_str() == last)
48  throw invalid_option_value(s);
49 
50  switch (*last) {
51  case 'k':
52  case 'K': result *= 1000LL; break;
53  case 'm':
54  case 'M': result *= 1000000LL; break;
55  case 'g':
56  case 'G': result *= 1000000000LL; break;
57  case '\0': break;
58  default: throw invalid_option_value(s + ": unknown suffix");
59  }
60  v = any(result);
61 }
62 
63 void validate(boost::any &v, const Strings &values, double *, int) {
64  validators::check_first_occurrence(v);
65  const std::string &s = validators::get_single_string(values);
66  char *last;
67  double result = strtod(s.c_str(), &last);
68 
69  if (s.c_str() == last)
70  throw invalid_option_value(s);
71 
72  switch (*last) {
73  case 'k':
74  case 'K': result *= 1000LL; break;
75  case 'm':
76  case 'M': result *= 1000000LL; break;
77  case 'g':
78  case 'G': result *= 1000000000LL; break;
79  case '\0': break;
80  default: throw invalid_option_value(s + ": unknown suffix");
81  }
82  v = any(result);
83 }
84 
85 void validate(boost::any &v, const Strings &values, ::int32_t *, int) {
86  validate(v, values, (int64_t *)0, 0);
87  int64_t res = any_cast<int64_t>(v);
88 
89  if (res > INT32_MAX || res < INT32_MIN) {
90  const std::string &s = validators::get_single_string(values);
91  throw invalid_option_value(s +": number out of range of 32-bit integer");
92  }
93  v = any((int32_t)res);
94 }
95 
96 void validate(boost::any &v, const Strings &values, ::uint16_t *, int) {
97  validate(v, values, (int64_t *)0, 0);
98  int64_t res = any_cast<int64_t>(v);
99 
100  if (res > UINT16_MAX) {
101  const std::string &s = validators::get_single_string(values);
102  throw invalid_option_value(s + ": number out of range of 16-bit integer");
103  }
104  v = any((uint16_t)res);
105 }
106 
107 }} // namespace boost::program_options
108 
109 
110 namespace {
111 
112 void
113 parse(command_line_parser &parser, const PropertiesDesc &desc,
114  variables_map &result, const PropertiesDesc *hidden,
115  const PositionalDesc *p, bool allow_unregistered) {
116  try {
117  PropertiesDesc full(desc);
118 
119  if (hidden)
120  full.add(*hidden);
121 
122  parser.options(full);
123 
124  if (p)
125  parser.positional(*p);
126 
127 #if BOOST_VERSION >= 103500
128  if (allow_unregistered)
129  store(parser.allow_unregistered().run(), result);
130  else
131  store(parser.run(), result);
132 #else
133  store(parser.run(), result);
134 #endif
135  }
136  catch (std::exception &e) {
138  }
139 }
140 
141 } // local namespace
142 
143 void
144 Properties::load(const String &fname, const PropertiesDesc &desc,
145  bool allow_unregistered) {
146  m_need_alias_sync = true;
147 
148  try {
149  std::ifstream in(fname.c_str());
150 
151  if (!in)
152  HT_THROWF(Error::CONFIG_BAD_CFG_FILE, "%s", strerror(errno));
153 
154 #if BOOST_VERSION >= 103500
155  parsed_options parsed_opts = parse_config_file(in, desc, allow_unregistered);
156  store(parsed_opts, m_map);
157  for (size_t i = 0; i < parsed_opts.options.size(); i++) {
158  if (parsed_opts.options[i].unregistered && parsed_opts.options[i].string_key != "")
159  m_map.insert(Map::value_type(parsed_opts.options[i].string_key,
160  Value(parsed_opts.options[i].value[0], false)));
161  }
162 #else
163  store(parse_config_file(in, desc), m_map);
164 #endif
165  }
166  catch (std::exception &e) {
167  HT_THROWF(Error::CONFIG_BAD_CFG_FILE, "%s: %s", fname.c_str(), e.what());
168  }
169 }
170 
171 void
172 Properties::parse_args(int argc, char *argv[], const PropertiesDesc &desc,
173  const PropertiesDesc *hidden, const PositionalDesc *p,
174  bool allow_unregistered) {
175  // command_line_parser can't seem to handle argc = 0
176  const char *dummy = "_";
177 
178  if (argc < 1) {
179  argc = 1;
180  argv = (char **)&dummy;
181  }
182  HT_TRY("parsing arguments",
183  command_line_parser parser(argc, argv);
184  parse(parser, desc, m_map, hidden, p, allow_unregistered));
185 }
186 
187 void
188 Properties::parse_args(const std::vector<String> &args,
189  const PropertiesDesc &desc, const PropertiesDesc *hidden,
190  const PositionalDesc *p, bool allow_unregistered) {
191  HT_TRY("parsing arguments",
192  command_line_parser parser(args);
193  parse(parser, desc, m_map, hidden, p, allow_unregistered));
194 }
195 
196 // As of boost 1.38, notify will segfault if anything is added to
197 // the variables_map by means other than store, which is too limiting.
198 // So don't call notify after add/setting properties manually or die
200  boost::program_options::notify(m_map);
201 }
202 
203 void Properties::alias(const String &primary, const String &secondary,
204  bool overwrite) {
205  if (overwrite)
206  m_alias_map[primary] = secondary;
207  else
208  m_alias_map.insert(std::make_pair(primary, secondary));
209 
210  m_need_alias_sync = true;
211 }
212 
214  if (!m_need_alias_sync)
215  return;
216 
217  for (const auto &v : m_alias_map) {
218  Map::iterator it1 = m_map.find(v.first);
219  Map::iterator it2 = m_map.find(v.second);
220 
221  if (it1 != m_map.end()) {
222  if (it2 == m_map.end()) // secondary missing
223  m_map.insert(std::make_pair(v.second, (*it1).second));
224  else if (!(*it1).second.defaulted())
225  (*it2).second = (*it1).second; // non-default primary trumps
226  else if (!(*it2).second.defaulted())
227  (*it1).second = (*it2).second; // otherwise use non-default secondary
228  }
229  else if (it2 != m_map.end()) { // primary missing
230  m_map.insert(std::make_pair(v.first, (*it2).second));
231  }
232  }
233  m_need_alias_sync = false;
234 }
235 
236 // need to be updated when adding new option type
237 String Properties::to_str(const boost::any &v) {
238  if (v.type() == typeid(String))
239  return boost::any_cast<String>(v);
240 
241  if (v.type() == typeid(uint16_t))
242  return format("%u", (unsigned)boost::any_cast<uint16_t>(v));
243 
244  if (v.type() == typeid(int32_t))
245  return format("%d", boost::any_cast<int32_t>(v));
246 
247  if (v.type() == typeid(int64_t))
248  return format("%llu", (Llu)boost::any_cast<int64_t>(v));
249 
250  if (v.type() == typeid(double))
251  return format("%g", boost::any_cast<double>(v));
252 
253  if (v.type() == typeid(bool)) {
254  bool bval = boost::any_cast<bool>(v);
255  return bval ? "true" : "false";
256  }
257  if (v.type() == typeid(Strings)) {
258  const Strings *strs = boost::any_cast<Strings>(&v);
259  return format_list(*strs);
260  }
261  if (v.type() == typeid(Int64s)) {
262  const Int64s *i64s = boost::any_cast<Int64s>(&v);
263  return format_list(*i64s);
264  }
265  if (v.type() == typeid(Doubles)) {
266  const Doubles *f64s = boost::any_cast<Doubles>(&v);
267  return format_list(*f64s);
268  }
269 
270  return "invalid option type";
271 }
272 
273 void
274 Properties::print(std::ostream &out, bool include_default) {
275  for (const auto &kv : m_map) {
276  bool isdefault = kv.second.defaulted();
277 
278  if (include_default || !isdefault) {
279  out << kv.first << '=' << to_str(kv.second.value());
280 
281  if (isdefault)
282  out << " (default)";
283 
284  out << std::endl;
285  }
286  }
287 }
void alias(const String &primary, const String &secondary, bool overwrite=false)
Setup an alias for a property.
Definition: Properties.cc:203
std::vector< double > Doubles
Definition: Properties.h:150
void parse_args(int argc, char *argv[], const PropertiesDesc &desc, const PropertiesDesc *hidden=0, const PositionalDesc *p=0, bool allow_unregistered=false)
Parses command line arguments.
Definition: Properties.cc:172
static bool allow_unregistered
Definition: Config.cc:50
Boost library.
Definition: Properties.cc:39
std::string String
A String is simply a typedef to std::string.
Definition: String.h:44
Po::positional_options_description PositionalDesc
Definition: Properties.h:201
String format(const char *fmt,...)
Returns a String using printf like format facilities Vanilla snprintf is about 1.5x faster than this...
Definition: String.cc:37
Po::typed_value< Int64s > * i64s(Int64s *v=0)
Definition: Properties.h:186
String format_list(const SequenceT &seq, const char *sep=", ")
Return a string presentation of a sequence.
Definition: String.h:99
Po::variable_value Value
Definition: Properties.h:209
long long unsigned int Llu
Shortcut for printf formats.
Definition: String.h:50
Po::typed_value< Doubles > * f64s(Doubles *v=0)
Definition: Properties.h:194
void validate(boost::any &v, const Strings &values,::uint16_t *, int)
Definition: Properties.cc:96
Program options handling.
std::vector< String > Strings
Definition: Properties.h:148
std::vector< int64_t > Int64s
Definition: Properties.h:149
void notify()
Calls user-defined notifier functions (if any) with final values.
Definition: Properties.cc:199
void print(std::ostream &out, bool include_default=false)
Prints keys and values of the configuration map.
Definition: Properties.cc:274
void sync_aliases()
Sync alias values.
Definition: Properties.cc:213
Logging routines and macros.
Compatibility Macros for C/C++.
Po::options_description PropertiesDesc
Definition: Properties.h:200
std::vector< std::string > Strings
Definition: Properties.h:46
Po::typed_value< Strings > * strs(Strings *v=0)
Definition: Properties.h:170
static String to_str(const boost::any &a)
Helper to print boost::any used by property values.
Definition: Properties.cc:237
Hypertable definitions
#define HT_THROWF(_code_, _fmt_,...)
Definition: Error.h:490
Program options.
Definition: Properties.cc:39
void load(const String &filename, const PropertiesDesc &desc, bool allow_unregistered=false)
Loads a configuration file with properties.
Definition: Properties.cc:144
#define HT_TRY(_s_, _code_)
Definition: Error.h:517
#define HT_THROW(_code_, _msg_)
Definition: Error.h:478