type_defs.c (20912B)
1 /* Copyright (c) 2001 Matej Pfajfar. 2 * Copyright (c) 2001-2004, Roger Dingledine. 3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. 4 * Copyright (c) 2007-2021, The Tor Project, Inc. */ 5 /* See LICENSE for licensing information */ 6 7 /** 8 * @file type_defs.c 9 * @brief Definitions for various low-level configuration types. 10 * 11 * This module creates a number of var_type_def_t objects, to be used by 12 * typedvar.c in manipulating variables. 13 * 14 * The types here are common types that can be implemented with Tor's 15 * low-level functionality. To define new types, see var_type_def_st.h. 16 **/ 17 18 #include "orconfig.h" 19 #include "lib/conf/conftypes.h" 20 #include "lib/conf/confdecl.h" 21 #include "lib/confmgt/typedvar.h" 22 #include "lib/confmgt/type_defs.h" 23 #include "lib/confmgt/unitparse.h" 24 25 #include "lib/cc/compat_compiler.h" 26 #include "lib/container/smartlist.h" 27 #include "lib/encoding/confline.h" 28 #include "lib/encoding/time_fmt.h" 29 #include "lib/log/escape.h" 30 #include "lib/log/log.h" 31 #include "lib/log/util_bug.h" 32 #include "lib/malloc/malloc.h" 33 #include "lib/string/parse_int.h" 34 #include "lib/string/printf.h" 35 36 #include "lib/confmgt/var_type_def_st.h" 37 38 #include <stddef.h> 39 #include <string.h> 40 #include <errno.h> 41 42 ////// 43 // CONFIG_TYPE_STRING 44 // CONFIG_TYPE_FILENAME 45 // 46 // These two types are the same for now, but they have different names. 47 // 48 // Warning: For this type, the default value (NULL) and "" are considered 49 // different values. That is generally risky, and best avoided for other 50 // types in the future. 51 ////// 52 53 static int 54 string_parse(void *target, const char *value, char **errmsg, 55 const void *params) 56 { 57 (void)params; 58 (void)errmsg; 59 char **p = (char**)target; 60 *p = tor_strdup(value); 61 return 0; 62 } 63 64 static char * 65 string_encode(const void *value, const void *params) 66 { 67 (void)params; 68 const char **p = (const char**)value; 69 return *p ? tor_strdup(*p) : NULL; 70 } 71 72 static void 73 string_clear(void *value, const void *params) 74 { 75 (void)params; 76 char **p = (char**)value; 77 tor_free(*p); // sets *p to NULL. 78 } 79 80 static const var_type_fns_t string_fns = { 81 .parse = string_parse, 82 .encode = string_encode, 83 .clear = string_clear, 84 }; 85 86 ///// 87 // CONFIG_TYPE_INT 88 // CONFIG_TYPE_POSINT 89 // 90 // These types are implemented as int, possibly with a restricted range. 91 ///// 92 93 /** 94 * Parameters for parsing an integer type. 95 **/ 96 typedef struct int_type_params_t { 97 int minval; /**< Lowest allowed value */ 98 int maxval; /**< Highest allowed value */ 99 } int_parse_params_t; 100 101 static const int_parse_params_t INT_PARSE_UNRESTRICTED = { 102 .minval = INT_MIN, 103 .maxval = INT_MAX, 104 }; 105 106 static const int_parse_params_t INT_PARSE_POSINT = { 107 .minval = 0, 108 .maxval = INT_MAX, 109 }; 110 111 static int 112 int_parse(void *target, const char *value, char **errmsg, const void *params) 113 { 114 const int_parse_params_t *pp; 115 if (params) { 116 pp = params; 117 } else { 118 pp = &INT_PARSE_UNRESTRICTED; 119 } 120 int *p = target; 121 int ok=0; 122 *p = (int)tor_parse_long(value, 10, pp->minval, pp->maxval, &ok, NULL); 123 if (!ok) { 124 tor_asprintf(errmsg, "Integer %s is malformed or out of bounds. " 125 "Allowed values are between %d and %d.", 126 value, pp->minval, pp->maxval); 127 return -1; 128 } 129 return 0; 130 } 131 132 static char * 133 int_encode(const void *value, const void *params) 134 { 135 (void)params; 136 int v = *(int*)value; 137 char *result; 138 tor_asprintf(&result, "%d", v); 139 return result; 140 } 141 142 static void 143 int_clear(void *value, const void *params) 144 { 145 (void)params; 146 *(int*)value = 0; 147 } 148 149 static bool 150 int_ok(const void *value, const void *params) 151 { 152 const int_parse_params_t *pp = params; 153 if (pp) { 154 int v = *(int*)value; 155 return pp->minval <= v && v <= pp->maxval; 156 } else { 157 return true; 158 } 159 } 160 161 static const var_type_fns_t int_fns = { 162 .parse = int_parse, 163 .encode = int_encode, 164 .clear = int_clear, 165 .ok = int_ok, 166 }; 167 168 ///// 169 // CONFIG_TYPE_UINT64 170 // 171 // This type is an unrestricted u64. 172 ///// 173 174 static int 175 uint64_parse(void *target, const char *value, char **errmsg, 176 const void *params) 177 { 178 (void)params; 179 (void)errmsg; 180 uint64_t *p = target; 181 int ok=0; 182 *p = tor_parse_uint64(value, 10, 0, UINT64_MAX, &ok, NULL); 183 if (!ok) { 184 tor_asprintf(errmsg, "Integer %s is malformed or out of bounds.", 185 value); 186 return -1; 187 } 188 return 0; 189 } 190 191 static char * 192 uint64_encode(const void *value, const void *params) 193 { 194 (void)params; 195 uint64_t v = *(uint64_t*)value; 196 char *result; 197 tor_asprintf(&result, "%"PRIu64, v); 198 return result; 199 } 200 201 static void 202 uint64_clear(void *value, const void *params) 203 { 204 (void)params; 205 *(uint64_t*)value = 0; 206 } 207 208 static const var_type_fns_t uint64_fns = { 209 .parse = uint64_parse, 210 .encode = uint64_encode, 211 .clear = uint64_clear, 212 }; 213 214 ///// 215 // CONFIG_TYPE_INTERVAL 216 // CONFIG_TYPE_MSEC_INTERVAL 217 // CONFIG_TYPE_MEMUNIT 218 // 219 // These types are implemented using the config_parse_units() function. 220 // The intervals are stored as ints, whereas memory units are stored as 221 // uint64_ts. 222 ///// 223 224 static int 225 units_parse_u64(void *target, const char *value, char **errmsg, 226 const void *params) 227 { 228 const unit_table_t *table = params; 229 tor_assert(table); 230 uint64_t *v = (uint64_t*)target; 231 int ok=1; 232 char *msg = NULL; 233 *v = config_parse_units(value, table, &ok, &msg); 234 if (!ok) { 235 tor_asprintf(errmsg, "Provided value is malformed or out of bounds: %s", 236 msg); 237 tor_free(msg); 238 return -1; 239 } 240 if (BUG(msg)) { 241 tor_free(msg); 242 } 243 return 0; 244 } 245 246 static int 247 units_parse_int(void *target, const char *value, char **errmsg, 248 const void *params) 249 { 250 const unit_table_t *table = params; 251 tor_assert(table); 252 int *v = (int*)target; 253 int ok=1; 254 char *msg = NULL; 255 uint64_t u64 = config_parse_units(value, table, &ok, &msg); 256 if (!ok) { 257 tor_asprintf(errmsg, "Provided value is malformed or out of bounds: %s", 258 msg); 259 tor_free(msg); 260 return -1; 261 } 262 if (BUG(msg)) { 263 tor_free(msg); 264 } 265 if (u64 > INT_MAX) { 266 tor_asprintf(errmsg, "Provided value %s is too large", value); 267 return -1; 268 } 269 *v = (int) u64; 270 return 0; 271 } 272 273 static bool 274 units_ok_int(const void *value, const void *params) 275 { 276 (void)params; 277 int v = *(int*)value; 278 return v >= 0; 279 } 280 281 static const var_type_fns_t memunit_fns = { 282 .parse = units_parse_u64, 283 .encode = uint64_encode, // doesn't use params 284 .clear = uint64_clear, // doesn't use params 285 }; 286 287 static const var_type_fns_t interval_fns = { 288 .parse = units_parse_int, 289 .encode = int_encode, // doesn't use params 290 .clear = int_clear, // doesn't use params, 291 .ok = units_ok_int // can't use int_ok, since that expects int params. 292 }; 293 294 ///// 295 // CONFIG_TYPE_DOUBLE 296 // 297 // This is a nice simple double. 298 ///// 299 300 static int 301 double_parse(void *target, const char *value, char **errmsg, 302 const void *params) 303 { 304 (void)params; 305 (void)errmsg; 306 double *v = (double*)target; 307 char *endptr=NULL; 308 errno = 0; 309 *v = strtod(value, &endptr); 310 if (endptr == value || *endptr != '\0') { 311 // Either there are no converted characters, or there were some characters 312 // that didn't get converted. 313 tor_asprintf(errmsg, "Could not convert %s to a number.", escaped(value)); 314 return -1; 315 } 316 if (errno == ERANGE) { 317 // strtod will set errno to ERANGE on underflow or overflow. 318 bool underflow = -.00001 < *v && *v < .00001; 319 tor_asprintf(errmsg, 320 "%s is too %s to express as a floating-point number.", 321 escaped(value), underflow ? "small" : "large"); 322 return -1; 323 } 324 return 0; 325 } 326 327 static char * 328 double_encode(const void *value, const void *params) 329 { 330 (void)params; 331 double v = *(double*)value; 332 char *result; 333 tor_asprintf(&result, "%f", v); 334 return result; 335 } 336 337 static void 338 double_clear(void *value, const void *params) 339 { 340 (void)params; 341 double *v = (double *)value; 342 *v = 0.0; 343 } 344 345 static const var_type_fns_t double_fns = { 346 .parse = double_parse, 347 .encode = double_encode, 348 .clear = double_clear, 349 }; 350 351 ///// 352 // CONFIG_TYPE_BOOL 353 // CONFIG_TYPE_AUTOBOOL 354 // 355 // These types are implemented as a case-insensitive string-to-integer 356 // mapping. 357 ///// 358 359 typedef struct enumeration_table_t { 360 const char *name; 361 int value; 362 } enumeration_table_t; 363 364 typedef struct enumeration_params_t { 365 const char *allowed_val_string; 366 const enumeration_table_t *table; 367 } enumeration_params_t; 368 369 static int 370 enum_parse(void *target, const char *value, char **errmsg, 371 const void *params_) 372 { 373 const enumeration_params_t *params = params_; 374 const enumeration_table_t *table = params->table; 375 int *p = (int *)target; 376 for (; table->name; ++table) { 377 if (!strcasecmp(value, table->name)) { 378 *p = table->value; 379 return 0; 380 } 381 } 382 tor_asprintf(errmsg, "Unrecognized value %s. %s", 383 value, params->allowed_val_string); 384 return -1; 385 } 386 387 static char * 388 enum_encode(const void *value, const void *params_) 389 { 390 int v = *(const int*)value; 391 const enumeration_params_t *params = params_; 392 const enumeration_table_t *table = params->table; 393 for (; table->name; ++table) { 394 if (v == table->value) 395 return tor_strdup(table->name); 396 } 397 return NULL; // error. 398 } 399 400 static void 401 enum_clear(void *value, const void *params_) 402 { 403 int *p = (int*)value; 404 const enumeration_params_t *params = params_; 405 const enumeration_table_t *table = params->table; 406 tor_assert(table->name); 407 *p = table->value; 408 } 409 410 static bool 411 enum_ok(const void *value, const void *params_) 412 { 413 int v = *(const int*)value; 414 const enumeration_params_t *params = params_; 415 const enumeration_table_t *table = params->table; 416 for (; table->name; ++table) { 417 if (v == table->value) 418 return true; 419 } 420 return false; 421 } 422 423 static const enumeration_table_t enum_table_bool[] = { 424 { "0", 0 }, 425 { "1", 1 }, 426 { NULL, 0 }, 427 }; 428 429 static const enumeration_params_t enum_params_bool = { 430 "Allowed values are 0 and 1.", 431 enum_table_bool 432 }; 433 434 static const enumeration_table_t enum_table_autobool[] = { 435 { "0", 0 }, 436 { "1", 1 }, 437 { "auto", -1 }, 438 { NULL, 0 }, 439 }; 440 441 static const enumeration_params_t enum_params_autobool = { 442 "Allowed values are 0, 1, and auto.", 443 enum_table_autobool 444 }; 445 446 static const var_type_fns_t enum_fns = { 447 .parse = enum_parse, 448 .encode = enum_encode, 449 .clear = enum_clear, 450 .ok = enum_ok, 451 }; 452 453 ///// 454 // CONFIG_TYPE_ISOTIME 455 // 456 // This is a time_t, encoded in ISO8601 format. 457 ///// 458 459 static int 460 time_parse(void *target, const char *value, char **errmsg, 461 const void *params) 462 { 463 (void) params; 464 time_t *p = target; 465 if (parse_iso_time(value, p) < 0) { 466 tor_asprintf(errmsg, "Invalid time %s", escaped(value)); 467 return -1; 468 } 469 return 0; 470 } 471 472 static char * 473 time_encode(const void *value, const void *params) 474 { 475 (void)params; 476 time_t v = *(const time_t *)value; 477 char *result = tor_malloc(ISO_TIME_LEN+1); 478 format_iso_time(result, v); 479 return result; 480 } 481 482 static void 483 time_clear(void *value, const void *params) 484 { 485 (void)params; 486 time_t *t = value; 487 *t = 0; 488 } 489 490 static const var_type_fns_t time_fns = { 491 .parse = time_parse, 492 .encode = time_encode, 493 .clear = time_clear, 494 }; 495 496 ///// 497 // CONFIG_TYPE_CSV 498 // 499 // This type is a comma-separated list of strings, stored in a smartlist_t. 500 // An empty list may be encoded either as an empty smartlist, or as NULL. 501 ///// 502 503 static int 504 csv_parse(void *target, const char *value, char **errmsg, 505 const void *params) 506 { 507 (void)params; 508 (void)errmsg; 509 smartlist_t **sl = (smartlist_t**)target; 510 *sl = smartlist_new(); 511 smartlist_split_string(*sl, value, ",", 512 SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); 513 return 0; 514 } 515 516 static char * 517 csv_encode(const void *value, const void *params) 518 { 519 (void)params; 520 const smartlist_t *sl = *(const smartlist_t **)value; 521 if (! sl) 522 return tor_strdup(""); 523 524 return smartlist_join_strings(*(smartlist_t**)value, ",", 0, NULL); 525 } 526 527 static void 528 csv_clear(void *value, const void *params) 529 { 530 (void)params; 531 smartlist_t **sl = (smartlist_t**)value; 532 if (!*sl) 533 return; 534 SMARTLIST_FOREACH(*sl, char *, cp, tor_free(cp)); 535 smartlist_free(*sl); // clears pointer. 536 } 537 538 static const var_type_fns_t csv_fns = { 539 .parse = csv_parse, 540 .encode = csv_encode, 541 .clear = csv_clear, 542 }; 543 544 ///// 545 // CONFIG_TYPE_CSV_INTERVAL 546 // 547 // This type used to be a list of time intervals, used to determine a download 548 // schedule. Now, only the first interval counts: everything after the first 549 // comma is discarded. 550 ///// 551 552 static int 553 legacy_csv_interval_parse(void *target, const char *value, char **errmsg, 554 const void *params) 555 { 556 (void)params; 557 /* We used to have entire smartlists here. But now that all of our 558 * download schedules use exponential backoff, only the first part 559 * matters. */ 560 const char *comma = strchr(value, ','); 561 const char *val = value; 562 char *tmp = NULL; 563 if (comma) { 564 tmp = tor_strndup(val, comma - val); 565 val = tmp; 566 } 567 568 int rv = units_parse_int(target, val, errmsg, &time_units); 569 tor_free(tmp); 570 return rv; 571 } 572 573 static const var_type_fns_t legacy_csv_interval_fns = { 574 .parse = legacy_csv_interval_parse, 575 .encode = int_encode, 576 .clear = int_clear, 577 }; 578 579 ///// 580 // CONFIG_TYPE_LINELIST 581 // CONFIG_TYPE_LINELIST_S 582 // CONFIG_TYPE_LINELIST_V 583 // 584 // A linelist is a raw config_line_t list. Order is preserved. 585 // 586 // The LINELIST type is used for homogeneous lists, where all the lines 587 // have the same key. 588 // 589 // The LINELIST_S and LINELIST_V types are used for the case where multiple 590 // lines of different keys are kept in a single list, to preserve their 591 // relative order. The unified list is stored as a "virtual" variable whose 592 // type is LINELIST_V; the individual sublists are treated as variables of 593 // type LINELIST_S. 594 // 595 // A linelist may be fragile or non-fragile. Assigning a line to a fragile 596 // linelist replaces the list with the line. If the line has the "APPEND" 597 // command set on it, or if the list is non-fragile, the line is appended. 598 // Either way, the new list is non-fragile. 599 ///// 600 601 static int 602 linelist_kv_parse(void *target, const struct config_line_t *line, 603 char **errmsg, const void *params) 604 { 605 (void)params; 606 (void)errmsg; 607 config_line_t **lines = target; 608 609 if (*lines && (*lines)->fragile) { 610 if (line->command == CONFIG_LINE_APPEND) { 611 (*lines)->fragile = 0; 612 } else { 613 config_free_lines(*lines); // sets it to NULL 614 } 615 } 616 617 config_line_append(lines, line->key, line->value); 618 return 0; 619 } 620 621 static int 622 linelist_kv_virt_noparse(void *target, const struct config_line_t *line, 623 char **errmsg, const void *params) 624 { 625 (void)target; 626 (void)line; 627 (void)params; 628 *errmsg = tor_strdup("Cannot assign directly to virtual option."); 629 return -1; 630 } 631 632 static struct config_line_t * 633 linelist_kv_encode(const char *key, const void *value, 634 const void *params) 635 { 636 (void)key; 637 (void)params; 638 config_line_t *lines = *(config_line_t **)value; 639 return config_lines_dup(lines); 640 } 641 642 static struct config_line_t * 643 linelist_s_kv_encode(const char *key, const void *value, 644 const void *params) 645 { 646 (void)params; 647 config_line_t *lines = *(config_line_t **)value; 648 return config_lines_dup_and_filter(lines, key); 649 } 650 651 static void 652 linelist_clear(void *target, const void *params) 653 { 654 (void)params; 655 config_line_t **lines = target; 656 config_free_lines(*lines); // sets it to NULL 657 } 658 659 static bool 660 linelist_eq(const void *a, const void *b, const void *params) 661 { 662 (void)params; 663 const config_line_t *lines_a = *(const config_line_t **)a; 664 const config_line_t *lines_b = *(const config_line_t **)b; 665 return config_lines_eq(lines_a, lines_b); 666 } 667 668 static int 669 linelist_copy(void *target, const void *value, const void *params) 670 { 671 (void)params; 672 config_line_t **ptr = (config_line_t **)target; 673 const config_line_t *val = *(const config_line_t **)value; 674 config_free_lines(*ptr); 675 *ptr = config_lines_dup(val); 676 return 0; 677 } 678 679 static void 680 linelist_mark_fragile(void *target, const void *params) 681 { 682 (void)params; 683 config_line_t **ptr = (config_line_t **)target; 684 if (*ptr) 685 (*ptr)->fragile = 1; 686 } 687 688 static const var_type_fns_t linelist_fns = { 689 .kv_parse = linelist_kv_parse, 690 .kv_encode = linelist_kv_encode, 691 .clear = linelist_clear, 692 .eq = linelist_eq, 693 .copy = linelist_copy, 694 .mark_fragile = linelist_mark_fragile, 695 }; 696 697 static const var_type_fns_t linelist_v_fns = { 698 .kv_parse = linelist_kv_virt_noparse, 699 .kv_encode = linelist_kv_encode, 700 .clear = linelist_clear, 701 .eq = linelist_eq, 702 .copy = linelist_copy, 703 .mark_fragile = linelist_mark_fragile, 704 }; 705 706 static const var_type_fns_t linelist_s_fns = { 707 .kv_parse = linelist_kv_parse, 708 .kv_encode = linelist_s_kv_encode, 709 .clear = linelist_clear, 710 .eq = linelist_eq, 711 .copy = linelist_copy, 712 }; 713 714 ///// 715 // CONFIG_TYPE_ROUTERSET 716 // 717 // XXXX to this module. 718 ///// 719 720 ///// 721 // CONFIG_TYPE_IGNORE 722 // 723 // Used to indicate an option that cannot be stored or encoded. 724 ///// 725 726 static int 727 ignore_parse(void *target, const char *value, char **errmsg, 728 const void *params) 729 { 730 (void)target; 731 (void)value; 732 (void)errmsg; 733 (void)params; 734 return 0; 735 } 736 737 static char * 738 ignore_encode(const void *value, const void *params) 739 { 740 (void)value; 741 (void)params; 742 return NULL; 743 } 744 745 static const var_type_fns_t ignore_fns = { 746 .parse = ignore_parse, 747 .encode = ignore_encode, 748 }; 749 750 const var_type_def_t STRING_type_defn = { 751 .name="String", .fns=&string_fns }; 752 const var_type_def_t FILENAME_type_defn = { 753 .name="Filename", .fns=&string_fns }; 754 const var_type_def_t INT_type_defn = { 755 .name="SignedInteger", .fns=&int_fns, 756 .params=&INT_PARSE_UNRESTRICTED }; 757 const var_type_def_t POSINT_type_defn = { 758 .name="Integer", .fns=&int_fns, 759 .params=&INT_PARSE_POSINT }; 760 const var_type_def_t UINT64_type_defn = { 761 .name="Integer", .fns=&uint64_fns, }; 762 const var_type_def_t MEMUNIT_type_defn = { 763 .name="DataSize", .fns=&memunit_fns, 764 .params=&memory_units }; 765 const var_type_def_t INTERVAL_type_defn = { 766 .name="TimeInterval", .fns=&interval_fns, 767 .params=&time_units }; 768 const var_type_def_t MSEC_INTERVAL_type_defn = { 769 .name="TimeMsecInterval", 770 .fns=&interval_fns, 771 .params=&time_msec_units }; 772 const var_type_def_t DOUBLE_type_defn = { 773 .name="Float", .fns=&double_fns, }; 774 const var_type_def_t BOOL_type_defn = { 775 .name="Boolean", .fns=&enum_fns, 776 .params=&enum_params_bool }; 777 const var_type_def_t AUTOBOOL_type_defn = { 778 .name="Boolean+Auto", .fns=&enum_fns, 779 .params=&enum_params_autobool }; 780 const var_type_def_t ISOTIME_type_defn = { 781 .name="Time", .fns=&time_fns, }; 782 const var_type_def_t CSV_type_defn = { 783 .name="CommaList", .fns=&csv_fns, }; 784 const var_type_def_t CSV_INTERVAL_type_defn = { 785 .name="TimeInterval", 786 .fns=&legacy_csv_interval_fns, }; 787 const var_type_def_t LINELIST_type_defn = { 788 .name="LineList", .fns=&linelist_fns, 789 .flags=CFLG_NOREPLACE }; 790 /* 791 * A "linelist_s" is a derived view of a linelist_v: inspecting 792 * it gets part of a linelist_v, and setting it adds to the linelist_v. 793 */ 794 const var_type_def_t LINELIST_S_type_defn = { 795 .name="Dependent", .fns=&linelist_s_fns, 796 .flags=CFLG_NOREPLACE| 797 /* The operations we disable here are 798 * handled by the linelist_v. */ 799 CFLG_NOCOPY|CFLG_NOCMP|CFLG_NODUMP }; 800 const var_type_def_t LINELIST_V_type_defn = { 801 .name="Virtual", .fns=&linelist_v_fns, 802 .flags=CFLG_NOREPLACE|CFLG_NOSET }; 803 const var_type_def_t IGNORE_type_defn = { 804 .name="Ignored", .fns=&ignore_fns, 805 .flags=CFLG_NOCOPY|CFLG_NOCMP|CFLG_NODUMP|CFLG_NOSET, 806 }; 807 const var_type_def_t OBSOLETE_type_defn = { 808 .name="Obsolete", .fns=&ignore_fns, 809 .flags=CFLG_GROUP_OBSOLETE, 810 }; 811 812 /** 813 * Table mapping conf_type_t values to var_type_def_t objects. 814 **/ 815 static const var_type_def_t *type_definitions_table[] = { 816 [CONFIG_TYPE_STRING] = &STRING_type_defn, 817 [CONFIG_TYPE_FILENAME] = &FILENAME_type_defn, 818 [CONFIG_TYPE_INT] = &INT_type_defn, 819 [CONFIG_TYPE_POSINT] = &POSINT_type_defn, 820 [CONFIG_TYPE_UINT64] = &UINT64_type_defn, 821 [CONFIG_TYPE_MEMUNIT] = &MEMUNIT_type_defn, 822 [CONFIG_TYPE_INTERVAL] = &INTERVAL_type_defn, 823 [CONFIG_TYPE_MSEC_INTERVAL] = &MSEC_INTERVAL_type_defn, 824 [CONFIG_TYPE_DOUBLE] = &DOUBLE_type_defn, 825 [CONFIG_TYPE_BOOL] = &BOOL_type_defn, 826 [CONFIG_TYPE_AUTOBOOL] = &AUTOBOOL_type_defn, 827 [CONFIG_TYPE_ISOTIME] = &ISOTIME_type_defn, 828 [CONFIG_TYPE_CSV] = &CSV_type_defn, 829 [CONFIG_TYPE_CSV_INTERVAL] = &CSV_INTERVAL_type_defn, 830 [CONFIG_TYPE_LINELIST] = &LINELIST_type_defn, 831 [CONFIG_TYPE_LINELIST_S] = &LINELIST_S_type_defn, 832 [CONFIG_TYPE_LINELIST_V] = &LINELIST_V_type_defn, 833 [CONFIG_TYPE_IGNORE] = &IGNORE_type_defn, 834 [CONFIG_TYPE_OBSOLETE] = &OBSOLETE_type_defn, 835 }; 836 837 /** 838 * Return a pointer to the var_type_def_t object for the given 839 * config_type_t value, or NULL if no such type definition exists. 840 **/ 841 const var_type_def_t * 842 lookup_type_def(config_type_t type) 843 { 844 int t = type; 845 tor_assert(t >= 0); 846 if (t >= (int)ARRAY_LENGTH(type_definitions_table)) 847 return NULL; 848 return type_definitions_table[t]; 849 }