commit 9dc946ba67a5d457ce00bf2853f624c3c7c344aa Author: Nick Mathewson nickm@torproject.org Date: Wed Feb 26 10:10:27 2020 -0500
Add a config_lines_partition() function to help with LINELIST_V.
This function works a little bit like strsep(), to get a chunk of configuration lines with a given header. We can use this to make hidden service config easier to parse. --- src/lib/encoding/confline.c | 29 ++++++++++++++++++++++++++ src/lib/encoding/confline.h | 1 + src/test/test_util.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+)
diff --git a/src/lib/encoding/confline.c b/src/lib/encoding/confline.c index ff8bacba3..eb1a4e30f 100644 --- a/src/lib/encoding/confline.c +++ b/src/lib/encoding/confline.c @@ -253,6 +253,35 @@ config_lines_dup_and_filter(const config_line_t *inp, return result; }
+/** + * Given a linelist <b>inp</b> beginning with the key <b>header</b>, find the + * next line with that key, and remove that instance and all following lines + * from the list. Return the lines that were removed. Operate + * case-insensitively. + * + * For example, if the header is "H", and <b>inp</b> contains "H, A, B, H, C, + * H, D", this function will alter <b>inp</b> to contain only "H, A, B", and + * return the elements "H, C, H, D" as a separate list. + **/ +config_line_t * +config_lines_partition(config_line_t *inp, const char *header) +{ + if (BUG(inp == NULL)) + return NULL; + if (BUG(strcasecmp(inp->key, header))) + return NULL; + + /* Advance ptr until it points to the link to the next segment of this + list. */ + config_line_t **ptr = &inp->next; + while (*ptr && strcasecmp((*ptr)->key, header)) { + ptr = &(*ptr)->next; + } + config_line_t *remainder = *ptr; + *ptr = NULL; + return remainder; +} + /** Return true iff a and b contain identical keys and values in identical * order. */ int diff --git a/src/lib/encoding/confline.h b/src/lib/encoding/confline.h index cd343e0e9..ce0d6c6e1 100644 --- a/src/lib/encoding/confline.h +++ b/src/lib/encoding/confline.h @@ -50,6 +50,7 @@ const config_line_t *config_line_find(const config_line_t *lines, const char *key); const config_line_t *config_line_find_case(const config_line_t *lines, const char *key); +config_line_t *config_lines_partition(config_line_t *inp, const char *header); int config_lines_eq(const config_line_t *a, const config_line_t *b); int config_count_key(const config_line_t *a, const char *key); void config_free_lines_(config_line_t *front); diff --git a/src/test/test_util.c b/src/test/test_util.c index fecd27909..234ae0674 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -1850,6 +1850,56 @@ test_util_config_line_crlf(void *arg) tor_free(k); tor_free(v); }
+static void +test_util_config_line_partition(void *arg) +{ + (void)arg; + config_line_t *lines = NULL, *orig, *rest = NULL; + + config_line_append(&lines, "Header", "X"); + config_line_append(&lines, "Item", "Y"); + config_line_append(&lines, "Thing", "Z"); + + config_line_append(&lines, "HEADER", "X2"); + + config_line_append(&lines, "header", "X3"); + config_line_append(&lines, "Item3", "Foob"); + + /* set up h2 and h3 to point to the places where we hope the headers will + be. */ + config_line_t *h2 = lines->next->next->next; + config_line_t *h3 = h2->next; + tt_str_op(h2->key, OP_EQ, "HEADER"); + tt_str_op(h3->key, OP_EQ, "header"); + + orig = lines; + rest = config_lines_partition(lines, "Header"); + tt_ptr_op(lines, OP_EQ, orig); + tt_ptr_op(rest, OP_EQ, h2); + tt_str_op(lines->next->key, OP_EQ, "Item"); + tt_str_op(lines->next->next->key, OP_EQ, "Thing"); + tt_ptr_op(lines->next->next->next, OP_EQ, NULL); + config_free_lines(lines); + + orig = lines = rest; + rest = config_lines_partition(lines, "Header"); + tt_ptr_op(lines, OP_EQ, orig); + tt_ptr_op(rest, OP_EQ, h3); + tt_ptr_op(lines->next, OP_EQ, NULL); + config_free_lines(lines); + + orig = lines = rest; + rest = config_lines_partition(lines, "Header"); + tt_ptr_op(lines, OP_EQ, orig); + tt_ptr_op(rest, OP_EQ, NULL); + tt_str_op(lines->next->key, OP_EQ, "Item3"); + tt_ptr_op(lines->next->next, OP_EQ, NULL); + + done: + config_free_lines(lines); + config_free_lines(rest); +} + #ifndef DISABLE_PWDB_TESTS static void test_util_expand_filename(void *arg) @@ -6379,6 +6429,7 @@ struct testcase_t util_tests[] = { UTIL_LEGACY(config_line_comment_character), UTIL_LEGACY(config_line_escaped_content), UTIL_LEGACY(config_line_crlf), + UTIL_TEST(config_line_partition, 0), UTIL_TEST_PWDB(expand_filename, 0), UTIL_LEGACY(escape_string_socks), UTIL_LEGACY(string_is_key_value),
tor-commits@lists.torproject.org