Logo AND Algorithmique Numérique Distribuée

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