aboutsummaryrefslogtreecommitdiff
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
parent9b49a89430eac9a50fdb067aefec9d1561872796 (diff)
parent851255170aaa419e9c8f2a7d1b3c7a124a9c2783 (diff)
downloadtor-c8e1538a0bdcb83dc2aeec075dcffdcac5bf45b7.tar.gz
tor-c8e1538a0bdcb83dc2aeec075dcffdcac5bf45b7.zip
Merge remote branch 'sebastian/continuation'
-rw-r--r--changes/torrc_continuation6
-rw-r--r--doc/tor.1.txt5
-rw-r--r--src/common/util.c79
-rw-r--r--src/test/test_util.c56
4 files changed, 140 insertions, 6 deletions
diff --git a/changes/torrc_continuation b/changes/torrc_continuation
new file mode 100644
index 0000000000..5b6e086e6f
--- /dev/null
+++ b/changes/torrc_continuation
@@ -0,0 +1,6 @@
+ o Minor features:
+ - Support line continuations in torrc. If a line ends with a
+ single backslash character, the newline is ignored, and the
+ configuration value is treated as continuing on the next line.
+ Resolves bug 1929.
+
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index 235d04be82..fe69a2d3fb 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -65,7 +65,10 @@ Other options can be specified either on the command-line (--option
value), or in the configuration file (option value or option "value").
Options are case-insensitive. C-style escaped characters are allowed inside
quoted values. Options on the command line take precedence over
- options found in the configuration file.
+ options found in the configuration file, except indicated otherwise. To
+ split one configuration entry into multiple lines, use a single \ before
+ the end of the line. Comments can be used in such multiline entries, but
+ they must start at the beginning of a line.
**BandwidthRate** __N__ **bytes**|**KB**|**MB**|**GB**::
A token bucket limits the average incoming bandwidth usage on this node to
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);