3 /* config - Dictionnary where the type of each variable is provided. */
5 /* This is useful to build named structs, like option or property sets. */
7 /* Copyright (c) 2001,2002,2003,2004 Martin Quinson. All rights reserved. */
9 /* This program is free software; you can redistribute it and/or modify it
10 * under the terms of the license (GNU LGPL) which comes with this package. */
14 #include "xbt/sysdep.h"
17 #include "xbt/dynar.h"
21 #include "xbt/config.h" /* prototypes of this module */
23 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_cfg, xbt, "configuration support");
25 /* xbt_cfgelm_t: the typedef corresponding to a config variable.
27 Both data and DTD are mixed, but fixing it now would prevent me to ever
31 /* Allowed type of the variable */
32 e_xbt_cfgelm_type_t type;
40 (cannot be an union because type peer uses both str and i) */
42 } s_xbt_cfgelm_t, *xbt_cfgelm_t;
44 static const char *xbt_cfgelm_type_name[xbt_cfgelm_type_count] =
45 { "int", "double", "string", "peer", "any" };
47 /* Internal stuff used in cache to free a variable */
48 static void xbt_cfgelm_free(void *data);
50 /* Retrieve the variable we'll modify */
51 static xbt_cfgelm_t xbt_cfgelm_get(xbt_cfg_t cfg, const char *name,
52 e_xbt_cfgelm_type_t type);
54 /*----[ Memory management ]-----------------------------------------------*/
56 /** @brief Constructor
58 * Initialise an config set
62 xbt_cfg_t xbt_cfg_new(void)
64 return (xbt_cfg_t) xbt_dict_new();
67 /** \brief Copy an existing configuration set
69 * \arg whereto the config set to be created
70 * \arg tocopy the source data
72 * This only copy the registrations, not the actual content
75 void xbt_cfg_cpy(xbt_cfg_t tocopy, xbt_cfg_t * whereto)
77 xbt_dict_cursor_t cursor = NULL;
78 xbt_cfgelm_t variable = NULL;
81 DEBUG1("Copy cfg set %p", tocopy);
83 xbt_assert0(tocopy, "cannot copy NULL config");
85 xbt_dict_foreach((xbt_dict_t) tocopy, cursor, name, variable) {
86 xbt_cfg_register(*whereto, name, variable->type, variable->min,
87 variable->max, variable->cb_set, variable->cb_rm);
91 /** @brief Destructor */
92 void xbt_cfg_free(xbt_cfg_t * cfg)
94 DEBUG1("Frees cfg set %p", cfg);
95 xbt_dict_free((xbt_dict_t *) cfg);
98 /** @brief Dump a config set for debuging purpose
100 * \arg name The name to give to this config set
101 * \arg indent what to write at the begining of each line (right number of spaces)
102 * \arg cfg the config set
104 void xbt_cfg_dump(const char *name, const char *indent, xbt_cfg_t cfg)
106 xbt_dict_t dict = (xbt_dict_t) cfg;
107 xbt_dict_cursor_t cursor = NULL;
108 xbt_cfgelm_t variable = NULL;
118 printf("%s>> Dumping of the config set '%s':\n", indent, name);
119 xbt_dict_foreach(dict, cursor, key, variable) {
121 printf("%s %s:", indent, key);
123 size = xbt_dynar_length(variable->content);
125 ("%d_to_%d_%s. Actual size=%d. prerm=%p,postset=%p, List of values:\n",
126 variable->min, variable->max, xbt_cfgelm_type_name[variable->type],
127 size, variable->cb_rm, variable->cb_set);
129 switch (variable->type) {
132 for (i = 0; i < size; i++) {
133 ival = xbt_dynar_get_as(variable->content, i, int);
134 printf("%s %d\n", indent, ival);
138 case xbt_cfgelm_double:
139 for (i = 0; i < size; i++) {
140 dval = xbt_dynar_get_as(variable->content, i, double);
141 printf("%s %f\n", indent, dval);
145 case xbt_cfgelm_string:
146 for (i = 0; i < size; i++) {
147 sval = xbt_dynar_get_as(variable->content, i, char *);
148 printf("%s %s\n", indent, sval);
152 case xbt_cfgelm_peer:
153 for (i = 0; i < size; i++) {
154 hval = xbt_dynar_get_as(variable->content, i, xbt_peer_t);
155 printf("%s %s:%d\n", indent, hval->name, hval->port);
160 printf("%s Invalid type!!\n", indent);
166 printf("%s<< End of the config set '%s'\n", indent, name);
169 xbt_dict_cursor_free(&cursor);
174 * free an config element
177 void xbt_cfgelm_free(void *data)
179 xbt_cfgelm_t c = (xbt_cfgelm_t) data;
181 DEBUG1("Frees cfgelm %p", c);
184 xbt_dynar_free(&(c->content));
188 /*----[ Registering stuff ]-----------------------------------------------*/
190 /** @brief Register an element within a config set
192 * @arg cfg the config set
193 * @arg type the type of the config element
194 * @arg min the minimum
195 * @arg max the maximum
199 xbt_cfg_register(xbt_cfg_t cfg,
200 const char *name, e_xbt_cfgelm_type_t type,
201 int min, int max, xbt_cfg_cb_t cb_set, xbt_cfg_cb_t cb_rm)
206 xbt_assert4(type >= xbt_cfgelm_int && type <= xbt_cfgelm_peer,
207 "type of %s not valid (%d should be between %d and %d)",
208 name, type, xbt_cfgelm_int, xbt_cfgelm_peer);
209 res = xbt_dict_get_or_null((xbt_dict_t) cfg, name);
212 WARN1("Config elem %s registered twice.", name);
213 /* Will be removed by the insertion of the new one */
216 res = xbt_new(s_xbt_cfgelm_t, 1);
217 DEBUG7("Register cfg elm %s (%d to %d %s (=%d) @%p in set %p)",
218 name, min, max, xbt_cfgelm_type_name[type], type, res, cfg);
223 res->cb_set = cb_set;
228 res->content = xbt_dynar_new(sizeof(int), NULL);
231 case xbt_cfgelm_double:
232 res->content = xbt_dynar_new(sizeof(double), NULL);
235 case xbt_cfgelm_string:
236 res->content = xbt_dynar_new(sizeof(char *), xbt_free_ref);
239 case xbt_cfgelm_peer:
240 res->content = xbt_dynar_new(sizeof(xbt_peer_t), xbt_peer_free_voidp);
244 ERROR1("%d is an invalide type code", type);
247 xbt_dict_set((xbt_dict_t) cfg, name, res, &xbt_cfgelm_free);
250 /** @brief Unregister an element from a config set.
252 * @arg cfg the config set
253 * @arg name the name of the elem to be freed
255 * Note that it removes both the description and the actual content.
256 * Throws not_found when no such element exists.
259 void xbt_cfg_unregister(xbt_cfg_t cfg, const char *name)
261 DEBUG2("Unregister elm '%s' from set %p", name, cfg);
262 xbt_dict_remove((xbt_dict_t) cfg, name);
266 * @brief Parse a string and register the stuff described.
268 * @arg cfg the config set
269 * @arg entry a string describing the element to register
271 * The string may consist in several variable descriptions separated by a space.
272 * Each of them must use the following syntax: \<name\>:\<min nb\>_to_\<max nb\>_\<type\>
273 * with type being one of 'string','int', 'peer' or 'double'.
276 void xbt_cfg_register_str(xbt_cfg_t cfg, const char *entry)
278 char *entrycpy = xbt_strdup(entry);
282 e_xbt_cfgelm_type_t type;
283 DEBUG1("Register string '%s'", entry);
285 tok = strchr(entrycpy, ':');
286 xbt_assert2(tok, "Invalid config element descriptor: %s%s",
287 entry, "; Should be <name>:<min nb>_to_<max nb>_<type>");
290 min = strtol(tok, &tok, 10);
291 xbt_assert1(tok, "Invalid minimum in config element descriptor %s", entry);
293 xbt_assert2(strcmp(tok, "_to_"),
294 "Invalid config element descriptor : %s%s",
295 entry, "; Should be <name>:<min nb>_to_<max nb>_<type>");
296 tok += strlen("_to_");
298 max = strtol(tok, &tok, 10);
299 xbt_assert1(tok, "Invalid maximum in config element descriptor %s", entry);
301 xbt_assert2(*(tok++) == '_',
302 "Invalid config element descriptor: %s%s", entry,
303 "; Should be <name>:<min nb>_to_<max nb>_<type>");
306 type < xbt_cfgelm_type_count
307 && strcmp(tok, xbt_cfgelm_type_name[type]); type++);
308 xbt_assert2(type < xbt_cfgelm_type_count,
309 "Invalid type in config element descriptor: %s%s", entry,
310 "; Should be one of 'string', 'int', 'peer' or 'double'.");
312 xbt_cfg_register(cfg, entrycpy, type, min, max, NULL, NULL);
314 free(entrycpy); /* strdup'ed by dict mechanism, but cannot be const */
317 /** @brief Check that each variable have the right amount of values */
319 void xbt_cfg_check(xbt_cfg_t cfg)
321 xbt_dict_cursor_t cursor;
322 xbt_cfgelm_t variable;
326 xbt_assert0(cfg, "NULL config set.");
327 DEBUG1("Check cfg set %p", cfg);
329 xbt_dict_foreach((xbt_dict_t) cfg, cursor, name, variable) {
330 size = xbt_dynar_length(variable->content);
331 if (variable->min > size) {
332 xbt_dict_cursor_free(&cursor);
333 THROW4(mismatch_error, 0,
334 "Config elem %s needs at least %d %s, but there is only %d values.",
335 name, variable->min, xbt_cfgelm_type_name[variable->type], size);
338 if (variable->max > 0 && variable->max < size) {
339 xbt_dict_cursor_free(&cursor);
340 THROW4(mismatch_error, 0,
341 "Config elem %s accepts at most %d %s, but there is %d values.",
342 name, variable->max, xbt_cfgelm_type_name[variable->type], size);
346 xbt_dict_cursor_free(&cursor);
349 static xbt_cfgelm_t xbt_cfgelm_get(xbt_cfg_t cfg,
350 const char *name, e_xbt_cfgelm_type_t type)
352 xbt_cfgelm_t res = NULL;
354 res = xbt_dict_get_or_null((xbt_dict_t) cfg, name);
356 THROW1(not_found_error, 0,
357 "No registered variable '%s' in this config set", name);
359 xbt_assert3(type == xbt_cfgelm_any || res->type == type,
360 "You tried to access to the config element %s as an %s, but its type is %s.",
362 xbt_cfgelm_type_name[type], xbt_cfgelm_type_name[res->type]);
367 /** @brief Get the type of this variable in that configuration set
369 * \arg cfg the config set
370 * \arg name the name of the element
371 * \arg type the result
375 e_xbt_cfgelm_type_t xbt_cfg_get_type(xbt_cfg_t cfg, const char *name)
378 xbt_cfgelm_t variable = NULL;
380 variable = xbt_dict_get_or_null((xbt_dict_t) cfg, name);
382 THROW1(not_found_error, 0,
383 "Can't get the type of '%s' since this variable does not exist",
386 INFO1("type in variable = %d", variable->type);
388 return variable->type;
391 /*----[ Setting ]---------------------------------------------------------*/
392 /** @brief va_args version of xbt_cfg_set
394 * \arg cfg config set to fill
395 * \arg n variable name
396 * \arg pa variable value
398 * Add some values to the config set.
400 void xbt_cfg_set_vargs(xbt_cfg_t cfg, const char *name, va_list pa)
405 e_xbt_cfgelm_type_t type = 0; /* Set a dummy value to make gcc happy. It cannot get uninitialized */
410 type = xbt_cfg_get_type(cfg, name);
412 if (e.category == not_found_error) {
414 THROW1(not_found_error, 0,
415 "Can't set the property '%s' since it's not registered", name);
421 case xbt_cfgelm_peer:
422 str = va_arg(pa, char *);
424 xbt_cfg_set_peer(cfg, name, str, i);
427 case xbt_cfgelm_string:
428 str = va_arg(pa, char *);
429 xbt_cfg_set_string(cfg, name, str);
434 xbt_cfg_set_int(cfg, name, i);
437 case xbt_cfgelm_double:
438 d = va_arg(pa, double);
439 xbt_cfg_set_double(cfg, name, d);
443 xbt_assert2(0, "Config element variable %s not valid (type=%d)", name,
448 /** @brief Add a NULL-terminated list of pairs {(char*)key, value} to the set
450 * \arg cfg config set to fill
451 * \arg name variable name
452 * \arg varargs variable value
455 void xbt_cfg_set(xbt_cfg_t cfg, const char *name, ...)
460 xbt_cfg_set_vargs(cfg, name, pa);
464 /** @brief Add values parsed from a string into a config set
466 * \arg cfg config set to fill
467 * \arg options a string containing the content to add to the config set. This
468 * is a '\\t',' ' or '\\n' separated list of variables. Each individual variable is
469 * like "[name]:[value]" where [name] is the name of an already registred
470 * variable, and [value] conforms to the data type under which this variable was
473 * @todo This is a crude manual parser, it should be a proper lexer.
476 void xbt_cfg_set_parse(xbt_cfg_t cfg, const char *options)
484 xbt_cfgelm_t variable = NULL;
485 char *optionlist_cpy;
486 char *option, *name, *val;
491 if (!options || !strlen(options)) { /* nothing to do */
494 optionlist_cpy = xbt_strdup(options);
496 DEBUG1("List to parse and set:'%s'", options);
497 option = optionlist_cpy;
498 while (1) { /* breaks in the code */
504 DEBUG3("Still to parse and set: '%s'. len=%d; option-name=%ld",
505 name, len, (long) (option - name));
508 while (option - name <= (len - 1) && *option != ' ' && *option != '\n'
509 && *option != '\t') {
510 DEBUG1("Take %c.", *option);
513 if (option - name == len) {
514 DEBUG0("Boundary=EOL");
515 option = NULL; /* don't do next iteration */
518 DEBUG3("Boundary on '%c'. len=%d;option-name=%ld",
519 *option, len, (long) (option - name));
521 /* Pass the following blank chars */
523 while (option - name < (len - 1) &&
524 (*option == ' ' || *option == '\n' || *option == '\t')) {
525 /* fprintf(stderr,"Ignore a blank char.\n"); */
528 if (option - name == len - 1)
529 option = NULL; /* don't do next iteration */
531 DEBUG2("parse now:'%s'; parse later:'%s'", name, option);
533 if (name[0] == ' ' || name[0] == '\n' || name[0] == '\t')
538 val = strchr(name, ':');
540 free(optionlist_cpy);
542 "Option '%s' badly formated. Should be of the form 'name:value'",
547 DEBUG2("name='%s';val='%s'", name, val);
550 variable = xbt_dict_get((xbt_dict_t) cfg, name);
553 /* put it back on what won't get freed, ie within "options" and out of "optionlist_cpy" */
554 name = (char *) (optionlist_cpy - name + options);
555 free(optionlist_cpy);
556 if (e.category == not_found_error) {
558 THROW1(not_found_error, 0,
559 "No registrated variable corresponding to '%s'.", name);
565 switch (variable->type) {
566 case xbt_cfgelm_string:
567 xbt_cfg_set_string(cfg, name, val); /* throws */
571 i = strtol(val, &val, 0);
573 free(optionlist_cpy);
575 "Value of option %s not valid. Should be an integer",
579 xbt_cfg_set_int(cfg, name, i); /* throws */
582 case xbt_cfgelm_double:
583 d = strtod(val, &val);
585 free(optionlist_cpy);
587 "Value of option %s not valid. Should be a double",
591 xbt_cfg_set_double(cfg, name, d); /* throws */
594 case xbt_cfgelm_peer:
596 val = strchr(val, ':');
598 free(optionlist_cpy);
600 "Value of option %s not valid. Should be an peer (machine:port)",
605 i = strtol(val, &val, 0);
607 free(optionlist_cpy);
609 "Value of option %s not valid. Should be an peer (machine:port)",
613 xbt_cfg_set_peer(cfg, name, str, i); /* throws */
617 THROW1(unknown_error, 0, "Type of config element %s is not valid.",
622 free(optionlist_cpy);
626 free(optionlist_cpy);
630 /** @brief Set or add an integer value to \a name within \a cfg
632 * \arg cfg the config set
633 * \arg name the name of the variable
634 * \arg val the value of the variable
636 void xbt_cfg_set_int(xbt_cfg_t cfg, const char *name, int val)
638 xbt_cfgelm_t variable;
640 VERB2("Configuration setting: %s=%d", name, val);
641 variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_int);
643 if (variable->max == 1) {
644 if (variable->cb_rm && xbt_dynar_length(variable->content))
645 (*variable->cb_rm) (name, 0);
647 xbt_dynar_set(variable->content, 0, &val);
650 && xbt_dynar_length(variable->content) ==
651 (unsigned long) variable->max)
652 THROW3(mismatch_error, 0,
653 "Cannot add value %d to the config element %s since it's already full (size=%d)",
654 val, name, variable->max);
656 xbt_dynar_push(variable->content, &val);
659 if (variable->cb_set)
660 (*variable->cb_set) (name, xbt_dynar_length(variable->content) - 1);
663 /** @brief Set or add a double value to \a name within \a cfg
665 * \arg cfg the config set
666 * \arg name the name of the variable
667 * \arg val the doule to set
670 void xbt_cfg_set_double(xbt_cfg_t cfg, const char *name, double val)
672 xbt_cfgelm_t variable;
674 VERB2("Configuration setting: %s=%f", name, val);
675 variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_double);
677 if (variable->max == 1) {
678 if (variable->cb_rm && xbt_dynar_length(variable->content))
679 (*variable->cb_rm) (name, 0);
681 xbt_dynar_set(variable->content, 0, &val);
683 if (variable->max && xbt_dynar_length(variable->content) == variable->max)
684 THROW3(mismatch_error, 0,
685 "Cannot add value %f to the config element %s since it's already full (size=%d)",
686 val, name, variable->max);
688 xbt_dynar_push(variable->content, &val);
691 if (variable->cb_set)
692 (*variable->cb_set) (name, xbt_dynar_length(variable->content) - 1);
695 /** @brief Set or add a string value to \a name within \a cfg
697 * \arg cfg the config set
698 * \arg name the name of the variable
699 * \arg val the value to be added
703 void xbt_cfg_set_string(xbt_cfg_t cfg, const char *name, const char *val)
705 xbt_cfgelm_t variable;
706 char *newval = xbt_strdup(val);
708 VERB2("Configuration setting: %s=%s", name, val);
709 variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_string);
710 DEBUG5("Variable: %d to %d %s (=%d) @%p",
711 variable->min, variable->max, xbt_cfgelm_type_name[variable->type],
712 variable->type, variable);
714 if (variable->max == 1) {
715 if (xbt_dynar_length(variable->content)) {
717 (*variable->cb_rm) (name, 0);
718 else if (variable->type == xbt_cfgelm_string) {
719 char *sval = xbt_dynar_get_as(variable->content, 0, char *);
724 xbt_dynar_set(variable->content, 0, &newval);
726 if (variable->max && xbt_dynar_length(variable->content) == variable->max)
727 THROW3(mismatch_error, 0,
728 "Cannot add value %s to the config element %s since it's already full (size=%d)",
729 name, val, variable->max);
731 xbt_dynar_push(variable->content, &newval);
734 if (variable->cb_set)
735 (*variable->cb_set) (name, xbt_dynar_length(variable->content) - 1);
738 /** @brief Set or add an peer value to \a name within \a cfg
740 * \arg cfg the config set
741 * \arg name the name of the variable
743 * \arg port the port number
745 * \e peer values are composed of a string (peername) and an integer (port)
749 xbt_cfg_set_peer(xbt_cfg_t cfg, const char *name, const char *peer, int port)
751 xbt_cfgelm_t variable;
752 xbt_peer_t val = xbt_peer_new(peer, port);
754 VERB3("Configuration setting: %s=%s:%d", name, peer, port);
756 variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_peer);
758 if (variable->max == 1) {
759 if (variable->cb_rm && xbt_dynar_length(variable->content))
760 (*variable->cb_rm) (name, 0);
762 xbt_dynar_set(variable->content, 0, &val);
764 if (variable->max && xbt_dynar_length(variable->content) == variable->max)
765 THROW4(mismatch_error, 0,
766 "Cannot add value %s:%d to the config element %s since it's already full (size=%d)",
767 peer, port, name, variable->max);
769 xbt_dynar_push(variable->content, &val);
772 if (variable->cb_set)
773 (*variable->cb_set) (name, xbt_dynar_length(variable->content) - 1);
776 /* ---- [ Removing ] ---- */
778 /** @brief Remove the provided \e val integer value from a variable
780 * \arg cfg the config set
781 * \arg name the name of the variable
782 * \arg val the value to be removed
784 void xbt_cfg_rm_int(xbt_cfg_t cfg, const char *name, int val)
787 xbt_cfgelm_t variable;
791 variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_int);
793 if (xbt_dynar_length(variable->content) == variable->min)
794 THROW3(mismatch_error, 0,
795 "Cannot remove value %d from the config element %s since it's already at its minimal size (=%d)",
796 val, name, variable->min);
798 xbt_dynar_foreach(variable->content, cpt, seen) {
801 (*variable->cb_rm) (name, cpt);
802 xbt_dynar_cursor_rm(variable->content, &cpt);
807 THROW2(not_found_error, 0,
808 "Can't remove the value %d of config element %s: value not found.",
812 /** @brief Remove the provided \e val double value from a variable
814 * \arg cfg the config set
815 * \arg name the name of the variable
816 * \arg val the value to be removed
819 void xbt_cfg_rm_double(xbt_cfg_t cfg, const char *name, double val)
821 xbt_cfgelm_t variable;
825 variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_double);
827 if (xbt_dynar_length(variable->content) == variable->min)
828 THROW3(mismatch_error, 0,
829 "Cannot remove value %f from the config element %s since it's already at its minimal size (=%d)",
830 val, name, variable->min);
832 xbt_dynar_foreach(variable->content, cpt, seen) {
834 xbt_dynar_cursor_rm(variable->content, &cpt);
836 (*variable->cb_rm) (name, cpt);
841 THROW2(not_found_error, 0,
842 "Can't remove the value %f of config element %s: value not found.",
846 /** @brief Remove the provided \e val string value from a variable
848 * \arg cfg the config set
849 * \arg name the name of the variable
850 * \arg val the value of the string which will be removed
852 void xbt_cfg_rm_string(xbt_cfg_t cfg, const char *name, const char *val)
854 xbt_cfgelm_t variable;
858 variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_string);
860 if (xbt_dynar_length(variable->content) == variable->min)
861 THROW3(mismatch_error, 0,
862 "Cannot remove value %s from the config element %s since it's already at its minimal size (=%d)",
863 name, val, variable->min);
865 xbt_dynar_foreach(variable->content, cpt, seen) {
866 if (!strcpy(seen, val)) {
868 (*variable->cb_rm) (name, cpt);
869 xbt_dynar_cursor_rm(variable->content, &cpt);
874 THROW2(not_found_error, 0,
875 "Can't remove the value %s of config element %s: value not found.",
879 /** @brief Remove the provided \e val peer value from a variable
881 * \arg cfg the config set
882 * \arg name the name of the variable
883 * \arg peer the peername
884 * \arg port the port number
888 xbt_cfg_rm_peer(xbt_cfg_t cfg, const char *name, const char *peer, int port)
890 xbt_cfgelm_t variable;
894 variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_peer);
896 if (xbt_dynar_length(variable->content) == variable->min)
897 THROW4(mismatch_error, 0,
898 "Cannot remove value %s:%d from the config element %s since it's already at its minimal size (=%d)",
899 peer, port, name, variable->min);
901 xbt_dynar_foreach(variable->content, cpt, seen) {
902 if (!strcpy(seen->name, peer) && seen->port == port) {
904 (*variable->cb_rm) (name, cpt);
905 xbt_dynar_cursor_rm(variable->content, &cpt);
910 THROW3(not_found_error, 0,
911 "Can't remove the value %s:%d of config element %s: value not found.",
915 /** @brief Remove the \e pos th value from the provided variable */
917 void xbt_cfg_rm_at(xbt_cfg_t cfg, const char *name, int pos)
920 xbt_cfgelm_t variable;
922 variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_any);
924 if (xbt_dynar_length(variable->content) == variable->min)
925 THROW3(mismatch_error, 0,
926 "Cannot remove %dth value from the config element %s since it's already at its minimal size (=%d)",
927 pos, name, variable->min);
930 (*variable->cb_rm) (name, pos);
931 xbt_dynar_remove_at(variable->content, pos, NULL);
934 /** @brief Remove all the values from a variable
936 * \arg cfg the config set
937 * \arg name the name of the variable
940 void xbt_cfg_empty(xbt_cfg_t cfg, const char *name)
942 xbt_cfgelm_t variable = NULL;
946 variable = xbt_dict_get((xbt_dict_t) cfg, name);
948 if (e.category != not_found_error)
952 THROW1(not_found_error, 0,
953 "Can't empty '%s' since this config element does not exist",
958 if (variable->cb_rm) {
961 xbt_dynar_foreach(variable->content, cpt, ignored) {
962 (*variable->cb_rm) (name, cpt);
965 xbt_dynar_reset(variable->content);
969 /*----[ Getting ]---------------------------------------------------------*/
971 /** @brief Retrieve an integer value of a variable (get a warning if not uniq)
973 * \arg cfg the config set
974 * \arg name the name of the variable
975 * \arg val the wanted value
977 * Returns the first value from the config set under the given name.
978 * If there is more than one value, it will issue a warning. Consider using
979 * xbt_cfg_get_dynar() instead.
981 * \warning the returned value is the actual content of the config set
983 int xbt_cfg_get_int(xbt_cfg_t cfg, const char *name)
985 xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_int);
987 if (xbt_dynar_length(variable->content) > 1) {
989 ("You asked for the first value of the config element '%s', but there is %lu values",
990 name, xbt_dynar_length(variable->content));
993 return xbt_dynar_get_as(variable->content, 0, int);
996 /** @brief Retrieve a double value of a variable (get a warning if not uniq)
998 * \arg cfg the config set
999 * \arg name the name of the variable
1000 * \arg val the wanted value
1002 * Returns the first value from the config set under the given name.
1003 * If there is more than one value, it will issue a warning. Consider using
1004 * xbt_cfg_get_dynar() instead.
1006 * \warning the returned value is the actual content of the config set
1009 double xbt_cfg_get_double(xbt_cfg_t cfg, const char *name)
1011 xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_double);
1013 if (xbt_dynar_length(variable->content) > 1) {
1015 ("You asked for the first value of the config element '%s', but there is %lu values\n",
1016 name, xbt_dynar_length(variable->content));
1019 return xbt_dynar_get_as(variable->content, 0, double);
1022 /** @brief Retrieve a string value of a variable (get a warning if not uniq)
1024 * \arg th the config set
1025 * \arg name the name of the variable
1026 * \arg val the wanted value
1028 * Returns the first value from the config set under the given name.
1029 * If there is more than one value, it will issue a warning. Consider using
1030 * xbt_cfg_get_dynar() instead.
1032 * \warning the returned value is the actual content of the config set
1035 char *xbt_cfg_get_string(xbt_cfg_t cfg, const char *name)
1037 xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_string);
1039 if (xbt_dynar_length(variable->content) > 1) {
1041 ("You asked for the first value of the config element '%s', but there is %lu values\n",
1042 name, xbt_dynar_length(variable->content));
1045 return xbt_dynar_get_as(variable->content, 0, char *);
1048 /** @brief Retrieve an peer value of a variable (get a warning if not uniq)
1050 * \arg cfg the config set
1051 * \arg name the name of the variable
1052 * \arg peer the peer
1053 * \arg port the port number
1055 * Returns the first value from the config set under the given name.
1056 * If there is more than one value, it will issue a warning. Consider using
1057 * xbt_cfg_get_dynar() instead.
1059 * \warning the returned value is the actual content of the config set
1062 void xbt_cfg_get_peer(xbt_cfg_t cfg, const char *name, char **peer, int *port)
1064 xbt_cfgelm_t variable;
1067 variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_peer);
1069 if (xbt_dynar_length(variable->content) > 1) {
1071 ("You asked for the first value of the config element '%s', but there is %lu values\n",
1072 name, xbt_dynar_length(variable->content));
1075 val = xbt_dynar_get_as(variable->content, 0, xbt_peer_t);
1080 /** @brief Retrieve the dynar of all the values stored in a variable
1082 * \arg cfg where to search in
1083 * \arg name what to search for
1086 * Get the data stored in the config set.
1088 * \warning the returned value is the actual content of the config set
1090 xbt_dynar_t xbt_cfg_get_dynar(xbt_cfg_t cfg, const char *name)
1092 xbt_cfgelm_t variable = NULL;
1096 variable = xbt_dict_get((xbt_dict_t) cfg, name);
1098 if (e.category == not_found_error) {
1100 THROW1(not_found_error, 0,
1101 "No registered variable %s in this config set", name);
1106 return variable->content;
1110 /** @brief Retrieve one of the integer value of a variable */
1111 int xbt_cfg_get_int_at(xbt_cfg_t cfg, const char *name, int pos)
1114 xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_int);
1115 return xbt_dynar_get_as(variable->content, pos, int);
1118 /** @brief Retrieve one of the double value of a variable */
1119 double xbt_cfg_get_double_at(xbt_cfg_t cfg, const char *name, int pos)
1122 xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_double);
1123 return xbt_dynar_get_as(variable->content, pos, double);
1127 /** @brief Retrieve one of the string value of a variable */
1128 char *xbt_cfg_get_string_at(xbt_cfg_t cfg, const char *name, int pos)
1131 xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_string);
1132 return xbt_dynar_get_as(variable->content, pos, char *);
1135 /** @brief Retrieve one of the peer value of a variable */
1137 xbt_cfg_get_peer_at(xbt_cfg_t cfg, const char *name, int pos,
1138 char **peer, int *port)
1141 xbt_cfgelm_t variable = xbt_cfgelm_get(cfg, name, xbt_cfgelm_int);
1142 xbt_peer_t val = xbt_dynar_get_ptr(variable->content, pos);
1153 XBT_TEST_SUITE("config", "Configuration support");
1155 static xbt_cfg_t make_set()
1157 xbt_cfg_t set = NULL;
1159 set = xbt_cfg_new();
1160 xbt_cfg_register_str(set, "speed:1_to_2_int");
1161 xbt_cfg_register_str(set, "peername:1_to_1_string");
1162 xbt_cfg_register_str(set, "user:1_to_10_string");
1165 } /* end_of_make_set */
1167 XBT_TEST_UNIT("memuse", test_config_memuse, "Alloc and free a config set")
1169 xbt_cfg_t set = make_set();
1170 xbt_test_add0("Alloc and free a config set");
1171 xbt_cfg_set_parse(set,
1172 "peername:veloce user:mquinson\nuser:oaumage\tuser:alegrand");
1177 XBT_TEST_UNIT("validation", test_config_validation, "Validation tests")
1179 xbt_cfg_t set = set = make_set();
1182 xbt_test_add0("Having too few elements for speed");
1183 xbt_cfg_set_parse(set,
1184 "peername:veloce user:mquinson\nuser:oaumage\tuser:alegrand");
1189 if (e.category != mismatch_error ||
1190 strncmp(e.msg, "Config elem speed needs",
1191 strlen("Config elem speed needs")))
1192 xbt_test_fail1("Got an exception. msg=%s", e.msg);
1200 xbt_test_add0("Having too much values of 'speed'");
1202 xbt_cfg_set_parse(set, "peername:toto:42 user:alegrand");
1204 xbt_cfg_set_parse(set, "speed:42 speed:24 speed:34");
1207 if (e.category != mismatch_error ||
1208 strncmp(e.msg, "Cannot add value 34 to the config elem speed",
1209 strlen("Config elem speed needs")))
1210 xbt_test_fail1("Got an exception. msg=%s", e.msg);
1219 XBT_TEST_UNIT("use", test_config_use, "Data retrieving tests")
1222 xbt_test_add0("Get a single value");
1224 /* get_single_value */
1226 xbt_cfg_t myset = make_set();
1228 xbt_cfg_set_parse(myset, "peername:toto:42 speed:42");
1229 ival = xbt_cfg_get_int(myset, "speed");
1231 xbt_test_fail1("Speed value = %d, I expected 42", ival);
1232 xbt_cfg_free(&myset);
1235 xbt_test_add0("Get multiple values");
1237 /* get_multiple_value */
1239 xbt_cfg_t myset = make_set();
1241 xbt_cfg_set_parse(myset, "peername:veloce user:foo\nuser:bar\tuser:toto");
1242 xbt_cfg_set_parse(myset, "speed:42");
1243 xbt_cfg_check(myset);
1244 dyn = xbt_cfg_get_dynar(myset, "user");
1246 if (xbt_dynar_length(dyn) != 3)
1247 xbt_test_fail1("Dynar length = %lu, I expected 3",
1248 xbt_dynar_length(dyn));
1250 if (strcmp(xbt_dynar_get_as(dyn, 0, char *), "foo"))
1251 xbt_test_fail1("Dynar[0] = %s, I expected foo",
1252 xbt_dynar_get_as(dyn, 0, char *));
1254 if (strcmp(xbt_dynar_get_as(dyn, 1, char *), "bar"))
1255 xbt_test_fail1("Dynar[1] = %s, I expected bar",
1256 xbt_dynar_get_as(dyn, 1, char *));
1258 if (strcmp(xbt_dynar_get_as(dyn, 2, char *), "toto"))
1259 xbt_test_fail1("Dynar[2] = %s, I expected toto",
1260 xbt_dynar_get_as(dyn, 2, char *));
1261 xbt_cfg_free(&myset);
1264 xbt_test_add0("Access to a non-existant entry");
1266 /* non-existant_entry */
1267 xbt_cfg_t myset = make_set();
1271 xbt_cfg_set_parse(myset, "color:blue");
1273 if (e.category != not_found_error)
1274 xbt_test_exception(e);
1277 xbt_cfg_free(&myset);
1280 #endif /* SIMGRID_TEST */