Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of git+ssh://scm.gforge.inria.fr//gitroot/simgrid/simgrid
[simgrid.git] / src / xbt / config.cpp
1 /* Copyright (c) 2004-2017. The SimGrid Team. All rights reserved.     */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #include <cstdio>
7
8 #include <algorithm>
9 #include <cerrno>
10 #include <cstring>
11 #include <climits>
12
13 #include <functional>
14 #include <map>
15 #include <stdexcept>
16 #include <string>
17 #include <type_traits>
18 #include <typeinfo>
19 #include <vector>
20
21 #include <xbt/ex.hpp>
22 #include <xbt/config.h>
23 #include <xbt/config.hpp>
24 #include "xbt/misc.h"
25 #include "xbt/sysdep.h"
26 #include "xbt/log.h"
27 #include "xbt/dynar.h"
28
29 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_cfg, xbt, "configuration support");
30
31 XBT_EXPORT_NO_IMPORT(xbt_cfg_t) simgrid_config = nullptr;
32 extern "C" {
33   XBT_PUBLIC(void) sg_config_finalize();
34 }
35
36 namespace simgrid {
37 namespace config {
38
39 missing_key_error::~missing_key_error() = default;
40
41 class Config;
42
43 namespace {
44
45 const char* true_values[] = {
46   "yes", "on", "true", "1"
47 };
48 const char* false_values[] = {
49   "no", "off", "false", "0"
50 };
51
52 static bool parseBool(const char* value)
53 {
54   for (const char* true_value : true_values)
55     if (std::strcmp(true_value, value) == 0)
56       return true;
57   for (const char* false_value : false_values)
58     if (std::strcmp(false_value, value) == 0)
59       return false;
60   throw std::range_error("not a boolean");
61 }
62
63 static double parseDouble(const char* value)
64 {
65   char* end;
66   errno = 0;
67   double res = std::strtod(value, &end);
68   if (errno == ERANGE)
69     throw std::range_error("out of range");
70   else if (errno)
71     xbt_die("Unexpected errno");
72   if (end == value || *end != '\0')
73     throw std::range_error("invalid double");
74   else
75     return res;
76 }
77
78 static long int parseLong(const char* value)
79 {
80   char* end;
81   errno = 0;
82   long int res = std::strtol(value, &end, 0);
83   if (errno) {
84     if (res == LONG_MIN && errno == ERANGE)
85       throw std::range_error("underflow");
86     else if (res == LONG_MAX && errno == ERANGE)
87       throw std::range_error("overflow");
88     xbt_die("Unexpected errno");
89   }
90   if (end == value || *end != '\0')
91     throw std::range_error("invalid integer");
92   else
93     return res;
94 }
95
96 // ***** ConfigType *****
97
98 /// A trait which define possible options types:
99 template<class T> struct ConfigType;
100
101 template<> struct ConfigType<int> {
102   static constexpr const char* type_name = "int";
103   static inline double parse(const char* value)
104   {
105     return parseLong(value);
106   }
107 };
108 template<> struct ConfigType<double> {
109   static constexpr const char* type_name = "double";
110   static inline double parse(const char* value)
111   {
112     return parseDouble(value);
113   }
114 };
115 template<> struct ConfigType<std::string> {
116   static constexpr const char* type_name = "string";
117   static inline std::string parse(const char* value)
118   {
119     return std::string(value);
120   }
121 };
122 template<> struct ConfigType<bool> {
123   static constexpr const char* type_name = "boolean";
124   static inline bool parse(const char* value)
125   {
126     return parseBool(value);
127   }
128 };
129
130 // **** Forward declarations ****
131
132 class ConfigurationElement ;
133 template<class T> class TypedConfigurationElement;
134
135 // **** ConfigurationElement ****
136
137 class ConfigurationElement {
138 protected:
139   std::string key;
140   std::string desc;
141   bool isdefault = true;
142
143 public:
144
145   /* Callback */
146   xbt_cfg_cb_t old_callback = nullptr;
147
148   ConfigurationElement(const char* key, const char* desc)
149     : key(key ? key : ""), desc(desc ? desc : "") {}
150   ConfigurationElement(const char* key, const char* desc, xbt_cfg_cb_t cb)
151     : key(key ? key : ""), desc(desc ? desc : ""), old_callback(cb) {}
152
153   virtual ~ConfigurationElement()=default;
154
155   virtual std::string getStringValue() = 0;
156   virtual void setStringValue(const char* value) = 0;
157   virtual const char* getTypeName() = 0;
158
159   template<class T>
160   T const& getValue() const
161   {
162     return dynamic_cast<const TypedConfigurationElement<T>&>(*this).getValue();
163   }
164   template<class T>
165   void setValue(T value)
166   {
167     dynamic_cast<TypedConfigurationElement<T>&>(*this).setValue(std::move(value));
168   }
169   template<class T>
170   void setDefaultValue(T value)
171   {
172     dynamic_cast<TypedConfigurationElement<T>&>(*this).setDefaultValue(std::move(value));
173   }
174   bool isDefault() const { return isdefault; }
175
176   std::string const& getDescription() const { return desc; }
177   std::string const& getKey() const { return key; }
178 };
179
180 // **** TypedConfigurationElement<T> ****
181
182 // TODO, could we use boost::any with some Type* reference?
183 template<class T>
184 class TypedConfigurationElement : public ConfigurationElement {
185 private:
186   T content;
187   std::function<void(T&)> callback;
188
189 public:
190   TypedConfigurationElement(const char* key, const char* desc, T value = T())
191     : ConfigurationElement(key, desc), content(std::move(value))
192   {}
193   TypedConfigurationElement(const char* key, const char* desc, T value,
194       xbt_cfg_cb_t cb)
195     : ConfigurationElement(key, desc, cb), content(std::move(value))
196   {}
197   TypedConfigurationElement(const char* key, const char* desc, T value,
198       std::function<void(T&)> callback)
199     : ConfigurationElement(key, desc), content(std::move(value)),
200       callback(std::move(callback))
201   {}
202   ~TypedConfigurationElement()=default;
203
204   std::string getStringValue() override;
205   const char* getTypeName() override;
206   void setStringValue(const char* value) override;
207
208   void update()
209   {
210     if (old_callback)
211       this->old_callback(key.c_str());
212     if (this->callback)
213       this->callback(this->content);
214   }
215
216   T const& getValue() const { return content; }
217
218   void setValue(T value)
219   {
220     this->content = std::move(value);
221     this->update();
222   }
223
224   void setDefaultValue(T value)
225   {
226     if (this->isdefault) {
227       this->content = std::move(value);
228       this->update();
229     } else {
230       XBT_DEBUG("Do not override configuration variable '%s' with value '%s'"
231         " because it was already set.", key.c_str(), to_string(value).c_str());
232     }
233   }
234 };
235
236 template<class T>
237 std::string TypedConfigurationElement<T>::getStringValue() // override
238 {
239   return to_string(content);
240 }
241
242 template<class T>
243 void TypedConfigurationElement<T>::setStringValue(const char* value) // override
244 {
245   this->content = ConfigType<T>::parse(value);
246   this->isdefault = false;
247   this->update();
248 }
249
250 template<class T>
251 const char* TypedConfigurationElement<T>::getTypeName() // override
252 {
253   return ConfigType<T>::type_name;
254 }
255
256 } // end of anonymous namespace
257
258 // **** Config ****
259
260 class Config {
261 private:
262   // name -> ConfigElement:
263   std::map<std::string, simgrid::config::ConfigurationElement*> options;
264   // alias -> xbt_dict_elm_t from options:
265   std::map<std::string, simgrid::config::ConfigurationElement*> aliases;
266   bool warn_for_aliases = true;
267
268 public:
269   Config() = default;
270   ~Config();
271
272   // No copy:
273   Config(Config const&) = delete;
274   Config& operator=(Config const&) = delete;
275
276   ConfigurationElement& operator[](const char* name);
277   template<class T>
278   TypedConfigurationElement<T>& getTyped(const char* name);
279   void alias(const char* realname, const char* aliasname);
280
281   template<class T, class... A>
282   simgrid::config::TypedConfigurationElement<T>*
283     registerOption(const char* name, A&&... a)
284   {
285     xbt_assert(options.find(name) == options.end(), "Refusing to register the config element '%s' twice.", name);
286     TypedConfigurationElement<T>* variable = new TypedConfigurationElement<T>(name, std::forward<A>(a)...);
287     XBT_DEBUG("Register cfg elm %s (%s) of type %s @%p in set %p)", name, variable->getDescription().c_str(),
288               variable->getTypeName(), variable, this);
289     options.insert({name, variable});
290     variable->update();
291     return variable;
292   }
293
294   // Debug:
295   void dump(const char *name, const char *indent);
296   void showAliases();
297   void help();
298
299 protected:
300   ConfigurationElement* getDictElement(const char* name);
301 };
302
303 Config::~Config()
304 {
305   XBT_DEBUG("Frees cfg set %p", this);
306   for (auto elm : options)
307     delete elm.second;
308 }
309
310 inline ConfigurationElement* Config::getDictElement(const char* name)
311 {
312   try {
313     return options.at(name);
314   } catch (std::out_of_range& unfound) {
315     try {
316       ConfigurationElement* res = aliases.at(name);
317       if (warn_for_aliases)
318         XBT_INFO("Option %s has been renamed to %s. Consider switching.", name, res->getKey().c_str());
319       return res;
320     } catch (std::out_of_range& missing_key) {
321       throw simgrid::config::missing_key_error(std::string("Bad config key: ") + name);
322     }
323   }
324 }
325
326 inline ConfigurationElement& Config::operator[](const char* name)
327 {
328   return *(getDictElement(name));
329 }
330
331 void Config::alias(const char* realname, const char* aliasname)
332 {
333   xbt_assert(aliases.find(aliasname) == aliases.end(), "Alias '%s' already.", aliasname);
334   ConfigurationElement* element = this->getDictElement(realname);
335   xbt_assert(element, "Cannot define an alias to the non-existing option '%s'.", realname);
336   this->aliases.insert({aliasname, element});
337 }
338
339 /** @brief Dump a config set for debuging purpose
340  *
341  * @param name The name to give to this config set
342  * @param indent what to write at the beginning of each line (right number of spaces)
343  */
344 void Config::dump(const char *name, const char *indent)
345 {
346   if (name)
347     printf("%s>> Dumping of the config set '%s':\n", indent, name);
348
349   for (auto elm : options)
350     printf("%s  %s: ()%s) %s", indent, elm.first.c_str(), elm.second->getTypeName(),
351            elm.second->getStringValue().c_str());
352
353   if (name)
354     printf("%s<< End of the config set '%s'\n", indent, name);
355   fflush(stdout);
356 }
357
358 /** @brief Displays the declared aliases and their description */
359 void Config::showAliases()
360 {
361   bool old_warn_for_aliases = false;
362   std::swap(warn_for_aliases, old_warn_for_aliases);
363   for (auto elm : aliases)
364     printf("   %s: %s\n", elm.first.c_str(), (*this)[elm.first.c_str()].getDescription().c_str());
365   std::swap(warn_for_aliases, old_warn_for_aliases);
366 }
367
368 /** @brief Displays the declared options and their description */
369 void Config::help()
370 {
371   for (auto elm : options) {
372     simgrid::config::ConfigurationElement* variable = this->options.at(elm.first);
373     printf("   %s: %s\n", elm.first.c_str(), variable->getDescription().c_str());
374     printf("       Type: %s; ", variable->getTypeName());
375     printf("Current value: %s\n", variable->getStringValue().c_str());
376   }
377 }
378
379 // ***** getConfig *****
380
381 template<class T>
382 XBT_PUBLIC(T const&) getConfig(const char* name)
383 {
384   return (*simgrid_config)[name].getValue<T>();
385 }
386
387 template XBT_PUBLIC(int const&) getConfig<int>(const char* name);
388 template XBT_PUBLIC(double const&) getConfig<double>(const char* name);
389 template XBT_PUBLIC(bool const&) getConfig<bool>(const char* name);
390 template XBT_PUBLIC(std::string const&) getConfig<std::string>(const char* name);
391
392 // ***** alias *****
393
394 void alias(const char* realname, const char* aliasname)
395 {
396   simgrid_config->alias(realname, aliasname);
397 }
398
399 // ***** declareFlag *****
400
401 template<class T>
402 XBT_PUBLIC(void) declareFlag(const char* name, const char* description,
403   T value, std::function<void(const T&)> callback)
404 {
405   if (simgrid_config == nullptr) {
406     simgrid_config = xbt_cfg_new();
407     atexit(sg_config_finalize);
408   }
409   simgrid_config->registerOption<T>(
410     name, description, std::move(value), std::move(callback));
411 }
412
413 template XBT_PUBLIC(void) declareFlag(const char* name,
414   const char* description, int value, std::function<void(int const &)> callback);
415 template XBT_PUBLIC(void) declareFlag(const char* name,
416   const char* description, double value, std::function<void(double const &)> callback);
417 template XBT_PUBLIC(void) declareFlag(const char* name,
418   const char* description, bool value, std::function<void(bool const &)> callback);
419 template XBT_PUBLIC(void) declareFlag(const char* name,
420   const char* description, std::string value, std::function<void(std::string const &)> callback);
421
422 }
423 }
424
425 // ***** C bindings *****
426
427 xbt_cfg_t xbt_cfg_new()        { return new simgrid::config::Config(); }
428 void xbt_cfg_free(xbt_cfg_t * cfg) { delete *cfg; }
429
430 void xbt_cfg_dump(const char *name, const char *indent, xbt_cfg_t cfg)
431 {
432   cfg->dump(name, indent);
433 }
434
435 /*----[ Registering stuff ]-----------------------------------------------*/
436
437 void xbt_cfg_register_double(const char *name, double default_value,
438   xbt_cfg_cb_t cb_set, const char *desc)
439 {
440   if (simgrid_config == nullptr)
441     simgrid_config = xbt_cfg_new();
442   simgrid_config->registerOption<double>(name, desc, default_value, cb_set);
443 }
444
445 void xbt_cfg_register_int(const char *name, int default_value,xbt_cfg_cb_t cb_set, const char *desc)
446 {
447   if (simgrid_config == nullptr) {
448     simgrid_config = xbt_cfg_new();
449     atexit(&sg_config_finalize);
450   }
451   simgrid_config->registerOption<int>(name, desc, default_value, cb_set);
452 }
453
454 void xbt_cfg_register_string(const char *name, const char *default_value, xbt_cfg_cb_t cb_set, const char *desc)
455 {
456   if (simgrid_config == nullptr) {
457     simgrid_config = xbt_cfg_new();
458     atexit(sg_config_finalize);
459   }
460   simgrid_config->registerOption<std::string>(name, desc,
461     default_value ? default_value : "", cb_set);
462 }
463
464 void xbt_cfg_register_boolean(const char *name, const char*default_value,xbt_cfg_cb_t cb_set, const char *desc)
465 {
466   if (simgrid_config == nullptr) {
467     simgrid_config = xbt_cfg_new();
468     atexit(sg_config_finalize);
469   }
470   simgrid_config->registerOption<bool>(name, desc, simgrid::config::parseBool(default_value), cb_set);
471 }
472
473 void xbt_cfg_register_alias(const char *realname, const char *aliasname)
474 {
475   if (simgrid_config == nullptr) {
476     simgrid_config = xbt_cfg_new();
477     atexit(sg_config_finalize);
478   }
479   simgrid_config->alias(realname, aliasname);
480 }
481
482 void xbt_cfg_aliases() { simgrid_config->showAliases(); }
483 void xbt_cfg_help()    { simgrid_config->help(); }
484
485 /*----[ Setting ]---------------------------------------------------------*/
486
487 /** @brief Add values parsed from a string into a config set
488  *
489  * @param options a string containing the content to add to the config set. This is a '\\t',' ' or '\\n' or ','
490  * separated list of variables. Each individual variable is like "[name]:[value]" where [name] is the name of an
491  * already registered variable, and [value] conforms to the data type under which this variable was registered.
492  *
493  * @todo This is a crude manual parser, it should be a proper lexer.
494  */
495 void xbt_cfg_set_parse(const char *options)
496 {
497   if (not options || not strlen(options)) { /* nothing to do */
498     return;
499   }
500   char *optionlist_cpy = xbt_strdup(options);
501
502   XBT_DEBUG("List to parse and set:'%s'", options);
503   char *option = optionlist_cpy;
504   while (1) {                   /* breaks in the code */
505     if (not option)
506       break;
507     char *name = option;
508     int len = strlen(name);
509     XBT_DEBUG("Still to parse and set: '%s'. len=%d; option-name=%ld", name, len, (long) (option - name));
510
511     /* Pass the value */
512     while (option - name <= (len - 1) && *option != ' ' && *option != '\n' && *option != '\t' && *option != ',') {
513       XBT_DEBUG("Take %c.", *option);
514       option++;
515     }
516     if (option - name == len) {
517       XBT_DEBUG("Boundary=EOL");
518       option = nullptr;            /* don't do next iteration */
519     } else {
520       XBT_DEBUG("Boundary on '%c'. len=%d;option-name=%ld", *option, len, (long) (option - name));
521       /* Pass the following blank chars */
522       *(option++) = '\0';
523       while (option - name < (len - 1) && (*option == ' ' || *option == '\n' || *option == '\t')) {
524         /*      fprintf(stderr,"Ignore a blank char.\n"); */
525         option++;
526       }
527       if (option - name == len - 1)
528         option = nullptr;          /* don't do next iteration */
529     }
530     XBT_DEBUG("parse now:'%s'; parse later:'%s'", name, option);
531
532     if (name[0] == ' ' || name[0] == '\n' || name[0] == '\t')
533       continue;
534     if (not strlen(name))
535       break;
536
537     char *val = strchr(name, ':');
538     xbt_assert(val, "Option '%s' badly formatted. Should be of the form 'name:value'", name);
539     /* don't free(optionlist_cpy) if the assert fails, 'name' points inside it */
540     *(val++) = '\0';
541
542     if (strncmp(name, "path", strlen("path")))
543       XBT_INFO("Configuration change: Set '%s' to '%s'", name, val);
544
545     try {
546       (*simgrid_config)[name].setStringValue(val);
547     }
548     catch (simgrid::config::missing_key_error& e) {
549       goto on_missing_key;
550     }
551     catch (...) {
552       goto on_exception;
553     }
554   }
555
556   free(optionlist_cpy);
557   return;
558
559   /* Do not THROWF from a C++ exception catching context, or some cleanups will be missing */
560 on_missing_key:
561   free(optionlist_cpy);
562   THROWF(not_found_error, 0, "Could not set variables %s", options);
563   return;
564 on_exception:
565   free(optionlist_cpy);
566   THROWF(unknown_error, 0, "Could not set variables %s", options);
567 }
568
569 // Horrible mess to translate C++ exceptions to C exceptions:
570 // Exit from the catch blog (and do the correct exceptio cleaning)
571 // before attempting to THROWF.
572 #define TRANSLATE_EXCEPTIONS(...) \
573   catch(simgrid::config::missing_key_error& e) { THROWF(not_found_error, 0, __VA_ARGS__); abort(); } \
574   catch(...) { THROWF(not_found_error, 0, __VA_ARGS__); abort(); }
575
576 /** @brief Set the value of a variable, using the string representation of that value
577  *
578  * @param key name of the variable to modify
579  * @param value string representation of the value to set
580  */
581
582 void xbt_cfg_set_as_string(const char *key, const char *value)
583 {
584   try {
585     (*simgrid_config)[key].setStringValue(value);
586     return;
587   }
588   TRANSLATE_EXCEPTIONS("Could not set variable %s as string %s", key, value);
589 }
590
591 /** @brief Set an integer value to \a name within \a cfg if it wasn't changed yet
592  *
593  * This is useful to change the default value of a variable while allowing
594  * users to override it with command line arguments
595  */
596 void xbt_cfg_setdefault_int(const char *key, int value)
597 {
598   try {
599     (*simgrid_config)[key].setDefaultValue<int>(value);
600     return;
601   }
602   TRANSLATE_EXCEPTIONS("Could not set variable %s to default integer %i",
603     key, value);
604 }
605
606 /** @brief Set an integer value to \a name within \a cfg if it wasn't changed yet
607  *
608  * This is useful to change the default value of a variable while allowing
609  * users to override it with command line arguments
610  */
611 void xbt_cfg_setdefault_double(const char *key, double value)
612 {
613   try {
614     (*simgrid_config)[key].setDefaultValue<double>(value);
615     return;
616   }
617   TRANSLATE_EXCEPTIONS("Could not set variable %s to default double %f",
618     key, value);
619 }
620
621 /** @brief Set a string value to \a name within \a cfg if it wasn't changed yet
622  *
623  * This is useful to change the default value of a variable while allowing
624  * users to override it with command line arguments
625  */
626 void xbt_cfg_setdefault_string(const char *key, const char *value)
627 {
628   try {
629     (*simgrid_config)[key].setDefaultValue<std::string>(value ? value : "");
630     return;
631   }
632   TRANSLATE_EXCEPTIONS("Could not set variable %s to default string %s",
633     key, value);
634 }
635
636 /** @brief Set an boolean value to \a name within \a cfg if it wasn't changed yet
637  *
638  * This is useful to change the default value of a variable while allowing
639  * users to override it with command line arguments
640  */
641 void xbt_cfg_setdefault_boolean(const char *key, const char *value)
642 {
643   try {
644     (*simgrid_config)[key].setDefaultValue<bool>(simgrid::config::parseBool(value));
645     return;
646   }
647   TRANSLATE_EXCEPTIONS("Could not set variable %s to default boolean %s",
648     key, value);
649 }
650
651 /** @brief Set an integer value to \a name within \a cfg
652  *
653  * @param key the name of the variable
654  * @param value the value of the variable
655  */
656 void xbt_cfg_set_int(const char *key, int value)
657 {
658   try {
659     (*simgrid_config)[key].setValue<int>(value);
660     return;
661   }
662   TRANSLATE_EXCEPTIONS("Could not set variable %s to integer %i",
663     key, value);
664 }
665
666 /** @brief Set or add a double value to \a name within \a cfg
667  *
668  * @param key the name of the variable
669  * @param value the double to set
670  */
671 void xbt_cfg_set_double(const char *key, double value)
672 {
673   try {
674     (*simgrid_config)[key].setValue<double>(value);
675     return;
676   }
677   TRANSLATE_EXCEPTIONS("Could not set variable %s to double %f",
678     key, value);
679 }
680
681 /** @brief Set or add a string value to \a name within \a cfg
682  *
683  * @param key the name of the variable
684  * @param value the value to be added
685  *
686  */
687 void xbt_cfg_set_string(const char *key, const char *value)
688 {
689   try {
690     (*simgrid_config)[key].setValue<std::string>(value ? value : "");
691     return;
692   }
693   TRANSLATE_EXCEPTIONS("Could not set variable %s to string %s",
694     key, value);
695 }
696
697 /** @brief Set or add a boolean value to \a name within \a cfg
698  *
699  * @param key the name of the variable
700  * @param value the value of the variable
701  */
702 void xbt_cfg_set_boolean(const char *key, const char *value)
703 {
704   try {
705     (*simgrid_config)[key].setValue<bool>(simgrid::config::parseBool(value));
706     return;
707   }
708   TRANSLATE_EXCEPTIONS("Could not set variable %s to boolean %s",
709     key, value);
710 }
711
712
713 /* Say if the value is the default value */
714 int xbt_cfg_is_default_value(const char *key)
715 {
716   try {
717     return (*simgrid_config)[key].isDefault() ? 1 : 0;
718   }
719   TRANSLATE_EXCEPTIONS("Could not get variable %s", key);
720 }
721
722 /*----[ Getting ]---------------------------------------------------------*/
723 /** @brief Retrieve an integer value of a variable (get a warning if not uniq)
724  *
725  * @param key the name of the variable
726  *
727  * Returns the first value from the config set under the given name.
728  */
729 int xbt_cfg_get_int(const char *key)
730 {
731   try {
732     return (*simgrid_config)[key].getValue<int>();
733   }
734   TRANSLATE_EXCEPTIONS("Could not get variable %s", key);
735 }
736
737 /** @brief Retrieve a double value of a variable (get a warning if not uniq)
738  *
739  * @param key the name of the variable
740  *
741  * Returns the first value from the config set under the given name.
742  */
743 double xbt_cfg_get_double(const char *key)
744 {
745   try {
746     return (*simgrid_config)[key].getValue<double>();
747   }
748   TRANSLATE_EXCEPTIONS("Could not get variable %s", key);
749 }
750
751 /** @brief Retrieve a string value of a variable (get a warning if not uniq)
752  *
753  * @param key the name of the variable
754  *
755  * Returns the first value from the config set under the given name.
756  * If there is more than one value, it will issue a warning.
757  * Returns nullptr if there is no value.
758  *
759  * \warning the returned value is the actual content of the config set
760  */
761 char *xbt_cfg_get_string(const char *key)
762 {
763   try {
764     return (char*) (*simgrid_config)[key].getValue<std::string>().c_str();
765   }
766   TRANSLATE_EXCEPTIONS("Could not get variable %s", key);
767 }
768
769 /** @brief Retrieve a boolean value of a variable (get a warning if not uniq)
770  *
771  * @param key the name of the variable
772  *
773  * Returns the first value from the config set under the given name.
774  * If there is more than one value, it will issue a warning.
775  */
776 int xbt_cfg_get_boolean(const char *key)
777 {
778   try {
779     return (*simgrid_config)[key].getValue<bool>() ? 1 : 0;
780   }
781   TRANSLATE_EXCEPTIONS("Could not get variable %s", key);
782 }
783
784 #ifdef SIMGRID_TEST
785
786 #include <string>
787
788 #include "xbt.h"
789 #include "xbt/ex.h"
790 #include <xbt/ex.hpp>
791
792 #include <xbt/config.hpp>
793
794 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(xbt_cfg);
795
796 XBT_TEST_SUITE("config", "Configuration support");
797
798 XBT_PUBLIC_DATA(xbt_cfg_t) simgrid_config;
799
800 static void make_set()
801 {
802   simgrid_config = nullptr;
803   xbt_log_threshold_set(&_XBT_LOGV(xbt_cfg), xbt_log_priority_critical);
804   xbt_cfg_register_int("speed", 0, nullptr, "");
805   xbt_cfg_register_string("peername", "", nullptr, "");
806   xbt_cfg_register_string("user", "", nullptr, "");
807 }                               /* end_of_make_set */
808
809 XBT_TEST_UNIT("memuse", test_config_memuse, "Alloc and free a config set")
810 {
811   auto temp = simgrid_config;
812   make_set();
813   xbt_test_add("Alloc and free a config set");
814   xbt_cfg_set_parse("peername:veloce user:bidule");
815   xbt_cfg_free(&simgrid_config);
816   simgrid_config = temp;
817 }
818
819 XBT_TEST_UNIT("use", test_config_use, "Data retrieving tests")
820 {
821   auto temp = simgrid_config;
822   make_set();
823   xbt_test_add("Get a single value");
824   {
825     /* get_single_value */
826     int ival;
827
828     xbt_cfg_set_parse("peername:toto:42 speed:42");
829     ival = xbt_cfg_get_int("speed");
830     if (ival != 42)
831       xbt_test_fail("Speed value = %d, I expected 42", ival);
832   }
833
834   xbt_test_add("Access to a non-existant entry");
835   {
836     try {
837       xbt_cfg_set_parse("color:blue");
838     } catch(xbt_ex& e) {
839       if (e.category != not_found_error)
840         xbt_test_exception(e);
841     }
842   }
843   xbt_cfg_free(&simgrid_config);
844   simgrid_config = temp;
845 }
846
847 XBT_TEST_UNIT("c++flags", test_config_cxx_flags, "C++ flags")
848 {
849   auto temp = simgrid_config;
850   make_set();
851   xbt_test_add("C++ declaration of flags");
852
853   simgrid::config::Flag<int> int_flag("int", "", 0);
854   simgrid::config::Flag<std::string> string_flag("string", "", "foo");
855   simgrid::config::Flag<double> double_flag("double", "", 0.32);
856   simgrid::config::Flag<bool> bool_flag1("bool1", "", false);
857   simgrid::config::Flag<bool> bool_flag2("bool2", "", true);
858
859   xbt_test_add("Parse values");
860   xbt_cfg_set_parse("int:42 string:bar double:8.0 bool1:true bool2:false");
861   xbt_test_assert(int_flag == 42, "Check int flag");
862   xbt_test_assert(string_flag == "bar", "Check string flag");
863   xbt_test_assert(double_flag == 8.0, "Check double flag");
864   xbt_test_assert(bool_flag1, "Check bool1 flag");
865   xbt_test_assert(not bool_flag2, "Check bool2 flag");
866
867   xbt_cfg_free(&simgrid_config);
868   simgrid_config = temp;
869 }
870
871 #endif                          /* SIMGRID_TEST */