Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
kill sets! kill!
[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", name);
469   }
470
471   xbt_assert(type == xbt_cfgelm_any || res->type == type,
472               "You tried to access to the config element %s as an %s, but its type is %s.",
473               name,
474               xbt_cfgelm_type_name[type], xbt_cfgelm_type_name[res->type]);
475
476   return res;
477 }
478
479 /** @brief Get the type of this variable in that configuration set
480  *
481  * @param cfg the config set
482  * @param name the name of the element
483  *
484  * @return the type of the given element
485  */
486
487 e_xbt_cfgelm_type_t xbt_cfg_get_type(xbt_cfg_t cfg, const char *name)
488 {
489
490   xbt_cfgelm_t variable = NULL;
491
492   variable = xbt_dict_get_or_null((xbt_dict_t) cfg, name);
493   if (!variable)
494     THROWF(not_found_error, 0,
495            "Can't get the type of '%s' since this variable does not exist",
496            name);
497
498   XBT_DEBUG("type in variable = %d", (int)variable->type);
499
500   return variable->type;
501 }
502
503 /*----[ Setting ]---------------------------------------------------------*/
504 /**  @brief va_args version of xbt_cfg_set
505  *
506  * @param cfg config set to fill
507  * @param name  variable name
508  * @param pa  variable value
509  *
510  * Add some values to the config set.
511  */
512 void xbt_cfg_set_vargs(xbt_cfg_t cfg, const char *name, va_list pa)
513 {
514   char *str;
515   int i;
516   double d;
517   e_xbt_cfgelm_type_t type = xbt_cfgelm_any; /* Set a dummy value to make gcc happy. It cannot get uninitialized */
518
519   xbt_ex_t e;
520
521   TRY {
522     type = xbt_cfg_get_type(cfg, name);
523   }
524   CATCH(e) {
525     if (e.category == not_found_error) {
526       xbt_ex_free(e);
527       THROWF(not_found_error, 0,
528              "Can't set the property '%s' since it's not registered",
529              name);
530     }
531     RETHROW;
532   }
533
534   switch (type) {
535   case xbt_cfgelm_string:
536     str = va_arg(pa, char *);
537     xbt_cfg_set_string(cfg, name, str);
538     break;
539
540   case xbt_cfgelm_int:
541     i = va_arg(pa, int);
542     xbt_cfg_set_int(cfg, name, i);
543     break;
544
545   case xbt_cfgelm_double:
546     d = va_arg(pa, double);
547     xbt_cfg_set_double(cfg, name, d);
548     break;
549
550   case xbt_cfgelm_boolean:
551     str = va_arg(pa, char *);
552     xbt_cfg_set_boolean(cfg, name, str);
553     break;
554
555   default:
556     xbt_die("Config element variable %s not valid (type=%d)", name, (int)type);
557   }
558 }
559
560 /** @brief Add a NULL-terminated list of pairs {(char*)key, value} to the set
561  *
562  * @param cfg config set to fill
563  * @param name variable name
564  * @param ... variable value
565  *
566  */
567 void xbt_cfg_set(xbt_cfg_t cfg, const char *name, ...)
568 {
569   va_list pa;
570
571   va_start(pa, name);
572   xbt_cfg_set_vargs(cfg, name, pa);
573   va_end(pa);
574 }
575
576 /** @brief Add values parsed from a string into a config set
577  *
578  * @param cfg config set to fill
579  * @param options a string containing the content to add to the config set. This
580  * is a '\\t',' ' or '\\n' or ',' separated list of variables. Each individual variable is
581  * like "[name]:[value]" where [name] is the name of an already registred
582  * variable, and [value] conforms to the data type under which this variable was
583  * registred.
584  *
585  * @todo This is a crude manual parser, it should be a proper lexer.
586  */
587
588 void xbt_cfg_set_parse(xbt_cfg_t cfg, const char *options) {
589
590   char *optionlist_cpy;
591   char *option, *name, *val;
592
593   int len;
594
595   XBT_IN();
596   if (!options || !strlen(options)) {   /* nothing to do */
597     return;
598   }
599   optionlist_cpy = xbt_strdup(options);
600
601   XBT_DEBUG("List to parse and set:'%s'", options);
602   option = optionlist_cpy;
603   while (1) {                   /* breaks in the code */
604
605     if (!option)
606       break;
607     name = option;
608     len = strlen(name);
609     XBT_DEBUG("Still to parse and set: '%s'. len=%d; option-name=%ld",
610            name, len, (long) (option - name));
611
612     /* Pass the value */
613     while (option - name <= (len - 1) && *option != ' ' && *option != '\n'
614            && *option != '\t' && *option != ',') {
615       XBT_DEBUG("Take %c.", *option);
616       option++;
617     }
618     if (option - name == len) {
619       XBT_DEBUG("Boundary=EOL");
620       option = NULL;            /* don't do next iteration */
621
622     } else {
623       XBT_DEBUG("Boundary on '%c'. len=%d;option-name=%ld",
624              *option, len, (long) (option - name));
625
626       /* Pass the following blank chars */
627       *(option++) = '\0';
628       while (option - name < (len - 1) &&
629              (*option == ' ' || *option == '\n' || *option == '\t')) {
630         /*      fprintf(stderr,"Ignore a blank char.\n"); */
631         option++;
632       }
633       if (option - name == len - 1)
634         option = NULL;          /* don't do next iteration */
635     }
636     XBT_DEBUG("parse now:'%s'; parse later:'%s'", name, option);
637
638     if (name[0] == ' ' || name[0] == '\n' || name[0] == '\t')
639       continue;
640     if (!strlen(name))
641       break;
642
643     val = strchr(name, ':');
644     if (!val) {
645       /* don't free(optionlist_cpy) here, 'name' points inside it */
646       xbt_die("Option '%s' badly formatted. Should be of the form 'name:value'",
647               name);
648     }
649     *(val++) = '\0';
650
651     if (strncmp(name, "contexts/", strlen("contexts/")) && strncmp(name, "path", strlen("path")))
652       XBT_INFO("Configuration change: Set '%s' to '%s'", name, val);
653
654     TRY {
655       xbt_cfg_set_as_string(cfg,name,val);
656     } CATCH_ANONYMOUS {
657       free(optionlist_cpy);
658       RETHROW;
659     }
660   }
661   free(optionlist_cpy);
662 }
663
664 /** @brief Set the value of a variable, using the string representation of that value
665  *
666  * @param cfg config set to modify
667  * @param key name of the variable to modify
668  * @param value string representation of the value to set
669  *
670  * @return the first char after the parsed value in val
671  */
672
673 void *xbt_cfg_set_as_string(xbt_cfg_t cfg, const char *key, const char *value) {
674   xbt_ex_t e;
675
676   char *ret;
677   volatile xbt_cfgelm_t variable = NULL;
678   int i;
679   double d;
680
681   TRY {
682     variable = xbt_dict_get((xbt_dict_t) cfg, key);
683   }
684   CATCH(e) {
685     if (e.category == not_found_error) {
686       xbt_ex_free(e);
687       THROWF(not_found_error, 0,
688           "No registered variable corresponding to '%s'.", key);
689     }
690     RETHROW;
691   }
692
693   switch (variable->type) {
694   case xbt_cfgelm_string:
695     xbt_cfg_set_string(cfg, key, value);     /* throws */
696     break;
697
698   case xbt_cfgelm_int:
699     i = strtol(value, &ret, 0);
700     if (ret == value) {
701       xbt_die("Value of option %s not valid. Should be an integer", key);
702     }
703
704     xbt_cfg_set_int(cfg, key, i);  /* throws */
705     break;
706
707   case xbt_cfgelm_double:
708     d = strtod(value, &ret);
709     if (ret == value) {
710       xbt_die("Value of option %s not valid. Should be a double", key);
711     }
712
713     xbt_cfg_set_double(cfg, key, d);       /* throws */
714     break;
715
716   case xbt_cfgelm_boolean:
717     xbt_cfg_set_boolean(cfg, key, value);  /* throws */
718     ret = (char *)value + strlen(value);
719     break;
720
721   default:
722     THROWF(unknown_error, 0, "Type of config element %s is not valid.", key);
723     break;
724   }
725
726   return ret;
727 }
728
729 /** @brief Set an integer value to \a name within \a cfg if it wasn't changed yet
730  *
731  * This is useful to change the default value of a variable while allowing
732  * users to override it with command line arguments
733  */
734 void xbt_cfg_setdefault_int(xbt_cfg_t cfg, const char *name, int val)
735 {
736   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_int);
737
738   if (variable->isdefault){
739     xbt_cfg_set_int(cfg, name, val);
740     variable->isdefault = 1;
741   }
742    else
743     XBT_DEBUG
744         ("Do not override configuration variable '%s' with value '%d' because it was already set.",
745          name, val);
746 }
747
748 /** @brief Set an integer value to \a name within \a cfg if it wasn't changed yet
749  *
750  * This is useful to change the default value of a variable while allowing
751  * users to override it with command line arguments
752  */
753 void xbt_cfg_setdefault_double(xbt_cfg_t cfg, const char *name, double val)
754 {
755   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_double);
756
757   if (variable->isdefault) {
758     xbt_cfg_set_double(cfg, name, val);
759     variable->isdefault = 1;
760   }
761   else
762     XBT_DEBUG
763         ("Do not override configuration variable '%s' with value '%f' because it was already set.",
764          name, val);
765 }
766
767 /** @brief Set a string value to \a name within \a cfg if it wasn't changed yet
768  *
769  * This is useful to change the default value of a variable while allowing
770  * users to override it with command line arguments
771  */
772 void xbt_cfg_setdefault_string(xbt_cfg_t cfg, const char *name,
773                                const char *val)
774 {
775   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_string);
776
777   if (variable->isdefault){
778     xbt_cfg_set_string(cfg, name, val);
779     variable->isdefault = 1;
780   }
781   else
782     XBT_DEBUG
783         ("Do not override configuration variable '%s' with value '%s' because it was already set.",
784          name, val);
785 }
786
787
788 /** @brief Set an boolean value to \a name within \a cfg if it wasn't changed yet
789  *
790  * This is useful to change the default value of a variable while allowing
791  * users to override it with command line arguments
792  */
793 void xbt_cfg_setdefault_boolean(xbt_cfg_t cfg, const char *name, const char *val)
794 {
795   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_boolean);
796
797   if (variable->isdefault){
798     xbt_cfg_set_boolean(cfg, name, val);
799     variable->isdefault = 1;
800   }
801    else
802     XBT_DEBUG
803         ("Do not override configuration variable '%s' with value '%s' because it was already set.",
804          name, val);
805 }
806
807 /** @brief Set or add an integer value to \a name within \a cfg
808  *
809  * @param cfg the config set
810  * @param name the name of the variable
811  * @param val the value of the variable
812  */
813 void xbt_cfg_set_int(xbt_cfg_t cfg, const char *name, int val)
814 {
815   xbt_cfgelm_t variable;
816
817   XBT_VERB("Configuration setting: %s=%d", name, val);
818   variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_int);
819
820   if (variable->max == 1) {
821     if (variable->cb_rm && !xbt_dynar_is_empty(variable->content))
822       variable->cb_rm(name, 0);
823
824     xbt_dynar_set(variable->content, 0, &val);
825   } else {
826     if (variable->max
827         && xbt_dynar_length(variable->content) ==
828         (unsigned long) variable->max)
829       THROWF(mismatch_error, 0,
830              "Cannot add value %d to the config element %s since it's already full (size=%d)",
831              val, name, variable->max);
832
833     xbt_dynar_push(variable->content, &val);
834   }
835
836   if (variable->cb_set)
837     variable->cb_set(name, xbt_dynar_length(variable->content) - 1);
838   variable->isdefault = 0;
839 }
840
841 /** @brief Set or add a double value to \a name within \a cfg
842  *
843  * @param cfg the config set
844  * @param name the name of the variable
845  * @param val the doule to set
846  */
847
848 void xbt_cfg_set_double(xbt_cfg_t cfg, const char *name, double val)
849 {
850   xbt_cfgelm_t variable;
851
852   XBT_VERB("Configuration setting: %s=%f", name, val);
853   variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_double);
854
855   if (variable->max == 1) {
856     if (variable->cb_rm && !xbt_dynar_is_empty(variable->content))
857       variable->cb_rm(name, 0);
858
859     xbt_dynar_set(variable->content, 0, &val);
860   } else {
861     if (variable->max
862         && xbt_dynar_length(variable->content) == variable->max)
863       THROWF(mismatch_error, 0,
864              "Cannot add value %f to the config element %s since it's already full (size=%d)",
865              val, name, variable->max);
866
867     xbt_dynar_push(variable->content, &val);
868   }
869
870   if (variable->cb_set)
871     variable->cb_set(name, xbt_dynar_length(variable->content) - 1);
872   variable->isdefault = 0;
873 }
874
875 /** @brief Set or add a string value to \a name within \a cfg
876  *
877  * @param cfg the config set
878  * @param name the name of the variable
879  * @param val the value to be added
880  *
881  */
882
883 void xbt_cfg_set_string(xbt_cfg_t cfg, const char *name, const char *val)
884 {
885   xbt_cfgelm_t variable;
886   char *newval = xbt_strdup(val);
887
888   XBT_VERB("Configuration setting: %s=%s", name, val);
889   variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_string);
890   XBT_DEBUG("Variable: %d to %d %s (=%d) @%p",
891          variable->min, variable->max,
892             xbt_cfgelm_type_name[variable->type], (int)variable->type, variable);
893
894   if (variable->max == 1) {
895     if (!xbt_dynar_is_empty(variable->content)) {
896       if (variable->cb_rm)
897         variable->cb_rm(name, 0);
898       else if (variable->type == xbt_cfgelm_string) {
899         char *sval = xbt_dynar_get_as(variable->content, 0, char *);
900         free(sval);
901       }
902     }
903
904     xbt_dynar_set(variable->content, 0, &newval);
905   } else {
906     if (variable->max
907         && xbt_dynar_length(variable->content) == variable->max)
908       THROWF(mismatch_error, 0,
909              "Cannot add value %s to the config element %s since it's already full (size=%d)",
910              name, val, variable->max);
911
912     xbt_dynar_push(variable->content, &newval);
913   }
914
915   if (variable->cb_set)
916     variable->cb_set(name, xbt_dynar_length(variable->content) - 1);
917   variable->isdefault = 0;
918 }
919
920 /** @brief Set or add a boolean value to \a name within \a cfg
921  *
922  * @param cfg the config set
923  * @param name the name of the variable
924  * @param val the value of the variable
925  */
926 void xbt_cfg_set_boolean(xbt_cfg_t cfg, const char *name, const char *val)
927 {
928   xbt_cfgelm_t variable;
929   int i, bval;
930
931   XBT_VERB("Configuration setting: %s=%s", name, val);
932   variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_boolean);
933
934   for (i = 0; xbt_cfgelm_boolean_values[i].true_val != NULL; i++) {
935         if (strcmp(val, xbt_cfgelm_boolean_values[i].true_val) == 0){
936           bval = 1;
937           break;
938         }
939         if (strcmp(val, xbt_cfgelm_boolean_values[i].false_val) == 0){
940           bval = 0;
941           break;
942         }
943   }
944   if (xbt_cfgelm_boolean_values[i].true_val == NULL) {
945     xbt_die("Value of option '%s' not valid. Should be a boolean (yes,no,on,off,true,false,0,1)", val);
946   }
947
948   if (variable->max == 1) {
949     if (variable->cb_rm && !xbt_dynar_is_empty(variable->content))
950       variable->cb_rm(name, 0);
951
952     xbt_dynar_set(variable->content, 0, &bval);
953   } else {
954     if (variable->max
955         && xbt_dynar_length(variable->content) ==
956         (unsigned long) variable->max)
957       THROWF(mismatch_error, 0,
958              "Cannot add value %s to the config element %s since it's already full (size=%d)",
959              val, name, variable->max);
960
961     xbt_dynar_push(variable->content, &bval);
962   }
963
964   if (variable->cb_set)
965     variable->cb_set(name, xbt_dynar_length(variable->content) - 1);
966   variable->isdefault = 0;
967 }
968
969 /* ---- [ Removing ] ---- */
970
971 /** @brief Remove the provided \e val integer value from a variable
972  *
973  * @param cfg the config set
974  * @param name the name of the variable
975  * @param val the value to be removed
976  */
977 void xbt_cfg_rm_int(xbt_cfg_t cfg, const char *name, int val)
978 {
979
980   xbt_cfgelm_t variable;
981   unsigned int cpt;
982   int seen;
983
984   variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_int);
985
986   if (xbt_dynar_length(variable->content) == variable->min)
987     THROWF(mismatch_error, 0,
988            "Cannot remove value %d from the config element %s since it's already at its minimal size (=%d)",
989            val, name, variable->min);
990
991   xbt_dynar_foreach(variable->content, cpt, seen) {
992     if (seen == val) {
993       if (variable->cb_rm)
994         variable->cb_rm(name, cpt);
995       xbt_dynar_cursor_rm(variable->content, &cpt);
996       return;
997     }
998   }
999
1000   THROWF(not_found_error, 0,
1001          "Can't remove the value %d of config element %s: value not found.",
1002          val, name);
1003 }
1004
1005 /** @brief Remove the provided \e val double value from a variable
1006  *
1007  * @param cfg the config set
1008  * @param name the name of the variable
1009  * @param val the value to be removed
1010  */
1011
1012 void xbt_cfg_rm_double(xbt_cfg_t cfg, const char *name, double val)
1013 {
1014   xbt_cfgelm_t variable;
1015   unsigned int cpt;
1016   double seen;
1017
1018   variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_double);
1019
1020   if (xbt_dynar_length(variable->content) == variable->min)
1021     THROWF(mismatch_error, 0,
1022            "Cannot remove value %f from the config element %s since it's already at its minimal size (=%d)",
1023            val, name, variable->min);
1024
1025   xbt_dynar_foreach(variable->content, cpt, seen) {
1026     if (seen == val) {
1027       xbt_dynar_cursor_rm(variable->content, &cpt);
1028       if (variable->cb_rm)
1029         variable->cb_rm(name, cpt);
1030       return;
1031     }
1032   }
1033
1034   THROWF(not_found_error, 0,
1035          "Can't remove the value %f of config element %s: value not found.",
1036          val, name);
1037 }
1038
1039 /** @brief Remove the provided \e val string value from a variable
1040  *
1041  * @param cfg the config set
1042  * @param name the name of the variable
1043  * @param val the value of the string which will be removed
1044  */
1045 void xbt_cfg_rm_string(xbt_cfg_t cfg, const char *name, const char *val)
1046 {
1047   xbt_cfgelm_t variable;
1048   unsigned int cpt;
1049   char *seen;
1050
1051   variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_string);
1052
1053   if (xbt_dynar_length(variable->content) == variable->min)
1054     THROWF(mismatch_error, 0,
1055            "Cannot remove value %s from the config element %s since it's already at its minimal size (=%d)",
1056            name, val, variable->min);
1057
1058   xbt_dynar_foreach(variable->content, cpt, seen) {
1059     if (!strcpy(seen, val)) {
1060       if (variable->cb_rm)
1061         variable->cb_rm(name, cpt);
1062       xbt_dynar_cursor_rm(variable->content, &cpt);
1063       return;
1064     }
1065   }
1066
1067   THROWF(not_found_error, 0,
1068          "Can't remove the value %s of config element %s: value not found.",
1069          val, name);
1070 }
1071
1072 /** @brief Remove the provided \e val boolean value from a variable
1073  *
1074  * @param cfg the config set
1075  * @param name the name of the variable
1076  * @param val the value to be removed
1077  */
1078 void xbt_cfg_rm_boolean(xbt_cfg_t cfg, const char *name, int val)
1079 {
1080
1081   xbt_cfgelm_t variable;
1082   unsigned int cpt;
1083   int seen;
1084
1085   variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_boolean);
1086
1087   if (xbt_dynar_length(variable->content) == variable->min)
1088     THROWF(mismatch_error, 0,
1089            "Cannot remove value %d from the config element %s since it's already at its minimal size (=%d)",
1090            val, name, variable->min);
1091
1092   xbt_dynar_foreach(variable->content, cpt, seen) {
1093     if (seen == val) {
1094       if (variable->cb_rm)
1095         variable->cb_rm(name, cpt);
1096       xbt_dynar_cursor_rm(variable->content, &cpt);
1097       return;
1098     }
1099   }
1100
1101   THROWF(not_found_error, 0,
1102          "Can't remove the value %d of config element %s: value not found.",
1103          val, name);
1104 }
1105
1106 /** @brief Remove the \e pos th value from the provided variable */
1107
1108 void xbt_cfg_rm_at(xbt_cfg_t cfg, const char *name, int pos)
1109 {
1110
1111   xbt_cfgelm_t variable;
1112
1113   variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_any);
1114
1115   if (xbt_dynar_length(variable->content) == variable->min)
1116     THROWF(mismatch_error, 0,
1117            "Cannot remove %dth value from the config element %s since it's already at its minimal size (=%d)",
1118            pos, name, variable->min);
1119
1120   if (variable->cb_rm)
1121     variable->cb_rm(name, pos);
1122   xbt_dynar_remove_at(variable->content, pos, NULL);
1123 }
1124
1125 /** @brief Remove all the values from a variable
1126  *
1127  * @param cfg the config set
1128  * @param name the name of the variable
1129  */
1130
1131 void xbt_cfg_empty(xbt_cfg_t cfg, const char *name)
1132 {
1133   xbt_cfgelm_t variable = NULL;
1134   xbt_ex_t e;
1135
1136   TRY {
1137     variable = xbt_dict_get((xbt_dict_t) cfg, name);
1138   }
1139   CATCH(e) {
1140     if (e.category != not_found_error)
1141       RETHROW;
1142
1143     xbt_ex_free(e);
1144     THROWF(not_found_error, 0,
1145            "Can't empty  '%s' since this config element does not exist",
1146            name);
1147   }
1148
1149   if (variable) {
1150     if (variable->cb_rm) {
1151       unsigned int cpt;
1152       void *ignored;
1153       xbt_dynar_foreach(variable->content, cpt, ignored) {
1154         variable->cb_rm(name, cpt);
1155       }
1156     }
1157     xbt_dynar_reset(variable->content);
1158   }
1159 }
1160 /*
1161  * Say if the value is the default value
1162  */
1163 int xbt_cfg_is_default_value(xbt_cfg_t cfg, const char *name)
1164 {
1165   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_any);
1166   return variable->isdefault;
1167 }
1168
1169 /*----[ Getting ]---------------------------------------------------------*/
1170
1171 /** @brief Retrieve an integer value of a variable (get a warning if not uniq)
1172  *
1173  * @param cfg the config set
1174  * @param name the name of the variable
1175  *
1176  * Returns the first value from the config set under the given name.
1177  * If there is more than one value, it will issue a warning. Consider using
1178  * xbt_cfg_get_dynar() instead.
1179  *
1180  * \warning the returned value is the actual content of the config set
1181  */
1182 int xbt_cfg_get_int(xbt_cfg_t cfg, const char *name)
1183 {
1184   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_int);
1185
1186   if (xbt_dynar_length(variable->content) > 1) {
1187     XBT_WARN
1188         ("You asked for the first value of the config element '%s', but there is %lu values",
1189          name, xbt_dynar_length(variable->content));
1190   }
1191
1192   return xbt_dynar_get_as(variable->content, 0, int);
1193 }
1194
1195 /** @brief Retrieve a double value of a variable (get a warning if not uniq)
1196  *
1197  * @param cfg the config set
1198  * @param name the name of the variable
1199  *
1200  * Returns the first value from the config set under the given name.
1201  * If there is more than one value, it will issue a warning. Consider using
1202  * xbt_cfg_get_dynar() instead.
1203  *
1204  * \warning the returned value is the actual content of the config set
1205  */
1206
1207 double xbt_cfg_get_double(xbt_cfg_t cfg, const char *name)
1208 {
1209   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_double);
1210
1211   if (xbt_dynar_length(variable->content) > 1) {
1212     XBT_WARN
1213         ("You asked for the first value of the config element '%s', but there is %lu values\n",
1214          name, xbt_dynar_length(variable->content));
1215   }
1216
1217   return xbt_dynar_get_as(variable->content, 0, double);
1218 }
1219
1220 /** @brief Retrieve a string value of a variable (get a warning if not uniq)
1221  *
1222  * @param cfg the config set
1223  * @param name the name of the variable
1224  *
1225  * Returns the first value from the config set under the given name.
1226  * If there is more than one value, it will issue a warning. Consider using
1227  * xbt_cfg_get_dynar() instead. Returns NULL if there is no value.
1228  *
1229  * \warning the returned value is the actual content of the config set
1230  */
1231
1232 char *xbt_cfg_get_string(xbt_cfg_t cfg, const char *name)
1233 {
1234   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_string);
1235
1236   if (xbt_dynar_length(variable->content) > 1) {
1237     XBT_WARN
1238         ("You asked for the first value of the config element '%s', but there is %lu values\n",
1239          name, xbt_dynar_length(variable->content));
1240   } else if (xbt_dynar_is_empty(variable->content)) {
1241     return NULL;
1242   }
1243
1244   return xbt_dynar_get_as(variable->content, 0, char *);
1245 }
1246
1247 /** @brief Retrieve a boolean value of a variable (get a warning if not uniq)
1248  *
1249  * @param cfg the config set
1250  * @param name the name of the variable
1251  *
1252  * Returns the first value from the config set under the given name.
1253  * If there is more than one value, it will issue a warning. Consider using
1254  * xbt_cfg_get_dynar() instead.
1255  *
1256  * \warning the returned value is the actual content of the config set
1257  */
1258 int xbt_cfg_get_boolean(xbt_cfg_t cfg, const char *name)
1259 {
1260   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_boolean);
1261
1262   if (xbt_dynar_length(variable->content) > 1) {
1263     XBT_WARN
1264         ("You asked for the first value of the config element '%s', but there is %lu values",
1265          name, xbt_dynar_length(variable->content));
1266   }
1267
1268   return xbt_dynar_get_as(variable->content, 0, int);
1269 }
1270
1271 /** @brief Retrieve the dynar of all the values stored in a variable
1272  *
1273  * @param cfg where to search in
1274  * @param name what to search for
1275  *
1276  * Get the data stored in the config set.
1277  *
1278  * \warning the returned value is the actual content of the config set
1279  */
1280 xbt_dynar_t xbt_cfg_get_dynar(xbt_cfg_t cfg, const char *name)
1281 {
1282   xbt_cfgelm_t variable = NULL;
1283   xbt_ex_t e;
1284
1285   TRY {
1286     variable = xbt_dict_get((xbt_dict_t) cfg, name);
1287   }
1288   CATCH(e) {
1289     if (e.category == not_found_error) {
1290       xbt_ex_free(e);
1291       THROWF(not_found_error, 0,
1292              "No registered variable %s in this config set", name);
1293     }
1294     RETHROW;
1295   }
1296
1297   return variable->content;
1298 }
1299
1300
1301 /** @brief Retrieve one of the integer value of a variable */
1302 int xbt_cfg_get_int_at(xbt_cfg_t cfg, const char *name, int pos)
1303 {
1304
1305   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_int);
1306   return xbt_dynar_get_as(variable->content, pos, int);
1307 }
1308
1309 /** @brief Retrieve one of the double value of a variable */
1310 double xbt_cfg_get_double_at(xbt_cfg_t cfg, const char *name, int pos)
1311 {
1312
1313   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_double);
1314   return xbt_dynar_get_as(variable->content, pos, double);
1315 }
1316
1317
1318 /** @brief Retrieve one of the string value of a variable */
1319 char *xbt_cfg_get_string_at(xbt_cfg_t cfg, const char *name, int pos)
1320 {
1321
1322   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_string);
1323   return xbt_dynar_get_as(variable->content, pos, char *);
1324 }
1325
1326 /** @brief Retrieve one of the boolean value of a variable */
1327 int xbt_cfg_get_boolean_at(xbt_cfg_t cfg, const char *name, int pos)
1328 {
1329
1330   xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_boolean);
1331   return xbt_dynar_get_as(variable->content, pos, int);
1332 }
1333
1334
1335 #ifdef SIMGRID_TEST
1336 #include "xbt.h"
1337 #include "xbt/ex.h"
1338
1339 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(xbt_cfg);
1340
1341 XBT_TEST_SUITE("config", "Configuration support");
1342
1343 static xbt_cfg_t make_set()
1344 {
1345   xbt_cfg_t set = NULL;
1346
1347   xbt_log_threshold_set(&_XBT_LOGV(xbt_cfg), xbt_log_priority_critical);
1348   xbt_cfg_register_str(&set, "speed:1_to_2_int");
1349   xbt_cfg_register_str(&set, "peername:1_to_1_string");
1350   xbt_cfg_register_str(&set, "user:1_to_10_string");
1351
1352   return set;
1353 }                               /* end_of_make_set */
1354
1355 XBT_TEST_UNIT("memuse", test_config_memuse, "Alloc and free a config set")
1356 {
1357   xbt_cfg_t set = make_set();
1358   xbt_test_add("Alloc and free a config set");
1359   xbt_cfg_set_parse(set,
1360                     "peername:veloce user:mquinson\nuser:oaumage\tuser:alegrand");
1361   xbt_cfg_free(&set);
1362   xbt_cfg_free(&set);
1363 }
1364
1365 XBT_TEST_UNIT("validation", test_config_validation, "Validation tests")
1366 {
1367   xbt_cfg_t set = set = make_set();
1368   xbt_ex_t e;
1369
1370   xbt_test_add("Having too few elements for speed");
1371   xbt_cfg_set_parse(set,
1372                     "peername:veloce user:mquinson\nuser:oaumage\tuser:alegrand");
1373   TRY {
1374     xbt_cfg_check(set);
1375   }
1376   CATCH(e) {
1377     if (e.category != mismatch_error ||
1378         strncmp(e.msg, "Config elem speed needs",
1379                 strlen("Config elem speed needs")))
1380       xbt_test_fail("Got an exception. msg=%s", e.msg);
1381     xbt_ex_free(e);
1382   }
1383   xbt_cfg_free(&set);
1384   xbt_cfg_free(&set);
1385
1386
1387
1388   xbt_test_add("Having too much values of 'speed'");
1389   set = make_set();
1390   xbt_cfg_set_parse(set, "peername:toto:42 user:alegrand");
1391   TRY {
1392     xbt_cfg_set_parse(set, "speed:42 speed:24 speed:34");
1393   }
1394   CATCH(e) {
1395     if (e.category != mismatch_error ||
1396         strncmp(e.msg, "Cannot add value 34 to the config elem speed",
1397                 strlen("Config elem speed needs")))
1398       xbt_test_fail("Got an exception. msg=%s", e.msg);
1399     xbt_ex_free(e);
1400   }
1401   xbt_cfg_check(set);
1402   xbt_cfg_free(&set);
1403   xbt_cfg_free(&set);
1404
1405 }
1406
1407 XBT_TEST_UNIT("use", test_config_use, "Data retrieving tests")
1408 {
1409
1410   xbt_test_add("Get a single value");
1411   {
1412     /* get_single_value */
1413     int ival;
1414     xbt_cfg_t myset = make_set();
1415
1416     xbt_cfg_set_parse(myset, "peername:toto:42 speed:42");
1417     ival = xbt_cfg_get_int(myset, "speed");
1418     if (ival != 42)
1419       xbt_test_fail("Speed value = %d, I expected 42", ival);
1420     xbt_cfg_free(&myset);
1421   }
1422
1423   xbt_test_add("Get multiple values");
1424   {
1425     /* get_multiple_value */
1426     xbt_dynar_t dyn;
1427     xbt_cfg_t myset = make_set();
1428
1429     xbt_cfg_set_parse(myset,
1430                       "peername:veloce user:foo\nuser:bar\tuser:toto");
1431     xbt_cfg_set_parse(myset, "speed:42");
1432     xbt_cfg_check(myset);
1433     dyn = xbt_cfg_get_dynar(myset, "user");
1434
1435     if (xbt_dynar_length(dyn) != 3)
1436       xbt_test_fail("Dynar length = %lu, I expected 3",
1437                      xbt_dynar_length(dyn));
1438
1439     if (strcmp(xbt_dynar_get_as(dyn, 0, char *), "foo"))
1440        xbt_test_fail("Dynar[0] = %s, I expected foo",
1441                       xbt_dynar_get_as(dyn, 0, char *));
1442
1443     if (strcmp(xbt_dynar_get_as(dyn, 1, char *), "bar"))
1444        xbt_test_fail("Dynar[1] = %s, I expected bar",
1445                       xbt_dynar_get_as(dyn, 1, char *));
1446
1447     if (strcmp(xbt_dynar_get_as(dyn, 2, char *), "toto"))
1448        xbt_test_fail("Dynar[2] = %s, I expected toto",
1449                       xbt_dynar_get_as(dyn, 2, char *));
1450     xbt_cfg_free(&myset);
1451   }
1452
1453   xbt_test_add("Access to a non-existant entry");
1454   {
1455     /* non-existant_entry */
1456     xbt_cfg_t myset = make_set();
1457     xbt_ex_t e;
1458
1459     TRY {
1460       xbt_cfg_set_parse(myset, "color:blue");
1461     }
1462     CATCH(e) {
1463       if (e.category != not_found_error)
1464         xbt_test_exception(e);
1465       xbt_ex_free(e);
1466     }
1467     xbt_cfg_free(&myset);
1468   }
1469 }
1470 #endif                          /* SIMGRID_TEST */