Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[XBT] Expanded error message for cfg values
[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_cfgelm_t: the typedef corresponding to a config variable.
25
26    Both data and DTD are mixed, but fixing it now would prevent me to ever
27    defend my thesis. */
28
29 typedef struct {
30   /* Description */
31   char *desc;
32
33   /* Allowed type of the variable */
34   e_xbt_cfgelm_type_t type;
35   int min, max;
36   unsigned isdefault:1;
37
38   /* Callbacks */
39   xbt_cfg_cb_t cb_set;
40   xbt_cfg_cb_t cb_rm;
41
42   /* actual content
43      (cannot be an union because type peer used to use both str and i, but it could be converted now) */
44   xbt_dynar_t content;
45 } s_xbt_cfgelm_t, *xbt_cfgelm_t;
46
47 static const char *xbt_cfgelm_type_name[xbt_cfgelm_type_count] =
48     { "int", "double", "string", "boolean", "any" };
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,
63                                    e_xbt_cfgelm_type_t type);
64
65 /*----[ Memory management ]-----------------------------------------------*/
66
67 /** @brief Constructor
68  *
69  * Initialise a config set
70  */
71
72
73 xbt_cfg_t xbt_cfg_new(void)
74 {
75   return (xbt_cfg_t) xbt_dict_new_homogeneous(&xbt_cfgelm_free);
76 }
77
78 /** \brief Copy an existing configuration set
79  *
80  * @param whereto the config set to be created
81  * @param tocopy the source data
82  *
83  * This only copy the registrations, not the actual content
84  */
85
86 void xbt_cfg_cpy(xbt_cfg_t tocopy, xbt_cfg_t * whereto)
87 {
88   xbt_dict_cursor_t cursor = NULL;
89   xbt_cfgelm_t variable = NULL;
90   char *name = NULL;
91
92   XBT_DEBUG("Copy cfg set %p", tocopy);
93   *whereto = NULL;
94   xbt_assert(tocopy, "cannot copy NULL config");
95
96   xbt_dict_foreach((xbt_dict_t) tocopy, cursor, name, variable) {
97     xbt_cfg_register(whereto, name, variable->desc, variable->type,
98                      variable->min, variable->max, variable->cb_set,
99                      variable->cb_rm);
100   }
101 }
102
103 /** @brief Destructor */
104 void xbt_cfg_free(xbt_cfg_t * cfg)
105 {
106   XBT_DEBUG("Frees cfg set %p", cfg);
107   xbt_dict_free((xbt_dict_t *) cfg);
108 }
109
110 /** @brief Dump a config set for debuging purpose
111  *
112  * @param name The name to give to this config set
113  * @param indent what to write at the begining of each line (right number of spaces)
114  * @param cfg the config set
115  */
116 void xbt_cfg_dump(const char *name, const char *indent, xbt_cfg_t cfg)
117 {
118   xbt_dict_t dict = (xbt_dict_t) cfg;
119   xbt_dict_cursor_t cursor = NULL;
120   xbt_cfgelm_t variable = NULL;
121   char *key = NULL;
122   int i;
123   int size;
124   int ival;
125   char *sval;
126   double dval;
127
128   if (name)
129     printf("%s>> Dumping of the config set '%s':\n", indent, name);
130   xbt_dict_foreach(dict, cursor, key, variable) {
131
132     printf("%s  %s:", indent, key);
133
134     size = xbt_dynar_length(variable->content);
135     printf
136         ("%d_to_%d_%s. Actual size=%d. prerm=%p,postset=%p, List of values:\n",
137          variable->min, variable->max,
138          xbt_cfgelm_type_name[variable->type], size, variable->cb_rm,
139          variable->cb_set);
140
141     switch (variable->type) {
142
143     case xbt_cfgelm_int:
144       for (i = 0; i < size; i++) {
145         ival = xbt_dynar_get_as(variable->content, i, int);
146         printf("%s    %d\n", indent, ival);
147       }
148       break;
149
150     case xbt_cfgelm_double:
151       for (i = 0; i < size; i++) {
152         dval = xbt_dynar_get_as(variable->content, i, double);
153         printf("%s    %f\n", indent, dval);
154       }
155       break;
156
157     case xbt_cfgelm_string:
158       for (i = 0; i < size; i++) {
159         sval = xbt_dynar_get_as(variable->content, i, char *);
160         printf("%s    %s\n", indent, sval);
161       }
162       break;
163
164     case xbt_cfgelm_boolean:
165       for (i = 0; i < size; i++) {
166         ival = xbt_dynar_get_as(variable->content, i, int);
167         printf("%s    %d\n", indent, ival);
168       }
169       break;
170
171     default:
172       printf("%s    Invalid type!!\n", indent);
173     }
174
175   }
176
177   if (name)
178     printf("%s<< End of the config set '%s'\n", indent, name);
179   fflush(stdout);
180
181   xbt_dict_cursor_free(&cursor);
182   return;
183 }
184
185 /*
186  * free an config element
187  */
188
189 void xbt_cfgelm_free(void *data)
190 {
191   xbt_cfgelm_t c = (xbt_cfgelm_t) data;
192
193   XBT_DEBUG("Frees cfgelm %p", c);
194   if (!c)
195     return;
196   xbt_free(c->desc);
197   xbt_dynar_free(&(c->content));
198   free(c);
199 }
200
201 /*----[ Registering stuff ]-----------------------------------------------*/
202
203 /** @brief Register an element within a config set
204  *
205  *  @param cfg the config set
206  *  @param name the name of the config element
207  *  @param desc a description for this item (used by xbt_cfg_help())
208  *  @param type the type of the config element
209  *  @param min the minimum number of values for this config element
210  *  @param max the maximum number of values for this config element
211  *  @param cb_set callback function called when a value is set
212  *  @param cb_rm callback function called when a value is removed
213  */
214
215 void
216 xbt_cfg_register(xbt_cfg_t * cfg,
217                  const char *name, const char *desc,
218                  e_xbt_cfgelm_type_t type, int min,
219                  int max, xbt_cfg_cb_t cb_set, xbt_cfg_cb_t cb_rm)
220 {
221   xbt_cfgelm_t res;
222
223   if (*cfg == NULL)
224     *cfg = xbt_cfg_new();
225   xbt_assert(type >= xbt_cfgelm_int && type <= xbt_cfgelm_boolean,
226               "type of %s not valid (%d should be between %d and %d)",
227              name, (int)type, xbt_cfgelm_int, xbt_cfgelm_boolean);
228   res = xbt_dict_get_or_null((xbt_dict_t) * cfg, name);
229
230   if (res) {
231     XBT_WARN("Config elem %s registered twice.", name);
232     /* Will be removed by the insertion of the new one */
233   }
234
235   res = xbt_new(s_xbt_cfgelm_t, 1);
236   XBT_DEBUG("Register cfg elm %s (%s) (%d to %d %s (=%d) @%p in set %p)",
237             name, desc, min, max, xbt_cfgelm_type_name[type], (int)type, res,
238          *cfg);
239
240   res->desc = xbt_strdup(desc);
241   res->type = type;
242   res->min = min;
243   res->max = max;
244   res->cb_set = cb_set;
245   res->cb_rm = cb_rm;
246   res->isdefault = 1;
247
248   switch (type) {
249   case xbt_cfgelm_int:
250     res->content = xbt_dynar_new(sizeof(int), NULL);
251     break;
252
253   case xbt_cfgelm_double:
254     res->content = xbt_dynar_new(sizeof(double), NULL);
255     break;
256
257   case xbt_cfgelm_string:
258     res->content = xbt_dynar_new(sizeof(char *), xbt_free_ref);
259     break;
260
261   case xbt_cfgelm_boolean:
262     res->content = xbt_dynar_new(sizeof(int), NULL);
263     break;
264
265   default:
266     XBT_ERROR("%d is an invalid type code", (int)type);
267   }
268
269   xbt_dict_set((xbt_dict_t) * cfg, name, res, NULL);
270 }
271
272 /** @brief Unregister an element from a config set.
273  *
274  *  @param cfg the config set
275  *  @param name the name of the element to be freed
276  *
277  *  Note that it removes both the description and the actual content.
278  *  Throws not_found when no such element exists.
279  */
280
281 void xbt_cfg_unregister(xbt_cfg_t cfg, const char *name)
282 {
283   XBT_DEBUG("Unregister elm '%s' from set %p", name, cfg);
284   xbt_dict_remove((xbt_dict_t) cfg, name);
285 }
286
287 /**
288  * @brief Parse a string and register the stuff described.
289  *
290  * @param cfg the config set
291  * @param entry a string describing the element to register
292  *
293  * The string may consist in several variable descriptions separated by a space.
294  * Each of them must use the following syntax: \<name\>:\<min nb\>_to_\<max nb\>_\<type\>
295  * with type being one of  'string','int' or 'double'.
296  *
297  * FIXME: this does not allow to set the description
298  */
299
300 void xbt_cfg_register_str(xbt_cfg_t * cfg, const char *entry)
301 {
302   char *entrycpy = xbt_strdup(entry);
303   char *tok;
304
305   int min, max;
306   e_xbt_cfgelm_type_t type;
307   XBT_DEBUG("Register string '%s'", entry);
308
309   tok = strchr(entrycpy, ':');
310   xbt_assert(tok, "Invalid config element descriptor: %s%s",
311               entry, "; Should be <name>:<min nb>_to_<max nb>_<type>");
312   *(tok++) = '\0';
313
314   min = strtol(tok, &tok, 10);
315   xbt_assert(tok, "Invalid minimum in config element descriptor %s",
316               entry);
317
318   xbt_assert(strcmp(tok, "_to_"),
319               "Invalid config element descriptor : %s%s",
320               entry, "; Should be <name>:<min nb>_to_<max nb>_<type>");
321   tok += strlen("_to_");
322
323   max = strtol(tok, &tok, 10);
324   xbt_assert(tok, "Invalid maximum in config element descriptor %s",
325               entry);
326
327   xbt_assert(*tok == '_',
328               "Invalid config element descriptor: %s%s", entry,
329               "; Should be <name>:<min nb>_to_<max nb>_<type>");
330   tok++;
331
332   for (type = (e_xbt_cfgelm_type_t)0;
333        type < xbt_cfgelm_type_count
334        && strcmp(tok, xbt_cfgelm_type_name[type]); type++);
335   xbt_assert(type < xbt_cfgelm_type_count,
336               "Invalid type in config element descriptor: %s%s", entry,
337               "; Should be one of 'string', 'int' or 'double'.");
338
339   xbt_cfg_register(cfg, entrycpy, NULL, type, min, max, NULL, NULL);
340
341   free(entrycpy);               /* strdup'ed by dict mechanism, but cannot be const */
342 }
343
344 static int strcmp_voidp(const void *pa, const void *pb)
345 {
346   return strcmp(*(const char **)pa, *(const char **)pb);
347 }
348
349 /** @brief Displays the declared options and their description */
350 void xbt_cfg_help(xbt_cfg_t cfg)
351 {
352   xbt_dict_cursor_t dict_cursor;
353   unsigned int dynar_cursor;
354   xbt_cfgelm_t variable;
355   char *name;
356   xbt_dynar_t names = xbt_dynar_new(sizeof(char *), NULL);
357
358   xbt_dict_foreach((xbt_dict_t )cfg, dict_cursor, name, variable) {
359     xbt_dynar_push(names, &name);
360   }
361   xbt_dynar_sort(names, strcmp_voidp);
362
363   xbt_dynar_foreach(names, dynar_cursor, name) {
364     int i;
365     int size;
366     variable = xbt_dict_get((xbt_dict_t )cfg, name);
367
368     printf("   %s: %s\n", name, variable->desc);
369     printf("       Type: %s; ", xbt_cfgelm_type_name[variable->type]);
370     if (variable->min != 1 || variable->max != 1) {
371       printf("Arity: min:%d to max:", variable->min);
372       if (variable->max == 0)
373         printf("(no bound); ");
374       else
375         printf("%d; ", variable->max);
376     }
377     size = xbt_dynar_length(variable->content);
378     printf("Current value%s: ", (size <= 1 ? "" : "s"));
379
380     if (size != 1)
381       printf(size == 0 ? "n/a\n" : "{ ");
382     for (i = 0; i < size; i++) {
383       const char *sep = (size == 1 ? "\n" : (i < size - 1 ? ", " : " }\n"));
384
385       switch (variable->type) {
386       case xbt_cfgelm_int:
387         printf("%d%s", xbt_dynar_get_as(variable->content, i, int), sep);
388         break;
389
390       case xbt_cfgelm_double:
391         printf("%f%s", xbt_dynar_get_as(variable->content, i, double), sep);
392         break;
393
394       case xbt_cfgelm_string:
395         printf("'%s'%s", xbt_dynar_get_as(variable->content, i, char *), sep);
396         break;
397
398       case xbt_cfgelm_boolean: {
399         int b = xbt_dynar_get_as(variable->content, i, int);
400         const char *bs = b ? xbt_cfgelm_boolean_values[0].true_val
401                            : xbt_cfgelm_boolean_values[0].false_val;
402         if (b == 0 || b == 1)
403           printf("'%s'%s", bs, sep);
404         else
405           printf("'%s/%d'%s", bs, b, sep);
406         break;
407       }
408
409       default:
410         printf("Invalid type!!%s", sep);
411       }
412     }
413   }
414
415   xbt_dynar_free(&names);
416 }
417
418 /** @brief Check that each variable have the right amount of values */
419 void xbt_cfg_check(xbt_cfg_t cfg)
420 {
421   xbt_dict_cursor_t cursor;
422   xbt_cfgelm_t variable;
423   char *name;
424   int size;
425
426   xbt_assert(cfg, "NULL config set.");
427   XBT_DEBUG("Check cfg set %p", cfg);
428
429   xbt_dict_foreach((xbt_dict_t) cfg, cursor, name, variable) {
430     size = xbt_dynar_length(variable->content);
431     if (variable->min > size) {
432       xbt_dict_cursor_free(&cursor);
433       THROWF(mismatch_error, 0,
434              "Config elem %s needs at least %d %s, but there is only %d values.",
435              name, variable->min, xbt_cfgelm_type_name[variable->type],
436              size);
437     }
438
439     if (variable->isdefault && size > variable->min) {
440       xbt_dict_cursor_free(&cursor);
441       THROWF(mismatch_error, 0,
442              "Config elem %s theoretically accepts %d %s, but has a default of %d values.",
443              name, variable->min, xbt_cfgelm_type_name[variable->type], size);
444     }
445
446     if (variable->max > 0 && variable->max < size) {
447       xbt_dict_cursor_free(&cursor);
448       THROWF(mismatch_error, 0,
449              "Config elem %s accepts at most %d %s, but there is %d values.",
450              name, variable->max, xbt_cfgelm_type_name[variable->type],
451              size);
452     }
453   }
454
455   xbt_dict_cursor_free(&cursor);
456 }
457
458 static xbt_cfgelm_t xbt_cfgelm_get(xbt_cfg_t cfg,
459                                    const char *name,
460                                    e_xbt_cfgelm_type_t type)
461 {
462   xbt_cfgelm_t res = NULL;
463
464   res = xbt_dict_get_or_null((xbt_dict_t) cfg, name);
465   if (!res) {
466     xbt_cfg_help(cfg);
467     THROWF(not_found_error, 0,
468            "No registered variable '%s' in this config set. It is possible that this "\
469            "configuration option has been renamed; please read the file ChangeLog carefully!", name);
470   }
471
472   xbt_assert(type == xbt_cfgelm_any || res->type == type,
473               "You tried to access to the config element %s as an %s, but its type is %s.",
474               name,
475               xbt_cfgelm_type_name[type], xbt_cfgelm_type_name[res->type]);
476
477   return res;
478 }
479
480 /** @brief Get the type of this variable in that configuration set
481  *
482  * @param cfg the config set
483  * @param name the name of the element
484  *
485  * @return the type of the given element
486  */
487
488 e_xbt_cfgelm_type_t xbt_cfg_get_type(xbt_cfg_t cfg, const char *name)
489 {
490
491   xbt_cfgelm_t variable = NULL;
492
493   variable = xbt_dict_get_or_null((xbt_dict_t) cfg, name);
494   if (!variable)
495     THROWF(not_found_error, 0,
496            "Can't get the type of '%s' since this variable does not exist",
497            name);
498
499   XBT_DEBUG("type in variable = %d", (int)variable->type);
500
501   return variable->type;
502 }
503
504 /*----[ Setting ]---------------------------------------------------------*/
505 /**  @brief va_args version of xbt_cfg_set
506  *
507  * @param cfg config set to fill
508  * @param name  variable name
509  * @param pa  variable value
510  *
511  * Add some values to the config set.
512  */
513 void xbt_cfg_set_vargs(xbt_cfg_t cfg, const char *name, va_list pa)
514 {
515   char *str;
516   int i;
517   double d;
518   e_xbt_cfgelm_type_t type = xbt_cfgelm_any; /* Set a dummy value to make gcc happy. It cannot get uninitialized */
519
520   xbt_ex_t e;
521
522   TRY {
523     type = xbt_cfg_get_type(cfg, name);
524   }
525   CATCH(e) {
526     if (e.category == not_found_error) {
527       xbt_ex_free(e);
528       THROWF(not_found_error, 0,
529              "Can't set the property '%s' since it's not registered",
530              name);
531     }
532     RETHROW;
533   }
534
535   switch (type) {
536   case xbt_cfgelm_string:
537     str = va_arg(pa, char *);
538     xbt_cfg_set_string(cfg, name, str);
539     break;
540
541   case xbt_cfgelm_int:
542     i = va_arg(pa, int);
543     xbt_cfg_set_int(cfg, name, i);
544     break;
545
546   case xbt_cfgelm_double:
547     d = va_arg(pa, double);
548     xbt_cfg_set_double(cfg, name, d);
549     break;
550
551   case xbt_cfgelm_boolean:
552     str = va_arg(pa, char *);
553     xbt_cfg_set_boolean(cfg, name, str);
554     break;
555
556   default:
557     xbt_die("Config element variable %s not valid (type=%d)", name, (int)type);
558   }
559 }
560
561 /** @brief Add a NULL-terminated list of pairs {(char*)key, value} to the set
562  *
563  * @param cfg config set to fill
564  * @param name variable name
565  * @param ... variable value
566  *
567  */
568 void xbt_cfg_set(xbt_cfg_t cfg, const char *name, ...)
569 {
570   va_list pa;
571
572   va_start(pa, name);
573   xbt_cfg_set_vargs(cfg, name, pa);
574   va_end(pa);
575 }
576
577 /** @brief Add values parsed from a string into a config set
578  *
579  * @param cfg config set to fill
580  * @param options a string containing the content to add to the config set. This
581  * is a '\\t',' ' or '\\n' or ',' separated list of variables. Each individual variable is
582  * like "[name]:[value]" where [name] is the name of an already registred
583  * variable, and [value] conforms to the data type under which this variable was
584  * registred.
585  *
586  * @todo This is a crude manual parser, it should be a proper lexer.
587  */
588
589 void xbt_cfg_set_parse(xbt_cfg_t cfg, const char *options) {
590
591   char *optionlist_cpy;
592   char *option, *name, *val;
593
594   int len;
595
596   XBT_IN();
597   if (!options || !strlen(options)) {   /* nothing to do */
598     return;
599   }
600   optionlist_cpy = xbt_strdup(options);
601
602   XBT_DEBUG("List to parse and set:'%s'", options);
603   option = optionlist_cpy;
604   while (1) {                   /* breaks in the code */
605
606     if (!option)
607       break;
608     name = option;
609     len = strlen(name);
610     XBT_DEBUG("Still to parse and set: '%s'. len=%d; option-name=%ld",
611            name, len, (long) (option - name));
612
613     /* Pass the value */
614     while (option - name <= (len - 1) && *option != ' ' && *option != '\n'
615            && *option != '\t' && *option != ',') {
616       XBT_DEBUG("Take %c.", *option);
617       option++;
618     }
619     if (option - name == len) {
620       XBT_DEBUG("Boundary=EOL");
621       option = NULL;            /* don't do next iteration */
622
623     } else {
624       XBT_DEBUG("Boundary on '%c'. len=%d;option-name=%ld",
625              *option, len, (long) (option - name));
626
627       /* Pass the following blank chars */
628       *(option++) = '\0';
629       while (option - name < (len - 1) &&
630              (*option == ' ' || *option == '\n' || *option == '\t')) {
631         /*      fprintf(stderr,"Ignore a blank char.\n"); */
632         option++;
633       }
634       if (option - name == len - 1)
635         option = NULL;          /* don't do next iteration */
636     }
637     XBT_DEBUG("parse now:'%s'; parse later:'%s'", name, option);
638
639     if (name[0] == ' ' || name[0] == '\n' || name[0] == '\t')
640       continue;
641     if (!strlen(name))
642       break;
643
644     val = strchr(name, ':');
645     if (!val) {
646       /* don't free(optionlist_cpy) here, 'name' points inside it */
647       xbt_die("Option '%s' badly formatted. Should be of the form 'name:value'",
648               name);
649     }
650     *(val++) = '\0';
651
652     if (strncmp(name, "contexts/", strlen("contexts/")) && strncmp(name, "path", strlen("path")))
653       XBT_INFO("Configuration change: Set '%s' to '%s'", name, val);
654
655     TRY {
656       xbt_cfg_set_as_string(cfg,name,val);
657     } CATCH_ANONYMOUS {
658       free(optionlist_cpy);
659       RETHROW;
660     }
661   }
662   free(optionlist_cpy);
663 }
664
665 /** @brief Set the value of a variable, using the string representation of that value
666  *
667  * @param cfg config set to modify
668  * @param key name of the variable to modify
669  * @param value string representation of the value to set
670  *
671  * @return the first char after the parsed value in val
672  */
673
674 void *xbt_cfg_set_as_string(xbt_cfg_t cfg, const char *key, const char *value) {
675   xbt_ex_t e;
676
677   char *ret;
678   volatile xbt_cfgelm_t variable = NULL;
679   int i;
680   double d;
681
682   TRY {
683     variable = xbt_dict_get((xbt_dict_t) cfg, key);
684   }
685   CATCH(e) {
686     if (e.category == not_found_error) {
687       xbt_ex_free(e);
688       THROWF(not_found_error, 0,
689           "No registered variable corresponding to '%s'.", key);
690     }
691     RETHROW;
692   }
693
694   switch (variable->type) {
695   case xbt_cfgelm_string:
696     xbt_cfg_set_string(cfg, key, value);     /* throws */
697     break;
698
699   case xbt_cfgelm_int:
700     i = strtol(value, &ret, 0);
701     if (ret == value) {
702       xbt_die("Value of option %s not valid. Should be an integer", key);
703     }
704
705     xbt_cfg_set_int(cfg, key, i);  /* throws */
706     break;
707
708   case xbt_cfgelm_double:
709     d = strtod(value, &ret);
710     if (ret == value) {
711       xbt_die("Value of option %s not valid. Should be a double", key);
712     }
713
714     xbt_cfg_set_double(cfg, key, d);       /* throws */
715     break;
716
717   case xbt_cfgelm_boolean:
718     xbt_cfg_set_boolean(cfg, key, value);  /* throws */
719     ret = (char *)value + strlen(value);
720     break;
721
722   default:
723     THROWF(unknown_error, 0, "Type of config element %s is not valid.", key);
724     break;
725   }
726
727   return ret;
728 }
729
730 /** @brief Set an integer value to \a name within \a cfg if it wasn't changed yet
731  *
732  * This is useful to change the default value of a variable while allowing
733  * users to override it with command line arguments
734  */
735 void xbt_cfg_setdefault_int(xbt_cfg_t cfg, const char *name, int val)
736 {
737   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_int);
738
739   if (variable->isdefault){
740     xbt_cfg_set_int(cfg, name, val);
741     variable->isdefault = 1;
742   }
743    else
744     XBT_DEBUG
745         ("Do not override configuration variable '%s' with value '%d' because it was already set.",
746          name, val);
747 }
748
749 /** @brief Set an integer value to \a name within \a cfg if it wasn't changed yet
750  *
751  * This is useful to change the default value of a variable while allowing
752  * users to override it with command line arguments
753  */
754 void xbt_cfg_setdefault_double(xbt_cfg_t cfg, const char *name, double val)
755 {
756   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_double);
757
758   if (variable->isdefault) {
759     xbt_cfg_set_double(cfg, name, val);
760     variable->isdefault = 1;
761   }
762   else
763     XBT_DEBUG
764         ("Do not override configuration variable '%s' with value '%f' because it was already set.",
765          name, val);
766 }
767
768 /** @brief Set a string value to \a name within \a cfg if it wasn't changed yet
769  *
770  * This is useful to change the default value of a variable while allowing
771  * users to override it with command line arguments
772  */
773 void xbt_cfg_setdefault_string(xbt_cfg_t cfg, const char *name,
774                                const char *val)
775 {
776   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_string);
777
778   if (variable->isdefault){
779     xbt_cfg_set_string(cfg, name, val);
780     variable->isdefault = 1;
781   }
782   else
783     XBT_DEBUG
784         ("Do not override configuration variable '%s' with value '%s' because it was already set.",
785          name, val);
786 }
787
788
789 /** @brief Set an boolean value to \a name within \a cfg if it wasn't changed yet
790  *
791  * This is useful to change the default value of a variable while allowing
792  * users to override it with command line arguments
793  */
794 void xbt_cfg_setdefault_boolean(xbt_cfg_t cfg, const char *name, const char *val)
795 {
796   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_boolean);
797
798   if (variable->isdefault){
799     xbt_cfg_set_boolean(cfg, name, val);
800     variable->isdefault = 1;
801   }
802    else
803     XBT_DEBUG
804         ("Do not override configuration variable '%s' with value '%s' because it was already set.",
805          name, val);
806 }
807
808 /** @brief Set or add an integer value to \a name within \a cfg
809  *
810  * @param cfg the config set
811  * @param name the name of the variable
812  * @param val the value of the variable
813  */
814 void xbt_cfg_set_int(xbt_cfg_t cfg, const char *name, int val)
815 {
816   xbt_cfgelm_t variable;
817
818   XBT_VERB("Configuration setting: %s=%d", name, val);
819   variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_int);
820
821   if (variable->max == 1) {
822     if (variable->cb_rm && !xbt_dynar_is_empty(variable->content))
823       variable->cb_rm(name, 0);
824
825     xbt_dynar_set(variable->content, 0, &val);
826   } else {
827     if (variable->max
828         && xbt_dynar_length(variable->content) ==
829         (unsigned long) variable->max)
830       THROWF(mismatch_error, 0,
831              "Cannot add value %d to the config element %s since it's already full (size=%d)",
832              val, name, variable->max);
833
834     xbt_dynar_push(variable->content, &val);
835   }
836
837   if (variable->cb_set)
838     variable->cb_set(name, xbt_dynar_length(variable->content) - 1);
839   variable->isdefault = 0;
840 }
841
842 /** @brief Set or add a double value to \a name within \a cfg
843  *
844  * @param cfg the config set
845  * @param name the name of the variable
846  * @param val the doule to set
847  */
848
849 void xbt_cfg_set_double(xbt_cfg_t cfg, const char *name, double val)
850 {
851   xbt_cfgelm_t variable;
852
853   XBT_VERB("Configuration setting: %s=%f", name, val);
854   variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_double);
855
856   if (variable->max == 1) {
857     if (variable->cb_rm && !xbt_dynar_is_empty(variable->content))
858       variable->cb_rm(name, 0);
859
860     xbt_dynar_set(variable->content, 0, &val);
861   } else {
862     if (variable->max
863         && xbt_dynar_length(variable->content) == variable->max)
864       THROWF(mismatch_error, 0,
865              "Cannot add value %f to the config element %s since it's already full (size=%d)",
866              val, name, variable->max);
867
868     xbt_dynar_push(variable->content, &val);
869   }
870
871   if (variable->cb_set)
872     variable->cb_set(name, xbt_dynar_length(variable->content) - 1);
873   variable->isdefault = 0;
874 }
875
876 /** @brief Set or add a string value to \a name within \a cfg
877  *
878  * @param cfg the config set
879  * @param name the name of the variable
880  * @param val the value to be added
881  *
882  */
883
884 void xbt_cfg_set_string(xbt_cfg_t cfg, const char *name, const char *val)
885 {
886   xbt_cfgelm_t variable;
887   char *newval = xbt_strdup(val);
888
889   XBT_VERB("Configuration setting: %s=%s", name, val);
890   variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_string);
891   XBT_DEBUG("Variable: %d to %d %s (=%d) @%p",
892          variable->min, variable->max,
893             xbt_cfgelm_type_name[variable->type], (int)variable->type, variable);
894
895   if (variable->max == 1) {
896     if (!xbt_dynar_is_empty(variable->content)) {
897       if (variable->cb_rm)
898         variable->cb_rm(name, 0);
899       else if (variable->type == xbt_cfgelm_string) {
900         char *sval = xbt_dynar_get_as(variable->content, 0, char *);
901         free(sval);
902       }
903     }
904
905     xbt_dynar_set(variable->content, 0, &newval);
906   } else {
907     if (variable->max
908         && xbt_dynar_length(variable->content) == variable->max)
909       THROWF(mismatch_error, 0,
910              "Cannot add value %s to the config element %s since it's already full (size=%d)",
911              name, val, variable->max);
912
913     xbt_dynar_push(variable->content, &newval);
914   }
915
916   if (variable->cb_set)
917     variable->cb_set(name, xbt_dynar_length(variable->content) - 1);
918   variable->isdefault = 0;
919 }
920
921 /** @brief Set or add a boolean value to \a name within \a cfg
922  *
923  * @param cfg the config set
924  * @param name the name of the variable
925  * @param val the value of the variable
926  */
927 void xbt_cfg_set_boolean(xbt_cfg_t cfg, const char *name, const char *val)
928 {
929   xbt_cfgelm_t variable;
930   int i, bval;
931
932   XBT_VERB("Configuration setting: %s=%s", name, val);
933   variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_boolean);
934
935   for (i = 0; xbt_cfgelm_boolean_values[i].true_val != NULL; i++) {
936         if (strcmp(val, xbt_cfgelm_boolean_values[i].true_val) == 0){
937           bval = 1;
938           break;
939         }
940         if (strcmp(val, xbt_cfgelm_boolean_values[i].false_val) == 0){
941           bval = 0;
942           break;
943         }
944   }
945   if (xbt_cfgelm_boolean_values[i].true_val == NULL) {
946     xbt_die("Value of option '%s' not valid. Should be a boolean (yes,no,on,off,true,false,0,1)", val);
947   }
948
949   if (variable->max == 1) {
950     if (variable->cb_rm && !xbt_dynar_is_empty(variable->content))
951       variable->cb_rm(name, 0);
952
953     xbt_dynar_set(variable->content, 0, &bval);
954   } else {
955     if (variable->max
956         && xbt_dynar_length(variable->content) ==
957         (unsigned long) variable->max)
958       THROWF(mismatch_error, 0,
959              "Cannot add value %s to the config element %s since it's already full (size=%d)",
960              val, name, variable->max);
961
962     xbt_dynar_push(variable->content, &bval);
963   }
964
965   if (variable->cb_set)
966     variable->cb_set(name, xbt_dynar_length(variable->content) - 1);
967   variable->isdefault = 0;
968 }
969
970 /* ---- [ Removing ] ---- */
971
972 /** @brief Remove the provided \e val integer value from a variable
973  *
974  * @param cfg the config set
975  * @param name the name of the variable
976  * @param val the value to be removed
977  */
978 void xbt_cfg_rm_int(xbt_cfg_t cfg, const char *name, int val)
979 {
980
981   xbt_cfgelm_t variable;
982   unsigned int cpt;
983   int seen;
984
985   variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_int);
986
987   if (xbt_dynar_length(variable->content) == variable->min)
988     THROWF(mismatch_error, 0,
989            "Cannot remove value %d from the config element %s since it's already at its minimal size (=%d)",
990            val, name, variable->min);
991
992   xbt_dynar_foreach(variable->content, cpt, seen) {
993     if (seen == val) {
994       if (variable->cb_rm)
995         variable->cb_rm(name, cpt);
996       xbt_dynar_cursor_rm(variable->content, &cpt);
997       return;
998     }
999   }
1000
1001   THROWF(not_found_error, 0,
1002          "Can't remove the value %d of config element %s: value not found.",
1003          val, name);
1004 }
1005
1006 /** @brief Remove the provided \e val double value from a variable
1007  *
1008  * @param cfg the config set
1009  * @param name the name of the variable
1010  * @param val the value to be removed
1011  */
1012
1013 void xbt_cfg_rm_double(xbt_cfg_t cfg, const char *name, double val)
1014 {
1015   xbt_cfgelm_t variable;
1016   unsigned int cpt;
1017   double seen;
1018
1019   variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_double);
1020
1021   if (xbt_dynar_length(variable->content) == variable->min)
1022     THROWF(mismatch_error, 0,
1023            "Cannot remove value %f from the config element %s since it's already at its minimal size (=%d)",
1024            val, name, variable->min);
1025
1026   xbt_dynar_foreach(variable->content, cpt, seen) {
1027     if (seen == val) {
1028       xbt_dynar_cursor_rm(variable->content, &cpt);
1029       if (variable->cb_rm)
1030         variable->cb_rm(name, cpt);
1031       return;
1032     }
1033   }
1034
1035   THROWF(not_found_error, 0,
1036          "Can't remove the value %f of config element %s: value not found.",
1037          val, name);
1038 }
1039
1040 /** @brief Remove the provided \e val string value from a variable
1041  *
1042  * @param cfg the config set
1043  * @param name the name of the variable
1044  * @param val the value of the string which will be removed
1045  */
1046 void xbt_cfg_rm_string(xbt_cfg_t cfg, const char *name, const char *val)
1047 {
1048   xbt_cfgelm_t variable;
1049   unsigned int cpt;
1050   char *seen;
1051
1052   variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_string);
1053
1054   if (xbt_dynar_length(variable->content) == variable->min)
1055     THROWF(mismatch_error, 0,
1056            "Cannot remove value %s from the config element %s since it's already at its minimal size (=%d)",
1057            name, val, variable->min);
1058
1059   xbt_dynar_foreach(variable->content, cpt, seen) {
1060     if (!strcpy(seen, val)) {
1061       if (variable->cb_rm)
1062         variable->cb_rm(name, cpt);
1063       xbt_dynar_cursor_rm(variable->content, &cpt);
1064       return;
1065     }
1066   }
1067
1068   THROWF(not_found_error, 0,
1069          "Can't remove the value %s of config element %s: value not found.",
1070          val, name);
1071 }
1072
1073 /** @brief Remove the provided \e val boolean value from a variable
1074  *
1075  * @param cfg the config set
1076  * @param name the name of the variable
1077  * @param val the value to be removed
1078  */
1079 void xbt_cfg_rm_boolean(xbt_cfg_t cfg, const char *name, int val)
1080 {
1081
1082   xbt_cfgelm_t variable;
1083   unsigned int cpt;
1084   int seen;
1085
1086   variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_boolean);
1087
1088   if (xbt_dynar_length(variable->content) == variable->min)
1089     THROWF(mismatch_error, 0,
1090            "Cannot remove value %d from the config element %s since it's already at its minimal size (=%d)",
1091            val, name, variable->min);
1092
1093   xbt_dynar_foreach(variable->content, cpt, seen) {
1094     if (seen == val) {
1095       if (variable->cb_rm)
1096         variable->cb_rm(name, cpt);
1097       xbt_dynar_cursor_rm(variable->content, &cpt);
1098       return;
1099     }
1100   }
1101
1102   THROWF(not_found_error, 0,
1103          "Can't remove the value %d of config element %s: value not found.",
1104          val, name);
1105 }
1106
1107 /** @brief Remove the \e pos th value from the provided variable */
1108
1109 void xbt_cfg_rm_at(xbt_cfg_t cfg, const char *name, int pos)
1110 {
1111
1112   xbt_cfgelm_t variable;
1113
1114   variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_any);
1115
1116   if (xbt_dynar_length(variable->content) == variable->min)
1117     THROWF(mismatch_error, 0,
1118            "Cannot remove %dth value from the config element %s since it's already at its minimal size (=%d)",
1119            pos, name, variable->min);
1120
1121   if (variable->cb_rm)
1122     variable->cb_rm(name, pos);
1123   xbt_dynar_remove_at(variable->content, pos, NULL);
1124 }
1125
1126 /** @brief Remove all the values from a variable
1127  *
1128  * @param cfg the config set
1129  * @param name the name of the variable
1130  */
1131
1132 void xbt_cfg_empty(xbt_cfg_t cfg, const char *name)
1133 {
1134   xbt_cfgelm_t variable = NULL;
1135   xbt_ex_t e;
1136
1137   TRY {
1138     variable = xbt_dict_get((xbt_dict_t) cfg, name);
1139   }
1140   CATCH(e) {
1141     if (e.category != not_found_error)
1142       RETHROW;
1143
1144     xbt_ex_free(e);
1145     THROWF(not_found_error, 0,
1146            "Can't empty  '%s' since this config element does not exist",
1147            name);
1148   }
1149
1150   if (variable) {
1151     if (variable->cb_rm) {
1152       unsigned int cpt;
1153       void *ignored;
1154       xbt_dynar_foreach(variable->content, cpt, ignored) {
1155         variable->cb_rm(name, cpt);
1156       }
1157     }
1158     xbt_dynar_reset(variable->content);
1159   }
1160 }
1161 /*
1162  * Say if the value is the default value
1163  */
1164 int xbt_cfg_is_default_value(xbt_cfg_t cfg, const char *name)
1165 {
1166   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_any);
1167   return variable->isdefault;
1168 }
1169
1170 /*----[ Getting ]---------------------------------------------------------*/
1171
1172 /** @brief Retrieve an integer value of a variable (get a warning if not uniq)
1173  *
1174  * @param cfg the config set
1175  * @param name the name of the variable
1176  *
1177  * Returns the first value from the config set under the given name.
1178  * If there is more than one value, it will issue a warning. Consider using
1179  * xbt_cfg_get_dynar() instead.
1180  *
1181  * \warning the returned value is the actual content of the config set
1182  */
1183 int xbt_cfg_get_int(xbt_cfg_t cfg, const char *name)
1184 {
1185   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_int);
1186
1187   if (xbt_dynar_length(variable->content) > 1) {
1188     XBT_WARN
1189         ("You asked for the first value of the config element '%s', but there is %lu values",
1190          name, xbt_dynar_length(variable->content));
1191   }
1192
1193   return xbt_dynar_get_as(variable->content, 0, int);
1194 }
1195
1196 /** @brief Retrieve a double value of a variable (get a warning if not uniq)
1197  *
1198  * @param cfg the config set
1199  * @param name the name of the variable
1200  *
1201  * Returns the first value from the config set under the given name.
1202  * If there is more than one value, it will issue a warning. Consider using
1203  * xbt_cfg_get_dynar() instead.
1204  *
1205  * \warning the returned value is the actual content of the config set
1206  */
1207
1208 double xbt_cfg_get_double(xbt_cfg_t cfg, const char *name)
1209 {
1210   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_double);
1211
1212   if (xbt_dynar_length(variable->content) > 1) {
1213     XBT_WARN
1214         ("You asked for the first value of the config element '%s', but there is %lu values\n",
1215          name, xbt_dynar_length(variable->content));
1216   }
1217
1218   return xbt_dynar_get_as(variable->content, 0, double);
1219 }
1220
1221 /** @brief Retrieve a string value of a variable (get a warning if not uniq)
1222  *
1223  * @param cfg the config set
1224  * @param name the name of the variable
1225  *
1226  * Returns the first value from the config set under the given name.
1227  * If there is more than one value, it will issue a warning. Consider using
1228  * xbt_cfg_get_dynar() instead. Returns NULL if there is no value.
1229  *
1230  * \warning the returned value is the actual content of the config set
1231  */
1232
1233 char *xbt_cfg_get_string(xbt_cfg_t cfg, const char *name)
1234 {
1235   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_string);
1236
1237   if (xbt_dynar_length(variable->content) > 1) {
1238     XBT_WARN
1239         ("You asked for the first value of the config element '%s', but there is %lu values\n",
1240          name, xbt_dynar_length(variable->content));
1241   } else if (xbt_dynar_is_empty(variable->content)) {
1242     return NULL;
1243   }
1244
1245   return xbt_dynar_get_as(variable->content, 0, char *);
1246 }
1247
1248 /** @brief Retrieve a boolean value of a variable (get a warning if not uniq)
1249  *
1250  * @param cfg the config set
1251  * @param name the name of the variable
1252  *
1253  * Returns the first value from the config set under the given name.
1254  * If there is more than one value, it will issue a warning. Consider using
1255  * xbt_cfg_get_dynar() instead.
1256  *
1257  * \warning the returned value is the actual content of the config set
1258  */
1259 int xbt_cfg_get_boolean(xbt_cfg_t cfg, const char *name)
1260 {
1261   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_boolean);
1262
1263   if (xbt_dynar_length(variable->content) > 1) {
1264     XBT_WARN
1265         ("You asked for the first value of the config element '%s', but there is %lu values",
1266          name, xbt_dynar_length(variable->content));
1267   }
1268
1269   return xbt_dynar_get_as(variable->content, 0, int);
1270 }
1271
1272 /** @brief Retrieve the dynar of all the values stored in a variable
1273  *
1274  * @param cfg where to search in
1275  * @param name what to search for
1276  *
1277  * Get the data stored in the config set.
1278  *
1279  * \warning the returned value is the actual content of the config set
1280  */
1281 xbt_dynar_t xbt_cfg_get_dynar(xbt_cfg_t cfg, const char *name)
1282 {
1283   xbt_cfgelm_t variable = NULL;
1284   xbt_ex_t e;
1285
1286   TRY {
1287     variable = xbt_dict_get((xbt_dict_t) cfg, name);
1288   }
1289   CATCH(e) {
1290     if (e.category == not_found_error) {
1291       xbt_ex_free(e);
1292       THROWF(not_found_error, 0,
1293              "No registered variable %s in this config set", name);
1294     }
1295     RETHROW;
1296   }
1297
1298   return variable->content;
1299 }
1300
1301
1302 /** @brief Retrieve one of the integer value of a variable */
1303 int xbt_cfg_get_int_at(xbt_cfg_t cfg, const char *name, int pos)
1304 {
1305
1306   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_int);
1307   return xbt_dynar_get_as(variable->content, pos, int);
1308 }
1309
1310 /** @brief Retrieve one of the double value of a variable */
1311 double xbt_cfg_get_double_at(xbt_cfg_t cfg, const char *name, int pos)
1312 {
1313
1314   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_double);
1315   return xbt_dynar_get_as(variable->content, pos, double);
1316 }
1317
1318
1319 /** @brief Retrieve one of the string value of a variable */
1320 char *xbt_cfg_get_string_at(xbt_cfg_t cfg, const char *name, int pos)
1321 {
1322
1323   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_string);
1324   return xbt_dynar_get_as(variable->content, pos, char *);
1325 }
1326
1327 /** @brief Retrieve one of the boolean value of a variable */
1328 int xbt_cfg_get_boolean_at(xbt_cfg_t cfg, const char *name, int pos)
1329 {
1330
1331   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_boolean);
1332   return xbt_dynar_get_as(variable->content, pos, int);
1333 }
1334
1335
1336 #ifdef SIMGRID_TEST
1337 #include "xbt.h"
1338 #include "xbt/ex.h"
1339
1340 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(xbt_cfg);
1341
1342 XBT_TEST_SUITE("config", "Configuration support");
1343
1344 static xbt_cfg_t make_set()
1345 {
1346   xbt_cfg_t set = NULL;
1347
1348   xbt_log_threshold_set(&_XBT_LOGV(xbt_cfg), xbt_log_priority_critical);
1349   xbt_cfg_register_str(&set, "speed:1_to_2_int");
1350   xbt_cfg_register_str(&set, "peername:1_to_1_string");
1351   xbt_cfg_register_str(&set, "user:1_to_10_string");
1352
1353   return set;
1354 }                               /* end_of_make_set */
1355
1356 XBT_TEST_UNIT("memuse", test_config_memuse, "Alloc and free a config set")
1357 {
1358   xbt_cfg_t set = make_set();
1359   xbt_test_add("Alloc and free a config set");
1360   xbt_cfg_set_parse(set,
1361                     "peername:veloce user:mquinson\nuser:oaumage\tuser:alegrand");
1362   xbt_cfg_free(&set);
1363   xbt_cfg_free(&set);
1364 }
1365
1366 XBT_TEST_UNIT("validation", test_config_validation, "Validation tests")
1367 {
1368   xbt_cfg_t set = set = make_set();
1369   xbt_ex_t e;
1370
1371   xbt_test_add("Having too few elements for speed");
1372   xbt_cfg_set_parse(set,
1373                     "peername:veloce user:mquinson\nuser:oaumage\tuser:alegrand");
1374   TRY {
1375     xbt_cfg_check(set);
1376   }
1377   CATCH(e) {
1378     if (e.category != mismatch_error ||
1379         strncmp(e.msg, "Config elem speed needs",
1380                 strlen("Config elem speed needs")))
1381       xbt_test_fail("Got an exception. msg=%s", e.msg);
1382     xbt_ex_free(e);
1383   }
1384   xbt_cfg_free(&set);
1385   xbt_cfg_free(&set);
1386
1387
1388
1389   xbt_test_add("Having too much values of 'speed'");
1390   set = make_set();
1391   xbt_cfg_set_parse(set, "peername:toto:42 user:alegrand");
1392   TRY {
1393     xbt_cfg_set_parse(set, "speed:42 speed:24 speed:34");
1394   }
1395   CATCH(e) {
1396     if (e.category != mismatch_error ||
1397         strncmp(e.msg, "Cannot add value 34 to the config elem speed",
1398                 strlen("Config elem speed needs")))
1399       xbt_test_fail("Got an exception. msg=%s", e.msg);
1400     xbt_ex_free(e);
1401   }
1402   xbt_cfg_check(set);
1403   xbt_cfg_free(&set);
1404   xbt_cfg_free(&set);
1405
1406 }
1407
1408 XBT_TEST_UNIT("use", test_config_use, "Data retrieving tests")
1409 {
1410
1411   xbt_test_add("Get a single value");
1412   {
1413     /* get_single_value */
1414     int ival;
1415     xbt_cfg_t myset = make_set();
1416
1417     xbt_cfg_set_parse(myset, "peername:toto:42 speed:42");
1418     ival = xbt_cfg_get_int(myset, "speed");
1419     if (ival != 42)
1420       xbt_test_fail("Speed value = %d, I expected 42", ival);
1421     xbt_cfg_free(&myset);
1422   }
1423
1424   xbt_test_add("Get multiple values");
1425   {
1426     /* get_multiple_value */
1427     xbt_dynar_t dyn;
1428     xbt_cfg_t myset = make_set();
1429
1430     xbt_cfg_set_parse(myset,
1431                       "peername:veloce user:foo\nuser:bar\tuser:toto");
1432     xbt_cfg_set_parse(myset, "speed:42");
1433     xbt_cfg_check(myset);
1434     dyn = xbt_cfg_get_dynar(myset, "user");
1435
1436     if (xbt_dynar_length(dyn) != 3)
1437       xbt_test_fail("Dynar length = %lu, I expected 3",
1438                      xbt_dynar_length(dyn));
1439
1440     if (strcmp(xbt_dynar_get_as(dyn, 0, char *), "foo"))
1441        xbt_test_fail("Dynar[0] = %s, I expected foo",
1442                       xbt_dynar_get_as(dyn, 0, char *));
1443
1444     if (strcmp(xbt_dynar_get_as(dyn, 1, char *), "bar"))
1445        xbt_test_fail("Dynar[1] = %s, I expected bar",
1446                       xbt_dynar_get_as(dyn, 1, char *));
1447
1448     if (strcmp(xbt_dynar_get_as(dyn, 2, char *), "toto"))
1449        xbt_test_fail("Dynar[2] = %s, I expected toto",
1450                       xbt_dynar_get_as(dyn, 2, char *));
1451     xbt_cfg_free(&myset);
1452   }
1453
1454   xbt_test_add("Access to a non-existant entry");
1455   {
1456     /* non-existant_entry */
1457     xbt_cfg_t myset = make_set();
1458     xbt_ex_t e;
1459
1460     TRY {
1461       xbt_cfg_set_parse(myset, "color:blue");
1462     }
1463     CATCH(e) {
1464       if (e.category != not_found_error)
1465         xbt_test_exception(e);
1466       xbt_ex_free(e);
1467     }
1468     xbt_cfg_free(&myset);
1469   }
1470 }
1471 #endif                          /* SIMGRID_TEST */