Logo AND Algorithmique Numérique Distribuée

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