|
@@ -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 == '#') {
|