aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2010-09-24 13:43:55 -0400
committerNick Mathewson <nickm@torproject.org>2010-09-24 13:43:55 -0400
commitc8e1538a0bdcb83dc2aeec075dcffdcac5bf45b7 (patch)
treef933499da338335c3454a4e82151a1d3af59341e /src
parent9b49a89430eac9a50fdb067aefec9d1561872796 (diff)
parent851255170aaa419e9c8f2a7d1b3c7a124a9c2783 (diff)
downloadtor-c8e1538a0bdcb83dc2aeec075dcffdcac5bf45b7.tar.gz
tor-c8e1538a0bdcb83dc2aeec075dcffdcac5bf45b7.zip
Merge remote branch 'sebastian/continuation'
Diffstat (limited to 'src')
-rw-r--r--src/common/util.c79
-rw-r--r--src/test/test_util.c56
2 files changed, 130 insertions, 5 deletions
diff --git a/src/common/util.c b/src/common/util.c
index 1d770458f7..abb2753c6e 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -2284,7 +2284,40 @@ unescape_string(const char *s, char **result, size_t *size_out)
const char *
parse_config_line_from_str(const char *line, char **key_out, char **value_out)
{
+ /* I believe the file format here is supposed to be:
+ FILE = (EMPTYLINE | LINE)* (EMPTYLASTLINE | LASTLINE)?
+
+ EMPTYLASTLINE = SPACE* | COMMENT
+ EMPTYLINE = EMPTYLASTLINE NL
+ SPACE = ' ' | '\r' | '\t'
+ COMMENT = '#' NOT-NL*
+ NOT-NL = Any character except '\n'
+ NL = '\n'
+
+ LASTLINE = SPACE* KEY SPACE* VALUES
+ LINE = LASTLINE NL
+ KEY = KEYCHAR+
+ KEYCHAR = Any character except ' ', '\r', '\n', '\t', '#', "\"
+
+ VALUES = QUOTEDVALUE | NORMALVALUE
+ QUOTEDVALUE = QUOTE QVITEM* QUOTE EOLSPACE?
+ QUOTE = '"'
+ QVCHAR = KEYCHAR | ESC ('n' | 't' | 'r' | '"' | ESC |'\'' | OCTAL | HEX)
+ ESC = "\\"
+ OCTAL = ODIGIT (ODIGIT ODIGIT?)?
+ HEX = ('x' | 'X') HEXDIGIT HEXDIGIT
+ ODIGIT = '0' .. '7'
+ HEXDIGIT = '0'..'9' | 'a' .. 'f' | 'A' .. 'F'
+ EOLSPACE = SPACE* COMMENT?
+
+ NORMALVALUE = (VALCHAR | ESC ESC_IGNORE | CONTINUATION)* EOLSPACE?
+ VALCHAR = Any character except ESC, '#', and '\n'
+ ESC_IGNORE = Any character except '#' or '\n'
+ CONTINUATION = ESC NL ( COMMENT NL )*
+ */
+
const char *key, *val, *cp;
+ int continuation = 0;
tor_assert(key_out);
tor_assert(value_out);
@@ -2308,9 +2341,10 @@ parse_config_line_from_str(const char *line, char **key_out, char **value_out)
return line;
}
- /* Skip until the next space. */
+ /* Skip until the next space or \ followed by newline. */
key = line;
- while (*line && !TOR_ISSPACE(*line) && *line != '#')
+ while (*line && !TOR_ISSPACE(*line) && *line != '#' &&
+ ! (line[0] == '\\' && line[1] == '\n'))
++line;
*key_out = tor_strndup(key, line-key);
@@ -2321,7 +2355,7 @@ parse_config_line_from_str(const char *line, char **key_out, char **value_out)
val = line;
/* Find the end of the line. */
- if (*line == '\"') {
+ if (*line == '\"') { // XXX No continuation handling is done here
if (!(line = unescape_string(line, value_out, NULL)))
return NULL;
while (*line == ' ' || *line == '\t')
@@ -2329,18 +2363,53 @@ parse_config_line_from_str(const char *line, char **key_out, char **value_out)
if (*line && *line != '#' && *line != '\n')
return NULL;
} else {
- while (*line && *line != '\n' && *line != '#')
- ++line;
+ /* Look for the end of the line. */
+ while (*line && *line != '\n' && (*line != '#' || continuation)) {
+ if (*line == '\\' && line[1] == '\n') {
+ continuation = 1;
+ line += 2;
+ } else if (*line == '#') {
+ do {
+ ++line;
+ } while (*line && *line != '\n');
+ if (*line == '\n')
+ ++line;
+ } else {
+ ++line;
+ }
+ }
+
if (*line == '\n') {
cp = line++;
} else {
cp = line;
}
+ /* Now back cp up to be the last nonspace character */
while (cp>val && TOR_ISSPACE(*(cp-1)))
--cp;
tor_assert(cp >= val);
+
+ /* Now copy out and decode the value. */
*value_out = tor_strndup(val, cp-val);
+ if (continuation) {
+ char *v_out, *v_in;
+ v_out = v_in = *value_out;
+ while (*v_in) {
+ if (*v_in == '#') {
+ do {
+ ++v_in;
+ } while (*v_in && *v_in != '\n');
+ if (*v_in == '\n')
+ ++v_in;
+ } else if (v_in[0] == '\\' && v_in[1] == '\n') {
+ v_in += 2;
+ } else {
+ *v_out++ = *v_in++;
+ }
+ }
+ *v_out = '\0';
+ }
}
if (*line == '#') {
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 8a13597978..d90927b35f 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -100,6 +100,15 @@ test_util_config_line(void)
"k4#a\n" "k5#abc\n" "k6 val #with comment\n"
"kseven \"a quoted 'string\"\n"
"k8 \"a \\x71uoted\\n\\\"str\\\\ing\\t\\001\\01\\1\\\"\"\n"
+ "k9 a line that\\\n spans two lines.\n\n"
+ "k10 more than\\\n one contin\\\nuation\n"
+ "k11 \\\ncontinuation at the start\n"
+ "k12 line with a\\\n#comment\n embedded\n"
+ "k13\\\ncontinuation at the very start\n"
+ "k14 a line that has a comment and # ends with a slash \\\n"
+ "k15 this should be the next new line\n"
+ "k16 a line that has a comment and # ends without a slash \n"
+ "k17 this should be the next new line\n"
, sizeof(buf));
str = buf;
@@ -161,7 +170,54 @@ test_util_config_line(void)
test_streq(k, "k8");
test_streq(v, "a quoted\n\"str\\ing\t\x01\x01\x01\"");
tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k9");
+ test_streq(v, "a line that spans two lines.");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k10");
+ test_streq(v, "more than one continuation");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k11");
+ test_streq(v, "continuation at the start");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k12");
+ test_streq(v, "line with a embedded");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k13");
+ test_streq(v, "continuation at the very start");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k14");
+ test_streq(v, "a line that has a comment and" );
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k15");
+ test_streq(v, "this should be the next new line");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k16");
+ test_streq(v, "a line that has a comment and" );
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k17");
+ test_streq(v, "this should be the next new line");
+ tor_free(k); tor_free(v);
+
test_streq(str, "");
+
done:
tor_free(k);
tor_free(v);