Logo AND Algorithmique Numérique Distribuée

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