Logo AND Algorithmique Numérique Distribuée

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