1 /* Copyright (c) 2004-2014,2016. The SimGrid Team.
2 * All rights reserved. */
12 #include <type_traits>
14 #include <xbt/config.h>
15 #include <xbt/config.hpp>
17 #include "xbt/sysdep.h"
20 #include "xbt/dynar.h"
25 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_cfg, xbt, "configuration support");
27 XBT_EXPORT_NO_IMPORT(xbt_cfg_t) simgrid_config = NULL;
32 void increment(e_xbt_cfgelm_type_t& type)
34 typedef std::underlying_type<e_xbt_cfgelm_type_t>::type underlying_type;
35 type = (e_xbt_cfgelm_type_t) ((underlying_type) type + 1);
43 // A configuration variable:
44 struct ConfigurationElement {
48 /* Allowed type of the variable */
49 e_xbt_cfgelm_type_t type;
50 bool isdefault = true;
53 xbt_cfg_cb_t cb_set = nullptr;
55 /* Advanced callback (for xbt_cfgelm_string only) */
56 std::function<void(const char* value)> callback;
58 /* actual content (could be an union or something) */
59 xbt_dynar_t content = nullptr;
61 ~ConfigurationElement()
63 XBT_DEBUG("Frees cfgelm %p", this);
64 if (this->type != xbt_cfgelm_alias)
65 xbt_dynar_free(&(this->content));
73 static const char *xbt_cfgelm_type_name[xbt_cfgelm_type_count] = { "int", "double", "string", "boolean", "any", "outofbound" };
75 const struct xbt_boolean_couple xbt_cfgelm_boolean_values[] = {
83 /* Internal stuff used in cache to free a variable */
84 static void xbt_cfgelm_free(void *data)
87 delete (simgrid::config::ConfigurationElement*) data;
90 /* Retrieve the variable we'll modify */
91 static simgrid::config::ConfigurationElement* xbt_cfgelm_get(xbt_cfg_t cfg, const char *name, e_xbt_cfgelm_type_t type);
93 /*----[ Memory management ]-----------------------------------------------*/
94 /** @brief Constructor
96 * Initialise a config set
98 xbt_cfg_t xbt_cfg_new(void)
100 return (xbt_cfg_t) xbt_dict_new_homogeneous(&xbt_cfgelm_free);
103 /** @brief Destructor */
104 void xbt_cfg_free(xbt_cfg_t * cfg)
106 XBT_DEBUG("Frees cfg set %p", cfg);
107 xbt_dict_free((xbt_dict_t *) cfg);
110 /** @brief Dump a config set for debuging purpose
112 * @param name The name to give to this config set
113 * @param indent what to write at the beginning of each line (right number of spaces)
114 * @param cfg the config set
116 void xbt_cfg_dump(const char *name, const char *indent, xbt_cfg_t cfg)
118 xbt_dict_t dict = (xbt_dict_t) cfg;
119 xbt_dict_cursor_t cursor = NULL;
120 simgrid::config::ConfigurationElement* variable = NULL;
129 printf("%s>> Dumping of the config set '%s':\n", indent, name);
131 xbt_dict_foreach(dict, cursor, key, variable) {
132 printf("%s %s:", indent, key);
134 size = xbt_dynar_length(variable->content);
135 printf ("%s. Actual size=%d. postset=%p\n",
136 xbt_cfgelm_type_name[variable->type], size, variable->cb_set);
138 switch (variable->type) {
140 for (i = 0; i < size; i++) {
141 ival = xbt_dynar_get_as(variable->content, i, int);
142 printf("%s %d\n", indent, ival);
145 case xbt_cfgelm_double:
146 for (i = 0; i < size; i++) {
147 dval = xbt_dynar_get_as(variable->content, i, double);
148 printf("%s %f\n", indent, dval);
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);
157 case xbt_cfgelm_boolean:
158 for (i = 0; i < size; i++) {
159 ival = xbt_dynar_get_as(variable->content, i, int);
160 printf("%s %d\n", indent, ival);
163 case xbt_cfgelm_alias:
167 printf("%s Invalid type!!\n", indent);
173 printf("%s<< End of the config set '%s'\n", indent, name);
176 xbt_dict_cursor_free(&cursor);
179 /*----[ Registering stuff ]-----------------------------------------------*/
180 /** @brief Register an element within a config set
182 * @param cfg the config set
183 * @param name the name of the config element
184 * @param desc a description for this item (used by xbt_cfg_help())
185 * @param type the type of the config element
186 * @param cb_set callback function called when a value is set
188 static void xbt_cfg_register(
189 xbt_cfg_t * cfg, const char *name, const char *desc, e_xbt_cfgelm_type_t type,
191 std::function<void(const char* value)> callback = std::function<void(const char* value)>())
194 *cfg = xbt_cfg_new();
195 xbt_assert(type >= xbt_cfgelm_int && type <= xbt_cfgelm_boolean,
196 "type of %s not valid (%d should be between %d and %d)",
197 name, (int)type, xbt_cfgelm_int, xbt_cfgelm_boolean);
199 simgrid::config::ConfigurationElement* res = (simgrid::config::ConfigurationElement*) xbt_dict_get_or_null((xbt_dict_t) * cfg, name);
200 xbt_assert(NULL == res, "Refusing to register the config element '%s' twice.", name);
202 res = new simgrid::config::ConfigurationElement();
203 XBT_DEBUG("Register cfg elm %s (%s) (%s (=%d) @%p in set %p)",
204 name, desc, xbt_cfgelm_type_name[type], (int)type, res, *cfg);
208 res->cb_set = cb_set;
209 res->callback = std::move(callback);
213 res->content = xbt_dynar_new(sizeof(int), NULL);
215 case xbt_cfgelm_double:
216 res->content = xbt_dynar_new(sizeof(double), NULL);
218 case xbt_cfgelm_string:
219 res->content = xbt_dynar_new(sizeof(char *), xbt_free_ref);
221 case xbt_cfgelm_boolean:
222 res->content = xbt_dynar_new(sizeof(int), NULL);
225 XBT_ERROR("%d is an invalid type code", (int)type);
229 xbt_dict_set((xbt_dict_t) * cfg, name, res, NULL);
232 void xbt_cfg_register_double(const char *name, double default_value,xbt_cfg_cb_t cb_set, const char *desc){
233 xbt_cfg_register(&simgrid_config,name,desc,xbt_cfgelm_double,cb_set);
234 xbt_cfg_setdefault_double(name, default_value);
236 void xbt_cfg_register_int(const char *name, int default_value,xbt_cfg_cb_t cb_set, const char *desc) {
237 xbt_cfg_register(&simgrid_config,name,desc,xbt_cfgelm_int,cb_set);
238 xbt_cfg_setdefault_int(name, default_value);
240 void xbt_cfg_register_string(const char *name, const char *default_value, xbt_cfg_cb_t cb_set, const char *desc){
241 xbt_cfg_register(&simgrid_config,name,desc,xbt_cfgelm_string,cb_set);
242 xbt_cfg_setdefault_string(name, default_value);
244 void xbt_cfg_register_boolean(const char *name, const char*default_value,xbt_cfg_cb_t cb_set, const char *desc){
245 xbt_cfg_register(&simgrid_config,name,desc,xbt_cfgelm_boolean,cb_set);
246 xbt_cfg_setdefault_boolean(name, default_value);
249 void xbt_cfg_register_alias(const char *newname, const char *oldname)
251 if (simgrid_config == NULL)
252 simgrid_config = xbt_cfg_new();
254 simgrid::config::ConfigurationElement* res = (simgrid::config::ConfigurationElement*) xbt_dict_get_or_null((xbt_dict_t) simgrid_config, oldname);
255 xbt_assert(NULL == res, "Refusing to register the option '%s' twice.", oldname);
257 res = (simgrid::config::ConfigurationElement*) xbt_dict_get_or_null((xbt_dict_t) simgrid_config, newname);
258 xbt_assert(res, "Cannot define an alias to the non-existing option '%s'.", newname);
260 res = new simgrid::config::ConfigurationElement();
261 XBT_DEBUG("Register cfg alias %s -> %s)",oldname,newname);
263 res->desc = std::string("Deprecated alias for ")+std::string(newname);
264 res->type = xbt_cfgelm_alias;
265 res->content = (xbt_dynar_t)newname;
267 xbt_dict_set((xbt_dict_t) simgrid_config, oldname, res, NULL);
271 * @brief Parse a string and register the stuff described.
273 * @param cfg the config set
274 * @param entry a string describing the element to register
276 * The string may consist in several variable descriptions separated by a space.
277 * Each of them must use the following syntax: \<name\>:\<type\>
278 * with type being one of 'string','int','bool' or 'double'.
280 * Note that this does not allow to set the description, so you should prefer the other interface
282 void xbt_cfg_register_str(xbt_cfg_t * cfg, const char *entry)
284 char *entrycpy = xbt_strdup(entry);
287 e_xbt_cfgelm_type_t type;
288 XBT_DEBUG("Register string '%s'", entry);
290 tok = strchr(entrycpy, ':');
291 xbt_assert(tok, "Invalid config element descriptor: %s; Should be <name>:<type>", entry);
294 for (type = (e_xbt_cfgelm_type_t)0; type < xbt_cfgelm_type_count && strcmp(tok, xbt_cfgelm_type_name[type]); increment(type));
295 xbt_assert(type < xbt_cfgelm_type_count,
296 "Invalid type in config element descriptor: %s; Should be one of 'string', 'int' or 'double'.", entry);
298 xbt_cfg_register(cfg, entrycpy, NULL, type, NULL);
300 free(entrycpy); /* strdup'ed by dict mechanism, but cannot be const */
303 /** @brief Displays the declared aliases and their description */
304 void xbt_cfg_aliases(void)
306 xbt_dict_cursor_t dict_cursor;
307 unsigned int dynar_cursor;
308 simgrid::config::ConfigurationElement* variable;
310 xbt_dynar_t names = xbt_dynar_new(sizeof(char *), NULL);
312 xbt_dict_foreach((xbt_dict_t )simgrid_config, dict_cursor, name, variable)
313 xbt_dynar_push(names, &name);
314 xbt_dynar_sort_strings(names);
316 xbt_dynar_foreach(names, dynar_cursor, name) {
317 variable = (simgrid::config::ConfigurationElement*) xbt_dict_get((xbt_dict_t )simgrid_config, name);
319 if (variable->type == xbt_cfgelm_alias)
320 printf(" %s: %s\n", name, variable->desc.c_str());
324 /** @brief Displays the declared options and their description */
325 void xbt_cfg_help(void)
327 xbt_dict_cursor_t dict_cursor;
328 unsigned int dynar_cursor;
329 simgrid::config::ConfigurationElement* variable;
331 xbt_dynar_t names = xbt_dynar_new(sizeof(char *), NULL);
333 xbt_dict_foreach((xbt_dict_t )simgrid_config, dict_cursor, name, variable)
334 xbt_dynar_push(names, &name);
335 xbt_dynar_sort_strings(names);
337 xbt_dynar_foreach(names, dynar_cursor, name) {
339 variable = (simgrid::config::ConfigurationElement*) xbt_dict_get((xbt_dict_t )simgrid_config, name);
340 if (variable->type == xbt_cfgelm_alias)
343 printf(" %s: %s\n", name, variable->desc.c_str());
344 printf(" Type: %s; ", xbt_cfgelm_type_name[variable->type]);
345 size = xbt_dynar_length(variable->content);
346 printf("Current value: ");
349 printf(size == 0 ? "n/a\n" : "{ ");
350 for (int i = 0; i < size; i++) {
351 const char *sep = (size == 1 ? "\n" : (i < size - 1 ? ", " : " }\n"));
353 switch (variable->type) {
355 printf("%d%s", xbt_dynar_get_as(variable->content, i, int), sep);
357 case xbt_cfgelm_double:
358 printf("%f%s", xbt_dynar_get_as(variable->content, i, double), sep);
360 case xbt_cfgelm_string:
361 printf("'%s'%s", xbt_dynar_get_as(variable->content, i, char *), sep);
363 case xbt_cfgelm_boolean: {
364 int b = xbt_dynar_get_as(variable->content, i, int);
365 const char *bs = b ? xbt_cfgelm_boolean_values[0].true_val: xbt_cfgelm_boolean_values[0].false_val;
366 if (b == 0 || b == 1)
367 printf("'%s'%s", bs, sep);
369 printf("'%s/%d'%s", bs, b, sep);
373 printf("Invalid type!!%s", sep);
378 xbt_dynar_free(&names);
381 static simgrid::config::ConfigurationElement* xbt_cfgelm_get(xbt_cfg_t cfg, const char *name, e_xbt_cfgelm_type_t type)
383 simgrid::config::ConfigurationElement* res = (simgrid::config::ConfigurationElement*) xbt_dict_get_or_null((xbt_dict_t) cfg, name);
385 // The user used the old name. Switch to the new one after a short warning
386 while (res && res->type == xbt_cfgelm_alias) {
387 const char* newname = (const char *)res->content;
388 XBT_INFO("Option %s has been renamed to %s. Consider switching.", name, newname);
389 res = xbt_cfgelm_get(cfg, newname, type);
395 THROWF(not_found_error, 0, "No registered variable '%s' in this config set.", name);
398 xbt_assert(type == xbt_cfgelm_any || res->type == type,
399 "You tried to access to the config element %s as an %s, but its type is %s.",
400 name, xbt_cfgelm_type_name[type], xbt_cfgelm_type_name[res->type]);
404 /** @brief Get the type of this variable in that configuration set
406 * @param cfg the config set
407 * @param name the name of the element
409 * @return the type of the given element
411 e_xbt_cfgelm_type_t xbt_cfg_get_type(xbt_cfg_t cfg, const char *name)
413 simgrid::config::ConfigurationElement* variable = NULL;
415 variable = (simgrid::config::ConfigurationElement*) xbt_dict_get_or_null((xbt_dict_t) cfg, name);
417 THROWF(not_found_error, 0, "Can't get the type of '%s' since this variable does not exist", name);
419 XBT_DEBUG("type in variable = %d", (int)variable->type);
420 return variable->type;
423 /*----[ Setting ]---------------------------------------------------------*/
424 /** @brief va_args version of xbt_cfg_set
426 * @param cfg config set to fill
427 * @param name variable name
428 * @param pa variable value
430 * Add some values to the config set.
432 void xbt_cfg_set_vargs(xbt_cfg_t cfg, const char *name, va_list pa)
437 e_xbt_cfgelm_type_t type = xbt_cfgelm_type_count; /* Set a dummy value to make gcc happy. It cannot get uninitialized */
442 type = xbt_cfg_get_type(cfg, name);
445 if (e.category == not_found_error) {
447 THROWF(not_found_error, 0, "Can't set the property '%s' since it's not registered", name);
453 case xbt_cfgelm_string:
454 str = va_arg(pa, char *);
455 xbt_cfg_set_string(name, str);
459 xbt_cfg_set_int(name, i);
461 case xbt_cfgelm_double:
462 d = va_arg(pa, double);
463 xbt_cfg_set_double(name, d);
465 case xbt_cfgelm_boolean:
466 str = va_arg(pa, char *);
467 xbt_cfg_set_boolean(name, str);
470 xbt_die("Config element variable %s not valid (type=%d)", name, (int)type);
474 /** @brief Add a NULL-terminated list of pairs {(char*)key, value} to the set
476 * @param cfg config set to fill
477 * @param name variable name
478 * @param ... variable value
480 void xbt_cfg_set(xbt_cfg_t cfg, const char *name, ...)
485 xbt_cfg_set_vargs(cfg, name, pa);
489 /** @brief Add values parsed from a string into a config set
491 * @param options a string containing the content to add to the config set. This is a '\\t',' ' or '\\n' or ','
492 * separated list of variables. Each individual variable is like "[name]:[value]" where [name] is the name of an
493 * already registered variable, and [value] conforms to the data type under which this variable was registered.
495 * @todo This is a crude manual parser, it should be a proper lexer.
497 void xbt_cfg_set_parse(const char *options)
499 if (!options || !strlen(options)) { /* nothing to do */
502 char *optionlist_cpy = xbt_strdup(options);
504 XBT_DEBUG("List to parse and set:'%s'", options);
505 char *option = optionlist_cpy;
506 while (1) { /* breaks in the code */
510 int len = strlen(name);
511 XBT_DEBUG("Still to parse and set: '%s'. len=%d; option-name=%ld", name, len, (long) (option - name));
514 while (option - name <= (len - 1) && *option != ' ' && *option != '\n' && *option != '\t' && *option != ',') {
515 XBT_DEBUG("Take %c.", *option);
518 if (option - name == len) {
519 XBT_DEBUG("Boundary=EOL");
520 option = NULL; /* don't do next iteration */
522 XBT_DEBUG("Boundary on '%c'. len=%d;option-name=%ld", *option, len, (long) (option - name));
523 /* Pass the following blank chars */
525 while (option - name < (len - 1) && (*option == ' ' || *option == '\n' || *option == '\t')) {
526 /* fprintf(stderr,"Ignore a blank char.\n"); */
529 if (option - name == len - 1)
530 option = NULL; /* don't do next iteration */
532 XBT_DEBUG("parse now:'%s'; parse later:'%s'", name, option);
534 if (name[0] == ' ' || name[0] == '\n' || name[0] == '\t')
539 char *val = strchr(name, ':');
540 xbt_assert(val, "Option '%s' badly formatted. Should be of the form 'name:value'", name);
541 /* don't free(optionlist_cpy) if the assert fails, 'name' points inside it */
544 if (strncmp(name, "contexts/", strlen("contexts/")) && strncmp(name, "path", strlen("path")))
545 XBT_INFO("Configuration change: Set '%s' to '%s'", name, val);
548 xbt_cfg_set_as_string(name,val);
550 free(optionlist_cpy);
554 free(optionlist_cpy);
557 /** @brief Set the value of a variable, using the string representation of that value
559 * @param key name of the variable to modify
560 * @param value string representation of the value to set
562 * @return the first char after the parsed value in val
565 void *xbt_cfg_set_as_string(const char *key, const char *value) {
569 volatile simgrid::config::ConfigurationElement* variable = NULL;
574 while (variable == NULL) {
575 variable = (simgrid::config::ConfigurationElement*) xbt_dict_get((xbt_dict_t) simgrid_config, key);
576 if (variable->type == xbt_cfgelm_alias) {
577 const char *newname = (const char*)variable->content;
578 XBT_INFO("Note: configuration '%s' is deprecated. Please use '%s' instead.", key, newname);
584 if (e.category == not_found_error) {
586 THROWF(not_found_error, 0, "No registered variable corresponding to '%s'.", key);
591 switch (variable->type) {
592 case xbt_cfgelm_string:
593 xbt_cfg_set_string(key, value); /* throws */
596 i = strtol(value, &ret, 0);
598 xbt_die("Value of option %s not valid. Should be an integer", key);
600 xbt_cfg_set_int(key, i); /* throws */
602 case xbt_cfgelm_double:
603 d = strtod(value, &ret);
605 xbt_die("Value of option %s not valid. Should be a double", key);
607 xbt_cfg_set_double(key, d); /* throws */
609 case xbt_cfgelm_boolean:
610 xbt_cfg_set_boolean(key, value); /* throws */
611 ret = (char *)value + strlen(value);
614 THROWF(unknown_error, 0, "Type of config element %s is not valid.", key);
620 /** @brief Set an integer value to \a name within \a cfg if it wasn't changed yet
622 * This is useful to change the default value of a variable while allowing
623 * users to override it with command line arguments
625 void xbt_cfg_setdefault_int(const char *name, int val)
627 simgrid::config::ConfigurationElement* variable = xbt_cfgelm_get(simgrid_config, name, xbt_cfgelm_int);
629 if (variable->isdefault){
630 xbt_cfg_set_int(name, val);
631 variable->isdefault = true;
633 XBT_DEBUG("Do not override configuration variable '%s' with value '%d' because it was already set.", name, val);
636 /** @brief Set an integer value to \a name within \a cfg if it wasn't changed yet
638 * This is useful to change the default value of a variable while allowing
639 * users to override it with command line arguments
641 void xbt_cfg_setdefault_double(const char *name, double val)
643 simgrid::config::ConfigurationElement* variable = xbt_cfgelm_get(simgrid_config, name, xbt_cfgelm_double);
645 if (variable->isdefault) {
646 xbt_cfg_set_double(name, val);
647 variable->isdefault = true;
649 XBT_DEBUG("Do not override configuration variable '%s' with value '%f' because it was already set.", name, val);
652 /** @brief Set a string value to \a name within \a cfg if it wasn't changed yet
654 * This is useful to change the default value of a variable while allowing
655 * users to override it with command line arguments
657 void xbt_cfg_setdefault_string(const char *name, const char *val)
659 simgrid::config::ConfigurationElement* variable = xbt_cfgelm_get(simgrid_config, name, xbt_cfgelm_string);
661 if (variable->isdefault){
662 xbt_cfg_set_string(name, val);
663 variable->isdefault = true;
665 XBT_DEBUG("Do not override configuration variable '%s' with value '%s' because it was already set.", name, val);
668 /** @brief Set an boolean value to \a name within \a cfg if it wasn't changed yet
670 * This is useful to change the default value of a variable while allowing
671 * users to override it with command line arguments
673 void xbt_cfg_setdefault_boolean(const char *name, const char *val)
675 simgrid::config::ConfigurationElement* variable = xbt_cfgelm_get(simgrid_config, name, xbt_cfgelm_boolean);
677 if (variable->isdefault){
678 xbt_cfg_set_boolean(name, val);
679 variable->isdefault = true;
682 XBT_DEBUG("Do not override configuration variable '%s' with value '%s' because it was already set.", name, val);
685 /** @brief Set an integer value to \a name within \a cfg
687 * @param name the name of the variable
688 * @param val the value of the variable
690 void xbt_cfg_set_int(const char *name, int val)
692 simgrid::config::ConfigurationElement* variable = xbt_cfgelm_get(simgrid_config, name, xbt_cfgelm_int);
694 xbt_dynar_set(variable->content, 0, &val);
696 if (variable->cb_set)
697 variable->cb_set(name);
698 variable->isdefault = false;
701 /** @brief Set or add a double value to \a name within \a cfg
703 * @param name the name of the variable
704 * @param val the double to set
706 void xbt_cfg_set_double(const char *name, double val)
708 simgrid::config::ConfigurationElement* variable = xbt_cfgelm_get(simgrid_config, name, xbt_cfgelm_double);
710 xbt_dynar_set(variable->content, 0, &val);
712 if (variable->cb_set)
713 variable->cb_set(name);
714 variable->isdefault = false;
717 /** @brief Set or add a string value to \a name within \a cfg
719 * @param cfg the config set
720 * @param name the name of the variable
721 * @param val the value to be added
724 void xbt_cfg_set_string(const char *name, const char *val)
726 char *newval = xbt_strdup(val);
727 simgrid::config::ConfigurationElement* variable = xbt_cfgelm_get(simgrid_config, name, xbt_cfgelm_string);
729 if (!xbt_dynar_is_empty(variable->content)) {
730 char *sval = xbt_dynar_get_as(variable->content, 0, char *);
734 xbt_dynar_set(variable->content, 0, &newval);
736 if (variable->cb_set)
737 variable->cb_set(name);
739 if (variable->callback) {
741 variable->callback(val);
743 catch(std::range_error& e) {
744 xbt_die("Invalid flag %s=%s: %s", val, name, e.what());
746 catch(std::exception& e) {
747 xbt_die("Error for flag %s=%s: %s", val, name, e.what());
750 xbt_die("Error for flag %s=%s", val, name);
754 variable->isdefault = false;
757 /** @brief Set or add a boolean value to \a name within \a cfg
759 * @param name the name of the variable
760 * @param val the value of the variable
762 void xbt_cfg_set_boolean(const char *name, const char *val)
765 simgrid::config::ConfigurationElement* variable = xbt_cfgelm_get(simgrid_config, name, xbt_cfgelm_boolean);
767 for (int i = 0; xbt_cfgelm_boolean_values[i].true_val != NULL; i++) {
768 if (strcmp(val, xbt_cfgelm_boolean_values[i].true_val) == 0){
772 if (strcmp(val, xbt_cfgelm_boolean_values[i].false_val) == 0){
777 xbt_assert(bval != -1, "Value of option '%s' not valid. Should be a boolean (yes,no,on,off,true,false,0,1)", val);
778 xbt_dynar_set(variable->content, 0, &bval);
780 if (variable->cb_set)
781 variable->cb_set(name);
782 variable->isdefault = false;
786 /* Say if the value is the default value */
787 int xbt_cfg_is_default_value(const char *name)
789 simgrid::config::ConfigurationElement* variable = xbt_cfgelm_get(simgrid_config, name, xbt_cfgelm_any);
790 return variable->isdefault;
793 /*----[ Getting ]---------------------------------------------------------*/
794 /** @brief Retrieve an integer value of a variable (get a warning if not uniq)
796 * @param name the name of the variable
798 * Returns the first value from the config set under the given name.
799 * If there is more than one value, it will issue a warning. Consider using xbt_cfg_get_dynar() instead.
801 int xbt_cfg_get_int(const char *name)
803 simgrid::config::ConfigurationElement* variable = xbt_cfgelm_get(simgrid_config, name, xbt_cfgelm_int);
805 if (xbt_dynar_length(variable->content) > 1) {
806 XBT_WARN("You asked for the first value of the config element '%s', but there is %lu values",
807 name, xbt_dynar_length(variable->content));
810 return xbt_dynar_get_as(variable->content, 0, int);
813 /** @brief Retrieve a double value of a variable (get a warning if not uniq)
815 * @param cfg the config set
816 * @param name the name of the variable
818 * Returns the first value from the config set under the given name.
819 * If there is more than one value, it will issue a warning. Consider using xbt_cfg_get_dynar() instead.
821 double xbt_cfg_get_double(const char *name)
823 simgrid::config::ConfigurationElement* variable = xbt_cfgelm_get(simgrid_config, name, xbt_cfgelm_double);
825 if (xbt_dynar_length(variable->content) > 1) {
826 XBT_WARN ("You asked for the first value of the config element '%s', but there is %lu values\n",
827 name, xbt_dynar_length(variable->content));
830 return xbt_dynar_get_as(variable->content, 0, double);
833 /** @brief Retrieve a string value of a variable (get a warning if not uniq)
835 * @param cfg the config set
836 * @param name the name of the variable
838 * Returns the first value from the config set under the given name.
839 * If there is more than one value, it will issue a warning. Consider using
840 * xbt_cfg_get_dynar() instead. Returns NULL if there is no value.
842 * \warning the returned value is the actual content of the config set
844 char *xbt_cfg_get_string(const char *name)
846 simgrid::config::ConfigurationElement* variable = xbt_cfgelm_get(simgrid_config, name, xbt_cfgelm_string);
848 if (xbt_dynar_length(variable->content) > 1) {
849 XBT_WARN("You asked for the first value of the config element '%s', but there is %lu values\n",
850 name, xbt_dynar_length(variable->content));
851 } else if (xbt_dynar_is_empty(variable->content)) {
855 return xbt_dynar_get_as(variable->content, 0, char *);
858 /** @brief Retrieve a boolean value of a variable (get a warning if not uniq)
860 * @param cfg the config set
861 * @param name the name of the variable
863 * Returns the first value from the config set under the given name.
864 * If there is more than one value, it will issue a warning. Consider using xbt_cfg_get_dynar() instead.
866 int xbt_cfg_get_boolean(const char *name)
868 simgrid::config::ConfigurationElement* variable = xbt_cfgelm_get(simgrid_config, name, xbt_cfgelm_boolean);
870 if (xbt_dynar_length(variable->content) > 1) {
871 XBT_WARN("You asked for the first value of the config element '%s', but there is %lu values",
872 name, xbt_dynar_length(variable->content));
875 return xbt_dynar_get_as(variable->content, 0, int);
881 bool parseBool(const char* value)
883 for (int i = 0; xbt_cfgelm_boolean_values[i].true_val != NULL; i++) {
884 if (std::strcmp(value, xbt_cfgelm_boolean_values[i].true_val) == 0)
886 if (std::strcmp(value, xbt_cfgelm_boolean_values[i].false_val) == 0)
889 throw std::range_error("not a boolean");
892 double parseDouble(const char* value)
896 double res = std::strtod(value, &end);
898 throw std::range_error("out of range");
900 xbt_die("Unexpected errno");
901 if (end == value || *end != '\0')
902 throw std::range_error("invalid double");
907 long int parseLong(const char* value)
911 long int res = std::strtol(value, &end, 0);
913 if (res == LONG_MIN && errno == ERANGE)
914 throw std::range_error("underflow");
915 else if (res == LONG_MAX && errno == ERANGE)
916 throw std::range_error("overflow");
917 xbt_die("Unexpected errno");
919 if (end == value || *end != '\0')
920 throw std::range_error("invalid integer");
925 void declareFlag(const char* name, const char* description,
926 std::function<void(const char* value)> callback)
928 xbt_cfg_register(&simgrid_config, name, description, xbt_cfgelm_string, NULL,
929 std::move(callback));
942 #include <xbt/config.hpp>
944 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(xbt_cfg);
946 XBT_TEST_SUITE("config", "Configuration support");
948 static xbt_cfg_t make_set()
950 xbt_cfg_t set = NULL;
952 xbt_log_threshold_set(&_XBT_LOGV(xbt_cfg), xbt_log_priority_critical);
953 xbt_cfg_register_str(&set, "speed:int");
954 xbt_cfg_register_str(&set, "peername:string");
955 xbt_cfg_register_str(&set, "user:string");
958 } /* end_of_make_set */
960 XBT_PUBLIC_DATA(xbt_cfg_t) simgrid_config;
962 XBT_TEST_UNIT("memuse", test_config_memuse, "Alloc and free a config set")
964 simgrid_config = make_set();
965 xbt_test_add("Alloc and free a config set");
966 xbt_cfg_set_parse("peername:veloce user:bidule");
967 xbt_cfg_free(&simgrid_config);
970 XBT_TEST_UNIT("use", test_config_use, "Data retrieving tests")
972 simgrid_config = make_set();
973 xbt_test_add("Get a single value");
975 /* get_single_value */
978 xbt_cfg_set_parse("peername:toto:42 speed:42");
979 ival = xbt_cfg_get_int("speed");
981 xbt_test_fail("Speed value = %d, I expected 42", ival);
984 xbt_test_add("Access to a non-existant entry");
989 xbt_cfg_set_parse("color:blue");
991 if (e.category != not_found_error)
992 xbt_test_exception(e);
996 xbt_cfg_free(&simgrid_config);
999 XBT_TEST_UNIT("c++flags", test_config_cxx_flags, "C++ flags")
1001 simgrid_config = make_set();
1002 xbt_test_add("C++ declaration of flags");
1004 simgrid::config::Flag<int> int_flag("int", "", 0);
1005 simgrid::config::Flag<std::string> string_flag("string", "", "foo");
1006 simgrid::config::Flag<double> double_flag("double", "", 0.32);
1007 simgrid::config::Flag<bool> bool_flag1("bool1", "", false);
1008 simgrid::config::Flag<bool> bool_flag2("bool2", "", true);
1010 xbt_test_add("Parse values");
1011 xbt_cfg_set_parse("int:42 string:bar double:8.0 bool1:true bool2:false");
1012 xbt_test_assert(int_flag == 42, "Check int flag");
1013 xbt_test_assert(string_flag == "bar", "Check string flag");
1014 xbt_test_assert(double_flag == 8.0, "Check double flag");
1015 xbt_test_assert(bool_flag1, "Check bool1 flag");
1016 xbt_test_assert(!bool_flag2, "Check bool2 flag");
1018 xbt_cfg_free(&simgrid_config);
1021 #endif /* SIMGRID_TEST */