From 0ea0bbf46811b890b7bc51e9becdbc905fb52297 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 23 Dec 2011 11:40:58 +0100 Subject: MAJOR: add support for quoted strings in configuration files Until now the only way to enter spaces in a config file was to backslash-escape them, which made config files quite hard to write. From now on, single and double quotes may also be used to delimit strings. Existing setups might break, though none of them have been identified so far. --- doc/configuration.txt | 33 +++++++++++++++++++++++++-------- src/cfgparse.c | 26 +++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index 066f935..f53c583 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -350,11 +350,27 @@ HAProxy's configuration process involves 3 major sources of parameters : - the proxies sections which can take form of "defaults", "listen", "frontend" and "backend". -The configuration file syntax consists in lines beginning with a keyword -referenced in this manual, optionally followed by one or several parameters -delimited by spaces. If spaces have to be entered in strings, then they must be -preceded by a backslash ('\') to be escaped. Backslashes also have to be -escaped by doubling them. +The configuration file is line-oriented, which means that each line is a single +statement. Lines are composed of words delimited by spaces or tabs. Leading +spaces and tabs are ignored. The number of spaces and tabs between words makes +no importance. Everything which stands after sharp symbol ('#') is considered +as comments and will be ignored. Empty lines are ignored. If a space, tab or a +sharp symbol needs to be entered, it needs to be escaped by a backslash ('\'), +or enclosed in a pair of single or double quotes (''' or '"') which are used to +delimit strings. Single or double quotes may themselves be escaped or enclosed +between the other type. Special characters may be entered as in the C language: + + - \t = tab = ASCII 9 = 0x09 + - \n = line feed (LF) = ASCII 10 = 0x0A + - \r = carriage return (CR) = ASCII 13 = 0x0D + - \ = space (' ') = ASCII 32 = 0x20 + - \" = double quote ('"') = ASCII 34 = 0x22 + - \# = sharp symbol ('#') = ASCII 35 = 0x23 + - \' = single quote (''') = ASCII 39 = 0x27 + - \\ = backslash ('\') = ASCII 92 = 0x5C + - \xHH = ASCII character represented by hex code 0xHH + +Other characters are not altered by the presence of a backslash. 2.2. Time format @@ -6917,9 +6933,10 @@ in section 4.2 : With all these keywords, the same conventions are used. The parameter is a POSIX extended regular expression (regex) which supports grouping through -parenthesis (without the backslash). Spaces and other delimiters must be -prefixed with a backslash ('\') to avoid confusion with a field delimiter. -Other characters may be prefixed with a backslash to change their meaning : +parenthesis (without the backslash). Spaces and other delimiters must either be +prefixed with a backslash ('\') or enclosed within single or double quotes, to +avoid confusion with a field delimiter. Other characters may be prefixed with a +backslash to change their meaning : \t for a tab \r for a carriage return (CR) diff --git a/src/cfgparse.c b/src/cfgparse.c index bf2eb36..8b11814 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -5328,6 +5328,7 @@ int readcfgfile(const char *file) char *end; char *args[MAX_LINE_ARGS + 1]; char *line = thisline; + char quote = 0; linenum++; @@ -5355,7 +5356,9 @@ int readcfgfile(const char *file) */ if (*line == '\\') { int skip = 0; - if (line[1] == ' ' || line[1] == '\\' || line[1] == '#') { + if (line[1] == ' ' || + line[1] == '\'' || line[1] == '"' || + line[1] == '\\' || line[1] == '#') { *line = line[1]; skip = 1; } @@ -5392,11 +5395,32 @@ int readcfgfile(const char *file) } line++; } + else if (quote) { + if (*line == '\n' || *line == '\r' || !*line) { + Alert("parsing [%s:%d] : missing closing quote <%c>.\n", file, linenum, quote); + err_code |= ERR_ALERT | ERR_FATAL; + break; + } + else if (*line == quote) { + /* closing quote */ + quote = 0; + memmove(line, line + 1, end - line); + end--; + } + else + line++; + } else if (*line == '#' || *line == '\n' || *line == '\r') { /* end of string, end of loop */ *line = 0; break; } + else if (*line == '"' || *line == '\'') { + /* opening quote */ + quote = *line; + memmove(line, line + 1, end - line); + end--; + } else if (isspace((unsigned char)*line)) { /* a non-escaped space is an argument separator */ *line++ = '\0'; -- 1.7.2.3