Logo AND Algorithmique Numérique Distribuée

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