Logo AND Algorithmique Numérique Distribuée

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