Loading changes/torrc_continuation 0 → 100644 +6 −0 Original line number Diff line number Diff line 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. doc/tor.1.txt +4 −1 Original line number Diff line number Diff line Loading @@ -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 Loading src/common/util.c +74 −5 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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); Loading @@ -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') Loading @@ -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 != '#') /* 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 == '#') { Loading src/test/test_util.c +56 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading
changes/torrc_continuation 0 → 100644 +6 −0 Original line number Diff line number Diff line 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.
doc/tor.1.txt +4 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
src/common/util.c +74 −5 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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); Loading @@ -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') Loading @@ -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 != '#') /* 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 == '#') { Loading
src/test/test_util.c +56 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading