diff --git a/src/common/util.c b/src/common/util.c index 76b7254cd3..cc00ff9792 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -875,7 +875,7 @@ char *read_file_to_str(const char *filename, int bin) { int parse_line_from_file(char *line, size_t maxlen, FILE *f, char **key_out, char **value_out) { - char *s, *key, *end, *value; + char *s; try_next_line: if(!fgets(line, maxlen, f)) { @@ -883,6 +883,17 @@ try_next_line: return 0; return -1; /* real error */ } + line[maxlen-1] = '\0'; + + s = parse_line_from_str(line, key_out, value_out); + if (!s) + return -1; + if (!*key_out) + goto try_next_line; + + return 1; + +#if 0 if((s = strchr(line,'#'))) /* strip comments */ *s = 0; /* stop the line there */ @@ -920,6 +931,73 @@ try_next_line: log_fn(LOG_DEBUG,"got keyword '%s', value '%s'", key, value); *key_out = key, *value_out = value; return 1; +#endif +} + + +/** DOCDOC. + * + * Return next line or end of string on success, NULL on failure. + */ +char * +parse_line_from_str(char *line, char **key_out, char **value_out) +{ + char *key, *val, *cp; + + tor_assert(key_out); + tor_assert(value_out); + + *key_out = *value_out = key = val = NULL; + /* Skip until the first keyword. */ + while (1) { + while (isspace(*line)) + ++line; + if (*line == '#') { + while (*line && *line != '\n') + ++line; + } else { + break; + } + } + + if (!*line) { /* End of string? */ + *key_out = *value_out = NULL; + return line; + } + + /* Skip until the next space. */ + key = line; + while (*line && !isspace(*line) && *line != '#') + ++line; + + /* Skip until the value */ + while (*line == ' ' || *line == '\t') + *line++ = '\0'; + val = line; + + /* Find the end of the line. */ + while (*line && *line != '\n' && *line != '#') + ++line; + if (*line == '\n') + cp = line++; + else { + cp = line-1; + } + while (cp>=val && isspace(*cp)) + *cp-- = '\0'; + + if (*line == '#') { + do { + *line++ = '\0'; + } while (*line && *line != '\n'); + if (*line == '\n') + ++line; + } + + *key_out = key; + *value_out = val; + + return line; } /** Expand any homedir prefix on 'filename'; return a newly allocated diff --git a/src/common/util.h b/src/common/util.h index dba95e456d..5674afc6be 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -92,6 +92,7 @@ int write_bytes_to_file(const char *fname, const char *str, size_t len, int bin); char *read_file_to_str(const char *filename, int bin); int parse_line_from_file(char *line, size_t maxlen, FILE *f, char **key_out, char **value_out); +char *parse_line_from_str(char *line, char **key_out, char **value_out); char *expand_filename(const char *filename); /* Net helpers */ diff --git a/src/or/test.c b/src/or/test.c index 2cece29d76..f1d1d6545f 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -489,7 +489,7 @@ test_util(void) { int i; uint32_t u32; uint16_t u16; - char *cp; + char *cp, *k, *v; start.tv_sec = 5; start.tv_usec = 5000; @@ -674,6 +674,53 @@ test_util(void) { test_eq(10L, tor_parse_long("10",10,0,100,NULL,NULL)); test_eq(0L, tor_parse_long("10",10,50,100,NULL,NULL)); + /* Test parse_line_from_str */ + strlcpy(buf, "k v\n" " key value with spaces \n" "keykey val\n" + "k2\n" + "k3 \n" "\n" " \n" "#comment\n" + "k4#a\n" "k5#abc\n" "k6 val #with comment\n", sizeof(buf)); + cp = buf; + + cp = parse_line_from_str(cp, &k, &v); + test_streq(k, "k"); + test_streq(v, "v"); + test_assert(!strcmpstart(cp, " key value with")); + + cp = parse_line_from_str(cp, &k, &v); + test_streq(k, "key"); + test_streq(v, "value with spaces"); + test_assert(!strcmpstart(cp, "keykey")); + + cp = parse_line_from_str(cp, &k, &v); + test_streq(k, "keykey"); + test_streq(v, "val"); + test_assert(!strcmpstart(cp, "k2\n")); + + cp = parse_line_from_str(cp, &k, &v); + test_streq(k, "k2"); + test_streq(v, ""); + test_assert(!strcmpstart(cp, "k3 \n")); + + cp = parse_line_from_str(cp, &k, &v); + test_streq(k, "k3"); + test_streq(v, ""); + test_assert(!strcmpstart(cp, "\n \n")); + + cp = parse_line_from_str(cp, &k, &v); + test_streq(k, "k4"); + test_streq(v, ""); + test_assert(!strcmpstart(cp, "k5#abc")); + + cp = parse_line_from_str(cp, &k, &v); + test_streq(k, "k5"); + test_streq(v, ""); + test_assert(!strcmpstart(cp, "k6")); + + cp = parse_line_from_str(cp, &k, &v); + test_streq(k, "k6"); + test_streq(v, "val"); + test_streq(cp, ""); + /* XXXX test older functions. */ smartlist_free(sl); }