Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Add -Wformat-signedness to warnCFLAGS for GCC >= 5.0.
[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 <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() = default;
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   bool warn_for_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     , warn_for_aliases(true)
320 {}
321
322 Config::~Config()
323 {
324   XBT_DEBUG("Frees cfg set %p", this);
325   xbt_dict_free(&this->options);
326   xbt_dict_free(&this->aliases);
327 }
328
329 inline
330 xbt_dictelm_t Config::getDictElement(const char* name)
331 {
332   // We are interested in the options dictelm:
333   xbt_dictelm_t res = xbt_dict_get_elm_or_null(options, name);
334   if (res)
335     return res;
336   // The aliases dict stores pointers to the options dictelm:
337   res = (xbt_dictelm_t) xbt_dict_get_or_null(aliases, name);
338   if (res && warn_for_aliases)
339     XBT_INFO("Option %s has been renamed to %s. Consider switching.", name, res->key);
340   return res;
341 }
342
343 inline
344 ConfigurationElement& Config::operator[](const char* name)
345 {
346   xbt_dictelm_t elm = getDictElement(name);
347   if (elm == nullptr)
348     throw simgrid::config::missing_key_error(std::string("Bad config key, ") + name);
349   return *(ConfigurationElement*)elm->content;
350 }
351
352 void Config::alias(const char* realname, const char* aliasname)
353 {
354   xbt_assert(this->getDictElement(aliasname) == nullptr, "Alias '%s' already.", aliasname);
355   xbt_dictelm_t element = this->getDictElement(realname);
356   xbt_assert(element, "Cannot define an alias to the non-existing option '%s'.", realname);
357   xbt_dict_set(this->aliases, aliasname, element, nullptr);
358 }
359
360 /** @brief Dump a config set for debuging purpose
361  *
362  * @param name The name to give to this config set
363  * @param indent what to write at the beginning of each line (right number of spaces)
364  */
365 void Config::dump(const char *name, const char *indent)
366 {
367   xbt_dict_t dict = this->options;
368   xbt_dict_cursor_t cursor = nullptr;
369   simgrid::config::ConfigurationElement* variable = nullptr;
370   char *key = nullptr;
371
372   if (name)
373     printf("%s>> Dumping of the config set '%s':\n", indent, name);
374
375   xbt_dict_foreach(dict, cursor, key, variable)
376     printf("%s  %s: ()%s) %s", indent, key,
377       variable->getTypeName(),
378       variable->getStringValue().c_str());
379
380   if (name)
381     printf("%s<< End of the config set '%s'\n", indent, name);
382   fflush(stdout);
383
384   xbt_dict_cursor_free(&cursor);
385 }
386
387 /** @brief Displays the declared aliases and their description */
388 void Config::showAliases()
389 {
390   xbt_dict_cursor_t dict_cursor;
391   xbt_dictelm_t dictel;
392   char *name;
393   std::vector<char*> names;
394
395   xbt_dict_foreach(this->aliases, dict_cursor, name, dictel)
396     names.push_back(name);
397   std::sort(begin(names), end(names), [](char* a, char* b) { return strcmp(a, b) < 0; });
398
399   bool old_warn_for_aliases = false;
400   std::swap(warn_for_aliases, old_warn_for_aliases);
401   for (auto name : names)
402     printf("   %s: %s\n", name, (*this)[name].getDescription().c_str());
403   std::swap(warn_for_aliases, old_warn_for_aliases);
404 }
405
406 /** @brief Displays the declared options and their description */
407 void Config::help()
408 {
409   xbt_dict_cursor_t dict_cursor;
410   simgrid::config::ConfigurationElement* variable;
411   char *name;
412   std::vector<char*> names;
413
414   xbt_dict_foreach(this->options, dict_cursor, name, variable)
415     names.push_back(name);
416   std::sort(begin(names), end(names), [](char* a, char* b) { return strcmp(a, b) < 0; });
417
418   for (auto name : names) {
419     variable = (simgrid::config::ConfigurationElement*) xbt_dict_get(this->options, name);
420     printf("   %s: %s\n", name, variable->getDescription().c_str());
421     printf("       Type: %s; ", variable->getTypeName());
422     printf("Current value: %s\n", variable->getStringValue().c_str());
423   }
424 }
425
426 // ***** getConfig *****
427
428 template<class T>
429 XBT_PUBLIC(T const&) getConfig(const char* name)
430 {
431   return (*simgrid_config)[name].getValue<T>();
432 }
433
434 template XBT_PUBLIC(int const&) getConfig<int>(const char* name);
435 template XBT_PUBLIC(double const&) getConfig<double>(const char* name);
436 template XBT_PUBLIC(bool const&) getConfig<bool>(const char* name);
437 template XBT_PUBLIC(std::string const&) getConfig<std::string>(const char* name);
438
439 // ***** alias *****
440
441 void alias(const char* realname, const char* aliasname)
442 {
443   simgrid_config->alias(realname, aliasname);
444 }
445
446 // ***** declareFlag *****
447
448 template<class T>
449 XBT_PUBLIC(void) declareFlag(const char* name, const char* description,
450   T value, std::function<void(const T&)> callback)
451 {
452   if (simgrid_config == nullptr) {
453     simgrid_config = xbt_cfg_new();
454     atexit(sg_config_finalize);
455   }
456   simgrid_config->registerOption<T>(
457     name, description, std::move(value), std::move(callback));
458 }
459
460 template XBT_PUBLIC(void) declareFlag(const char* name,
461   const char* description, int value, std::function<void(int const &)> callback);
462 template XBT_PUBLIC(void) declareFlag(const char* name,
463   const char* description, double value, std::function<void(double const &)> callback);
464 template XBT_PUBLIC(void) declareFlag(const char* name,
465   const char* description, bool value, std::function<void(bool const &)> callback);
466 template XBT_PUBLIC(void) declareFlag(const char* name,
467   const char* description, std::string value, std::function<void(std::string const &)> callback);
468
469 }
470 }
471
472 // ***** C bindings *****
473
474 xbt_cfg_t xbt_cfg_new()        { return new simgrid::config::Config(); }
475 void xbt_cfg_free(xbt_cfg_t * cfg) { delete *cfg; }
476
477 void xbt_cfg_dump(const char *name, const char *indent, xbt_cfg_t cfg)
478 {
479   cfg->dump(name, indent);
480 }
481
482 /*----[ Registering stuff ]-----------------------------------------------*/
483
484 void xbt_cfg_register_double(const char *name, double default_value,
485   xbt_cfg_cb_t cb_set, const char *desc)
486 {
487   if (simgrid_config == nullptr)
488     simgrid_config = xbt_cfg_new();
489   simgrid_config->registerOption<double>(name, desc, default_value, cb_set);
490 }
491
492 void xbt_cfg_register_int(const char *name, int default_value,xbt_cfg_cb_t cb_set, const char *desc)
493 {
494   if (simgrid_config == nullptr) {
495     simgrid_config = xbt_cfg_new();
496     atexit(&sg_config_finalize);
497   }
498   simgrid_config->registerOption<int>(name, desc, default_value, cb_set);
499 }
500
501 void xbt_cfg_register_string(const char *name, const char *default_value, xbt_cfg_cb_t cb_set, const char *desc)
502 {
503   if (simgrid_config == nullptr) {
504     simgrid_config = xbt_cfg_new();
505     atexit(sg_config_finalize);
506   }
507   simgrid_config->registerOption<std::string>(name, desc,
508     default_value ? default_value : "", cb_set);
509 }
510
511 void xbt_cfg_register_boolean(const char *name, const char*default_value,xbt_cfg_cb_t cb_set, const char *desc)
512 {
513   if (simgrid_config == nullptr) {
514     simgrid_config = xbt_cfg_new();
515     atexit(sg_config_finalize);
516   }
517   simgrid_config->registerOption<bool>(name, desc, simgrid::config::parseBool(default_value), cb_set);
518 }
519
520 void xbt_cfg_register_alias(const char *realname, const char *aliasname)
521 {
522   if (simgrid_config == nullptr) {
523     simgrid_config = xbt_cfg_new();
524     atexit(sg_config_finalize);
525   }
526   simgrid_config->alias(realname, aliasname);
527 }
528
529 void xbt_cfg_aliases() { simgrid_config->showAliases(); }
530 void xbt_cfg_help()    { simgrid_config->help(); }
531
532 /*----[ Setting ]---------------------------------------------------------*/
533
534 /** @brief Add values parsed from a string into a config set
535  *
536  * @param options a string containing the content to add to the config set. This is a '\\t',' ' or '\\n' or ','
537  * separated list of variables. Each individual variable is like "[name]:[value]" where [name] is the name of an
538  * already registered variable, and [value] conforms to the data type under which this variable was registered.
539  *
540  * @todo This is a crude manual parser, it should be a proper lexer.
541  */
542 void xbt_cfg_set_parse(const char *options)
543 {
544   if (not options || not strlen(options)) { /* nothing to do */
545     return;
546   }
547   char *optionlist_cpy = xbt_strdup(options);
548
549   XBT_DEBUG("List to parse and set:'%s'", options);
550   char *option = optionlist_cpy;
551   while (1) {                   /* breaks in the code */
552     if (not option)
553       break;
554     char *name = option;
555     int len = strlen(name);
556     XBT_DEBUG("Still to parse and set: '%s'. len=%d; option-name=%ld", name, len, (long) (option - name));
557
558     /* Pass the value */
559     while (option - name <= (len - 1) && *option != ' ' && *option != '\n' && *option != '\t' && *option != ',') {
560       XBT_DEBUG("Take %c.", *option);
561       option++;
562     }
563     if (option - name == len) {
564       XBT_DEBUG("Boundary=EOL");
565       option = nullptr;            /* don't do next iteration */
566     } else {
567       XBT_DEBUG("Boundary on '%c'. len=%d;option-name=%ld", *option, len, (long) (option - name));
568       /* Pass the following blank chars */
569       *(option++) = '\0';
570       while (option - name < (len - 1) && (*option == ' ' || *option == '\n' || *option == '\t')) {
571         /*      fprintf(stderr,"Ignore a blank char.\n"); */
572         option++;
573       }
574       if (option - name == len - 1)
575         option = nullptr;          /* don't do next iteration */
576     }
577     XBT_DEBUG("parse now:'%s'; parse later:'%s'", name, option);
578
579     if (name[0] == ' ' || name[0] == '\n' || name[0] == '\t')
580       continue;
581     if (not strlen(name))
582       break;
583
584     char *val = strchr(name, ':');
585     xbt_assert(val, "Option '%s' badly formatted. Should be of the form 'name:value'", name);
586     /* don't free(optionlist_cpy) if the assert fails, 'name' points inside it */
587     *(val++) = '\0';
588
589     if (strncmp(name, "path", strlen("path")))
590       XBT_INFO("Configuration change: Set '%s' to '%s'", name, val);
591
592     try {
593       (*simgrid_config)[name].setStringValue(val);
594     }
595     catch (simgrid::config::missing_key_error& e) {
596       goto on_missing_key;
597     }
598     catch (...) {
599       goto on_exception;
600     }
601   }
602
603   free(optionlist_cpy);
604   return;
605
606   /* Do not THROWF from a C++ exception catching context, or some cleanups will be missing */
607 on_missing_key:
608   free(optionlist_cpy);
609   THROWF(not_found_error, 0, "Could not set variables %s", options);
610   return;
611 on_exception:
612   free(optionlist_cpy);
613   THROWF(unknown_error, 0, "Could not set variables %s", options);
614 }
615
616 // Horrible mess to translate C++ exceptions to C exceptions:
617 // Exit from the catch blog (and do the correct exceptio cleaning)
618 // before attempting to THROWF.
619 #define TRANSLATE_EXCEPTIONS(...) \
620   catch(simgrid::config::missing_key_error& e) { THROWF(not_found_error, 0, __VA_ARGS__); abort(); } \
621   catch(...) { THROWF(not_found_error, 0, __VA_ARGS__); abort(); }
622
623 /** @brief Set the value of a variable, using the string representation of that value
624  *
625  * @param key name of the variable to modify
626  * @param value string representation of the value to set
627  */
628
629 void xbt_cfg_set_as_string(const char *key, const char *value)
630 {
631   try {
632     (*simgrid_config)[key].setStringValue(value);
633     return;
634   }
635   TRANSLATE_EXCEPTIONS("Could not set variable %s as string %s", key, value);
636 }
637
638 /** @brief Set an integer value to \a name within \a cfg if it wasn't changed yet
639  *
640  * This is useful to change the default value of a variable while allowing
641  * users to override it with command line arguments
642  */
643 void xbt_cfg_setdefault_int(const char *key, int value)
644 {
645   try {
646     (*simgrid_config)[key].setDefaultValue<int>(value);
647     return;
648   }
649   TRANSLATE_EXCEPTIONS("Could not set variable %s to default integer %i",
650     key, value);
651 }
652
653 /** @brief Set an integer value to \a name within \a cfg if it wasn't changed yet
654  *
655  * This is useful to change the default value of a variable while allowing
656  * users to override it with command line arguments
657  */
658 void xbt_cfg_setdefault_double(const char *key, double value)
659 {
660   try {
661     (*simgrid_config)[key].setDefaultValue<double>(value);
662     return;
663   }
664   TRANSLATE_EXCEPTIONS("Could not set variable %s to default double %f",
665     key, value);
666 }
667
668 /** @brief Set a string value to \a name within \a cfg if it wasn't changed yet
669  *
670  * This is useful to change the default value of a variable while allowing
671  * users to override it with command line arguments
672  */
673 void xbt_cfg_setdefault_string(const char *key, const char *value)
674 {
675   try {
676     (*simgrid_config)[key].setDefaultValue<std::string>(value ? value : "");
677     return;
678   }
679   TRANSLATE_EXCEPTIONS("Could not set variable %s to default string %s",
680     key, value);
681 }
682
683 /** @brief Set an boolean value to \a name within \a cfg if it wasn't changed yet
684  *
685  * This is useful to change the default value of a variable while allowing
686  * users to override it with command line arguments
687  */
688 void xbt_cfg_setdefault_boolean(const char *key, const char *value)
689 {
690   try {
691     (*simgrid_config)[key].setDefaultValue<bool>(simgrid::config::parseBool(value));
692     return;
693   }
694   TRANSLATE_EXCEPTIONS("Could not set variable %s to default boolean %s",
695     key, value);
696 }
697
698 /** @brief Set an integer value to \a name within \a cfg
699  *
700  * @param key the name of the variable
701  * @param value the value of the variable
702  */
703 void xbt_cfg_set_int(const char *key, int value)
704 {
705   try {
706     (*simgrid_config)[key].setValue<int>(value);
707     return;
708   }
709   TRANSLATE_EXCEPTIONS("Could not set variable %s to integer %i",
710     key, value);
711 }
712
713 /** @brief Set or add a double value to \a name within \a cfg
714  *
715  * @param key the name of the variable
716  * @param value the double to set
717  */
718 void xbt_cfg_set_double(const char *key, double value)
719 {
720   try {
721     (*simgrid_config)[key].setValue<double>(value);
722     return;
723   }
724   TRANSLATE_EXCEPTIONS("Could not set variable %s to double %f",
725     key, value);
726 }
727
728 /** @brief Set or add a string value to \a name within \a cfg
729  *
730  * @param key the name of the variable
731  * @param value the value to be added
732  *
733  */
734 void xbt_cfg_set_string(const char *key, const char *value)
735 {
736   try {
737     (*simgrid_config)[key].setValue<std::string>(value ? value : "");
738     return;
739   }
740   TRANSLATE_EXCEPTIONS("Could not set variable %s to string %s",
741     key, value);
742 }
743
744 /** @brief Set or add a boolean value to \a name within \a cfg
745  *
746  * @param key the name of the variable
747  * @param value the value of the variable
748  */
749 void xbt_cfg_set_boolean(const char *key, const char *value)
750 {
751   try {
752     (*simgrid_config)[key].setValue<bool>(simgrid::config::parseBool(value));
753     return;
754   }
755   TRANSLATE_EXCEPTIONS("Could not set variable %s to boolean %s",
756     key, value);
757 }
758
759
760 /* Say if the value is the default value */
761 int xbt_cfg_is_default_value(const char *key)
762 {
763   try {
764     return (*simgrid_config)[key].isDefault() ? 1 : 0;
765   }
766   TRANSLATE_EXCEPTIONS("Could not get variable %s", key);
767 }
768
769 /*----[ Getting ]---------------------------------------------------------*/
770 /** @brief Retrieve an integer value of a variable (get a warning if not uniq)
771  *
772  * @param key the name of the variable
773  *
774  * Returns the first value from the config set under the given name.
775  */
776 int xbt_cfg_get_int(const char *key)
777 {
778   try {
779     return (*simgrid_config)[key].getValue<int>();
780   }
781   TRANSLATE_EXCEPTIONS("Could not get variable %s", key);
782 }
783
784 /** @brief Retrieve a double value of a variable (get a warning if not uniq)
785  *
786  * @param key the name of the variable
787  *
788  * Returns the first value from the config set under the given name.
789  */
790 double xbt_cfg_get_double(const char *key)
791 {
792   try {
793     return (*simgrid_config)[key].getValue<double>();
794   }
795   TRANSLATE_EXCEPTIONS("Could not get variable %s", key);
796 }
797
798 /** @brief Retrieve a string value of a variable (get a warning if not uniq)
799  *
800  * @param key the name of the variable
801  *
802  * Returns the first value from the config set under the given name.
803  * If there is more than one value, it will issue a warning.
804  * Returns nullptr if there is no value.
805  *
806  * \warning the returned value is the actual content of the config set
807  */
808 char *xbt_cfg_get_string(const char *key)
809 {
810   try {
811     return (char*) (*simgrid_config)[key].getValue<std::string>().c_str();
812   }
813   TRANSLATE_EXCEPTIONS("Could not get variable %s", key);
814 }
815
816 /** @brief Retrieve a boolean value of a variable (get a warning if not uniq)
817  *
818  * @param key the name of the variable
819  *
820  * Returns the first value from the config set under the given name.
821  * If there is more than one value, it will issue a warning.
822  */
823 int xbt_cfg_get_boolean(const char *key)
824 {
825   try {
826     return (*simgrid_config)[key].getValue<bool>() ? 1 : 0;
827   }
828   TRANSLATE_EXCEPTIONS("Could not get variable %s", key);
829 }
830
831 #ifdef SIMGRID_TEST
832
833 #include <string>
834
835 #include "xbt.h"
836 #include "xbt/ex.h"
837 #include <xbt/ex.hpp>
838
839 #include <xbt/config.hpp>
840
841 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(xbt_cfg);
842
843 XBT_TEST_SUITE("config", "Configuration support");
844
845 XBT_PUBLIC_DATA(xbt_cfg_t) simgrid_config;
846
847 static void make_set()
848 {
849   simgrid_config = nullptr;
850   xbt_log_threshold_set(&_XBT_LOGV(xbt_cfg), xbt_log_priority_critical);
851   xbt_cfg_register_int("speed", 0, nullptr, "");
852   xbt_cfg_register_string("peername", "", nullptr, "");
853   xbt_cfg_register_string("user", "", nullptr, "");
854 }                               /* end_of_make_set */
855
856 XBT_TEST_UNIT("memuse", test_config_memuse, "Alloc and free a config set")
857 {
858   auto temp = simgrid_config;
859   make_set();
860   xbt_test_add("Alloc and free a config set");
861   xbt_cfg_set_parse("peername:veloce user:bidule");
862   xbt_cfg_free(&simgrid_config);
863   simgrid_config = temp;
864 }
865
866 XBT_TEST_UNIT("use", test_config_use, "Data retrieving tests")
867 {
868   auto temp = simgrid_config;
869   make_set();
870   xbt_test_add("Get a single value");
871   {
872     /* get_single_value */
873     int ival;
874
875     xbt_cfg_set_parse("peername:toto:42 speed:42");
876     ival = xbt_cfg_get_int("speed");
877     if (ival != 42)
878       xbt_test_fail("Speed value = %d, I expected 42", ival);
879   }
880
881   xbt_test_add("Access to a non-existant entry");
882   {
883     try {
884       xbt_cfg_set_parse("color:blue");
885     } catch(xbt_ex& e) {
886       if (e.category != not_found_error)
887         xbt_test_exception(e);
888     }
889   }
890   xbt_cfg_free(&simgrid_config);
891   simgrid_config = temp;
892 }
893
894 XBT_TEST_UNIT("c++flags", test_config_cxx_flags, "C++ flags")
895 {
896   auto temp = simgrid_config;
897   make_set();
898   xbt_test_add("C++ declaration of flags");
899
900   simgrid::config::Flag<int> int_flag("int", "", 0);
901   simgrid::config::Flag<std::string> string_flag("string", "", "foo");
902   simgrid::config::Flag<double> double_flag("double", "", 0.32);
903   simgrid::config::Flag<bool> bool_flag1("bool1", "", false);
904   simgrid::config::Flag<bool> bool_flag2("bool2", "", true);
905
906   xbt_test_add("Parse values");
907   xbt_cfg_set_parse("int:42 string:bar double:8.0 bool1:true bool2:false");
908   xbt_test_assert(int_flag == 42, "Check int flag");
909   xbt_test_assert(string_flag == "bar", "Check string flag");
910   xbt_test_assert(double_flag == 8.0, "Check double flag");
911   xbt_test_assert(bool_flag1, "Check bool1 flag");
912   xbt_test_assert(not bool_flag2, "Check bool2 flag");
913
914   xbt_cfg_free(&simgrid_config);
915   simgrid_config = temp;
916 }
917
918 #endif                          /* SIMGRID_TEST */