Logo AND Algorithmique Numérique Distribuée

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