confline.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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-2017, The Tor Project, Inc. */
  5. /* See LICENSE for licensing information */
  6. #include "compat.h"
  7. #include "confline.h"
  8. #include "torlog.h"
  9. #include "util.h"
  10. /** Helper: allocate a new configuration option mapping 'key' to 'val',
  11. * append it to *<b>lst</b>. */
  12. void
  13. config_line_append(config_line_t **lst,
  14. const char *key,
  15. const char *val)
  16. {
  17. config_line_t *newline;
  18. newline = tor_malloc_zero(sizeof(config_line_t));
  19. newline->key = tor_strdup(key);
  20. newline->value = tor_strdup(val);
  21. newline->next = NULL;
  22. while (*lst)
  23. lst = &((*lst)->next);
  24. (*lst) = newline;
  25. }
  26. /** Return the line in <b>lines</b> whose key is exactly <b>key</b>, or NULL
  27. * if no such key exists. For handling commandline-only options only; other
  28. * options should be looked up in the appropriate data structure. */
  29. const config_line_t *
  30. config_line_find(const config_line_t *lines,
  31. const char *key)
  32. {
  33. const config_line_t *cl;
  34. for (cl = lines; cl; cl = cl->next) {
  35. if (!strcmp(cl->key, key))
  36. return cl;
  37. }
  38. return NULL;
  39. }
  40. /** Helper: parse the config string and strdup into key/value
  41. * strings. Set *result to the list, or NULL if parsing the string
  42. * failed. Return 0 on success, -1 on failure. Warn and ignore any
  43. * misformatted lines.
  44. *
  45. * If <b>extended</b> is set, then treat keys beginning with / and with + as
  46. * indicating "clear" and "append" respectively. */
  47. int
  48. config_get_lines(const char *string, config_line_t **result, int extended)
  49. {
  50. config_line_t *list = NULL, **next;
  51. char *k, *v;
  52. const char *parse_err;
  53. next = &list;
  54. do {
  55. k = v = NULL;
  56. string = parse_config_line_from_str_verbose(string, &k, &v, &parse_err);
  57. if (!string) {
  58. log_warn(LD_CONFIG, "Error while parsing configuration: %s",
  59. parse_err?parse_err:"<unknown>");
  60. config_free_lines(list);
  61. tor_free(k);
  62. tor_free(v);
  63. return -1;
  64. }
  65. if (k && v) {
  66. unsigned command = CONFIG_LINE_NORMAL;
  67. if (extended) {
  68. if (k[0] == '+') {
  69. char *k_new = tor_strdup(k+1);
  70. tor_free(k);
  71. k = k_new;
  72. command = CONFIG_LINE_APPEND;
  73. } else if (k[0] == '/') {
  74. char *k_new = tor_strdup(k+1);
  75. tor_free(k);
  76. k = k_new;
  77. tor_free(v);
  78. v = tor_strdup("");
  79. command = CONFIG_LINE_CLEAR;
  80. }
  81. }
  82. /* This list can get long, so we keep a pointer to the end of it
  83. * rather than using config_line_append over and over and getting
  84. * n^2 performance. */
  85. *next = tor_malloc_zero(sizeof(config_line_t));
  86. (*next)->key = k;
  87. (*next)->value = v;
  88. (*next)->next = NULL;
  89. (*next)->command = command;
  90. next = &((*next)->next);
  91. } else {
  92. tor_free(k);
  93. tor_free(v);
  94. }
  95. } while (*string);
  96. *result = list;
  97. return 0;
  98. }
  99. /**
  100. * Free all the configuration lines on the linked list <b>front</b>.
  101. */
  102. void
  103. config_free_lines(config_line_t *front)
  104. {
  105. config_line_t *tmp;
  106. while (front) {
  107. tmp = front;
  108. front = tmp->next;
  109. tor_free(tmp->key);
  110. tor_free(tmp->value);
  111. tor_free(tmp);
  112. }
  113. }
  114. /** Return a newly allocated deep copy of the lines in <b>inp</b>. */
  115. config_line_t *
  116. config_lines_dup(const config_line_t *inp)
  117. {
  118. return config_lines_dup_and_filter(inp, NULL);
  119. }
  120. /** Return a newly allocated deep copy of the lines in <b>inp</b>,
  121. * but only the ones that match <b>key</b>. */
  122. config_line_t *
  123. config_lines_dup_and_filter(const config_line_t *inp,
  124. const char *key)
  125. {
  126. config_line_t *result = NULL;
  127. config_line_t **next_out = &result;
  128. while (inp) {
  129. if (key && strcasecmpstart(inp->key, key)) {
  130. inp = inp->next;
  131. continue;
  132. }
  133. *next_out = tor_malloc_zero(sizeof(config_line_t));
  134. (*next_out)->key = tor_strdup(inp->key);
  135. (*next_out)->value = tor_strdup(inp->value);
  136. inp = inp->next;
  137. next_out = &((*next_out)->next);
  138. }
  139. (*next_out) = NULL;
  140. return result;
  141. }
  142. /** Return true iff a and b contain identical keys and values in identical
  143. * order. */
  144. int
  145. config_lines_eq(config_line_t *a, config_line_t *b)
  146. {
  147. while (a && b) {
  148. if (strcasecmp(a->key, b->key) || strcmp(a->value, b->value))
  149. return 0;
  150. a = a->next;
  151. b = b->next;
  152. }
  153. if (a || b)
  154. return 0;
  155. return 1;
  156. }
  157. /** Return the number of lines in <b>a</b> whose key is <b>key</b>. */
  158. int
  159. config_count_key(const config_line_t *a, const char *key)
  160. {
  161. int n = 0;
  162. while (a) {
  163. if (!strcasecmp(a->key, key)) {
  164. ++n;
  165. }
  166. a = a->next;
  167. }
  168. return n;
  169. }