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