char *ConfigParser::lastToken = NULL;
std::queue<std::string> ConfigParser::undo;
+
+int ConfigParser::RecognizeQuotedValues = true;
+
void
ConfigParser::destruct()
{
undo.push(tok);
}
+char *
+xstrtok(char *str, const char *delimiters)
+{
+ assert(!str); // we are parsing the configuration file
+ // no support unless enabled in the configuration and
+ // no support for other delimiters (they may need to be eradicated!)
+ return (ConfigParser::RecognizeQuotedValues &&
+ strcmp(delimiters, " \t\n\r") == 0) ?
+ ConfigParser::NextToken() : ::strtok(str, delimiters);
+}
+
+
char *
ConfigParser::strtokFile(void)
{
strncpy(undoToken, undo.front().c_str(), sizeof(undoToken));
undoToken[sizeof(undoToken) - 1] = '\0';
undo.pop();
- return undoToken;
+ return lastToken = undoToken;
}
+ // XXX: add file:name support to the quoted string-aware parser
+ if (RecognizeQuotedValues)
+ return lastToken = ConfigParser::NextToken();
+
lastToken = NULL;
do {
return lastToken = t;
}
+/// returns token after stripping any comments
+/// must be called in non-quoted context only
+char *
+ConfigParser::StripComment(char *token)
+{
+ if (!token)
+ return NULL;
+
+ // we are outside the quoted string context
+ // assume that anything starting with a '#' is a comment
+ if (char *comment = strchr(token, '#')) {
+ *comment = '\0'; // remove the comment from this token
+ (void)strtok(NULL, ""); // remove the comment from the current line
+ if (!*token)
+ return NULL; // token was a comment
+ }
+
+ return token;
+}
+
void
ConfigParser::ParseQuotedString(char **var, bool *wasQuoted)
{
- String sVar;
- ParseQuotedString(&sVar, wasQuoted);
- *var = xstrdup(sVar.termedBuf());
+ if (const char *phrase = NextElement(wasQuoted))
+ *var = xstrdup(phrase);
+ else
+ self_destruct();
}
void
ConfigParser::ParseQuotedString(String *var, bool *wasQuoted)
{
+ if (const char *phrase = NextElement(wasQuoted))
+ var->reset(phrase);
+ else
+ self_destruct();
+}
+
+char *
+ConfigParser::NextElement(bool *wasQuoted)
+{
+ if (wasQuoted)
+ *wasQuoted = false;
+
// Get all of the remaining string
char *token = strtok(NULL, "");
if (token == NULL)
- self_destruct();
+ return NULL;
- if (*token != '"') {
- token = strtok(token, w_space);
- var->reset(token);
- if (wasQuoted)
- *wasQuoted = false;
- return;
- } else if (wasQuoted)
+ // skip leading whitespace (may skip the entire token that way)
+ while (xisspace(*token)) ++token;
+
+ if (*token != '"')
+ return StripComment(strtok(token, w_space));
+
+ if (wasQuoted)
*wasQuoted = true;
char *s = token + 1;
}
if (*s != '"') {
- debugs(3, DBG_CRITICAL, "ParseQuotedString: missing '\"' at the end of quoted string" );
+ debugs(3, DBG_CRITICAL, "missing '\"' at the end of quoted string" );
self_destruct();
}
strtok(s-1, "\""); /*Reset the strtok to point after the " */
*s = '\0';
- var->reset(token+1);
+ return (token+1);
}
+char *
+ConfigParser::NextToken()
+{
+ return NextElement(NULL);
+ // TODO: support file:name syntax to auto-include files, but think how
+ // admins will be able to disable that interpretation w/o disabling
+ // macros and other special value processing. The "file:" prefix or
+ // any similar key construct would probably have to go outside the
+ // optionally quoted string for that to work: file:"name with $macros".
+}
+
+
const char *
ConfigParser::QuoteString(String &var)
{
static char * strtokFile();
static void strtokFileUndo();
static void strtokFilePutBack(const char *);
+
+ /**
+ Returns the body of the next element. The element is either a token or
+ a quoted string with optional escape sequences and/or macros. The body
+ of a quoted string element does not include quotes or escape sequences.
+ Future code will want to see Elements and not just their bodies.
+ */
+ static char *NextToken();
+
+ /// configuration_includes_quoted_values in squid.conf
+ static int RecognizeQuotedValues;
+
+protected:
+ static char *NextElement(bool *wasQuoted);
+ static char *StripComment(char *token);
+
private:
static char *lastToken;
static std::queue<std::string> undo;
int parseConfigFile(const char *file_name);
+/// XXX: Used for temporary hacks to allow old code to handle quoted values
+/// without replacing every strtok() call.
+extern char *xstrtok(char *str, const char *delimiters);
+
+
#endif /* SQUID_CONFIGPARSER_H */
configuration files.
+ Values with spaces, quotes, and other special characters
+
+ Squid supports directive parameters with spaces, quotes, and other
+ special characters. Surround such parameters with "double quotes". Use
+ the configuration_includes_quoted_values directive to enable or
+ disable that support.
+
+ XXX: Document escaping and macro substitution rules inside quoted
+ strings.
+
+ XXX: Support single-quoted strings that prevent macro substitution.
+
+
Conditional configuration
If-statements can be used to make configuration directives
-----------------------------------------------------------------------------
COMMENT_END
+NAME: configuration_includes_quoted_values
+COMMENT: on|off
+TYPE: onoff
+DEFAULT: on
+LOC: ConfigParser::RecognizeQuotedValues
+DOC_START
+ If set, Squid will recognize each "quoted string" as a single
+ configuration directive parameter. The quotes are stripped before the
+ parameter value is interpreted or used. XXX: Give more details.
+DOC_END
+
NAME: memory_pools
COMMENT: on|off
TYPE: onoff