]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Quoted values in squid.conf
authorChristos Tsantilas <chtsanti@users.sourceforge.net>
Sun, 21 Jul 2013 19:24:35 +0000 (22:24 +0300)
committerChristos Tsantilas <chtsanti@users.sourceforge.net>
Sun, 21 Jul 2013 19:24:35 +0000 (22:24 +0300)
This patch :
  - adds support for quoted values in the entire squid.conf
  - warn about or prohibit values that can no longer be interpreted as
    either quoted strings or simple tokens
  - support parameters("/path/to/file.name") syntax to load external
    configuration files
  - Checks if macros allowed in "double quoted" values.
  - replaces the strtok() calls with calls to the new ConfigParser::NextToken()
  - modify strtokFile to use new ConfigParser::NextToken()
  - Add the new configuration_includes_quoted_values configuration option, to
    control the squid parser behaviour. If set to on Squid will recognize each
    "quoted string" after a configuration directive as a single parameter

This is a Measurement Factory project

27 files changed:
src/ConfigParser.cc
src/ConfigParser.h
src/HelperChildConfig.cc
src/Notes.cc
src/Parsing.cc
src/SwapDir.cc
src/acl/Acl.cc
src/acl/Gadgets.cc
src/adaptation/Config.cc
src/adaptation/ServiceConfig.cc
src/adaptation/ServiceGroups.cc
src/cache_cf.cc
src/cf.data.pre
src/cf_gen.cc
src/external_acl.cc
src/format/Config.cc
src/format/Format.h
src/ip/QosConfig.cc
src/log/Config.cc
src/tests/stub_cache_cf.cc
src/tests/testACLMaxUserIP.cc
src/tests/testAuth.cc
src/tests/testConfigParser.cc
src/tests/testCoss.cc
src/tests/testRock.cc
src/tests/testUfs.cc
src/wccp2.cc

index 453ca76f6fdaba8b2964a726b59ee47d4308fb5c..a4e3ffcb86afcb13c14b2ffdb6f1a95b582505ef 100644 (file)
 #include "fatal.h"
 #include "globals.h"
 
-char *ConfigParser::lastToken = NULL;
-std::queue<std::string> ConfigParser::undo;
+int ConfigParser::RecognizeQuotedValues = true;
+std::stack<ConfigParser::CfgFile *> ConfigParser::CfgFiles;
+ConfigParser::TokenType ConfigParser::LastTokenType = ConfigParser::SimpleToken;
+char *ConfigParser::LastToken = NULL;
+char *ConfigParser::CfgLine = NULL;
+char *ConfigParser::CfgPos = NULL;
+std::queue<std::string> ConfigParser::Undo_;
+bool ConfigParser::AllowMacros_ = false;
 
 void
 ConfigParser::destruct()
 {
     shutting_down = 1;
-    fatalf("Bungled %s line %d: %s",
-           cfg_filename, config_lineno, config_input_line);
+    if (!CfgFiles.empty()) {
+        std::ostringstream message;
+        CfgFile *f = CfgFiles.top();
+        message << "Bungled " << f->filePath << " line " << f->lineNo <<
+        ": " << f->currentLine << std::endl;
+        CfgFiles.pop();
+        delete f;
+        while (!CfgFiles.empty()) {
+            f = CfgFiles.top();
+            message << " included from " << f->filePath << " line " <<
+            f->lineNo << ": " << f->currentLine << std::endl;
+            CfgFiles.pop();
+            delete f;
+        }
+        message << " included from " <<  cfg_filename << " line " <<
+        config_lineno << ": " << config_input_line << std::endl;
+        std::string msg = message.str();
+        fatalf("%s", msg.c_str());
+    } else
+        fatalf("Bungled %s line %d: %s",
+               cfg_filename, config_lineno, config_input_line);
 }
 
 void
-ConfigParser::strtokFileUndo()
+ConfigParser::TokenUndo()
 {
-    assert(lastToken);
-    undo.push(lastToken);
+    assert(LastToken);
+    Undo_.push(LastToken);
 }
 
 void
-ConfigParser::strtokFilePutBack(const char *tok)
+ConfigParser::TokenPutBack(const char *tok)
 {
     assert(tok);
-    undo.push(tok);
+    Undo_.push(tok);
 }
 
 char *
-ConfigParser::strtokFile(void)
+ConfigParser::Undo()
 {
+    LOCAL_ARRAY(char, undoToken, CONFIG_LINE_LIMIT);
+    if (!Undo_.empty()) {
+        strncpy(undoToken, Undo_.front().c_str(), sizeof(undoToken));
+        undoToken[sizeof(undoToken) - 1] = '\0';
+        Undo_.pop();
+        return undoToken;
+    }
+    return NULL;
+}
+
+char *
+ConfigParser::strtokFile()
+{
+    if (RecognizeQuotedValues)
+        return ConfigParser::NextToken();
+
     static int fromFile = 0;
     static FILE *wordFile = NULL;
-    LOCAL_ARRAY(char, undoToken, CONFIG_LINE_LIMIT);
 
-    char *t, *fn;
+    char *t;
     LOCAL_ARRAY(char, buf, CONFIG_LINE_LIMIT);
 
-    if (!undo.empty()) {
-        strncpy(undoToken, undo.front().c_str(), sizeof(undoToken));
-        undoToken[sizeof(undoToken) - 1] = '\0';
-        undo.pop();
-        return undoToken;
-    }
+    if ((LastToken = ConfigParser::Undo()))
+        return LastToken;
 
-    lastToken = NULL;
     do {
 
         if (!fromFile) {
-            t = (strtok(NULL, w_space));
-
-            if (!t || *t == '#') {
+            ConfigParser::TokenType tokenType;
+            t = ConfigParser::NextElement(tokenType, true);
+            if (!t) {
                 return NULL;
-            } else if (*t == '\"' || *t == '\'') {
+            } else if (tokenType == ConfigParser::QuotedToken) {
                 /* quote found, start reading from file */
-                fn = ++t;
-
-                while (*t && *t != '\"' && *t != '\'')
-                    ++t;
+                debugs(3, 8,"Quoted token found : " << t);
 
-                *t = '\0';
-
-                if ((wordFile = fopen(fn, "r")) == NULL) {
-                    debugs(28, DBG_CRITICAL, "strtokFile: " << fn << " not found");
-                    return (NULL);
+                if ((wordFile = fopen(t, "r")) == NULL) {
+                    debugs(3, DBG_CRITICAL, "Can not open file " << t << " for reading");
+                    return false;
                 }
 
 #if _SQUID_WINDOWS_
@@ -108,7 +138,7 @@ ConfigParser::strtokFile(void)
 
                 fromFile = 1;
             } else {
-                return lastToken = t;
+                return LastToken = t;
             }
         }
 
@@ -139,52 +169,182 @@ ConfigParser::strtokFile(void)
         /* skip blank lines */
     } while ( *t == '#' || !*t );
 
-    return lastToken = t;
-}
-
-void
-ConfigParser::ParseQuotedString(char **var, bool *wasQuoted)
-{
-    String sVar;
-    ParseQuotedString(&sVar, wasQuoted);
-    *var = xstrdup(sVar.termedBuf());
+    return LastToken = t;
 }
 
-void
-ConfigParser::ParseQuotedString(String *var, bool *wasQuoted)
+char *
+ConfigParser::UnQuote(char *token, char **end)
 {
-    // Get all of the remaining string
-    char *token = strtok(NULL, "");
-    if (token == NULL)
-        self_destruct();
-
-    if (*token != '"') {
-        token = strtok(token, w_space);
-        var->reset(token);
-        if (wasQuoted)
-            *wasQuoted = false;
-        return;
-    } else if (wasQuoted)
-        *wasQuoted = true;
-
+    char quoteChar = *token;
+    assert(quoteChar == '"' || quoteChar == '\'');
     char  *s = token + 1;
     /* scan until the end of the quoted string, unescaping " and \  */
-    while (*s && *s != '"') {
-        if (*s == '\\') {
+    while (*s && *s != quoteChar) {
+        if (*s == '\\' && isalnum(*( s + 1))) {
+            debugs(3, DBG_CRITICAL, "Unsupported escape sequence: " << s);
+            self_destruct();
+        } else if (*s == '$' && quoteChar == '"') {
+            debugs(3, DBG_CRITICAL, "Unsupported cfg macro: " << s);
+            self_destruct();
+        } else if (*s == '%' && quoteChar == '"' && (!AllowMacros_ )) {
+            debugs(3, DBG_CRITICAL, "Macros are not supported here: " << s);
+            self_destruct();
+        } else if (*s == '\\') {
             const char * next = s+1; // may point to 0
             memmove(s, next, strlen(next) + 1);
         }
         ++s;
     }
 
-    if (*s != '"') {
-        debugs(3, DBG_CRITICAL, "ParseQuotedString: missing '\"' at the end of quoted string" );
+    if (*s != quoteChar) {
+        debugs(3, DBG_CRITICAL, "missing '" << quoteChar << "' at the end of quoted string: " << (s-1));
         self_destruct();
     }
-    strtok(s-1, "\""); /*Reset the strtok to point after the "  */
-    *s = '\0';
+    *end = s;
+    return (token+1);
+}
+
+void
+ConfigParser::SetCfgLine(char *line)
+{
+    CfgLine = line;
+    CfgPos = line;
+}
+
+char *
+ConfigParser::TokenParse(char * &nextToken, ConfigParser::TokenType &type, bool legacy)
+{
+    if (!nextToken || *nextToken == '\0')
+        return NULL;
+    type = ConfigParser::SimpleToken;
+    nextToken += strspn(nextToken, w_space);
+    if (*nextToken == '"' || *nextToken == '\'') {
+        type = ConfigParser::QuotedToken;
+        char *token = UnQuote(nextToken, &nextToken);
+        *nextToken = '\0';
+        ++nextToken;
+        return token;
+    }
+
+    char *token = nextToken;
+    if (char *t = strchr(nextToken, '#'))
+        *t = '\0';
+    const char *sep;
+    if (legacy)
+        sep = w_space;
+    else
+        sep = w_space "(";
+    nextToken += strcspn(nextToken, sep);
+
+    if (!legacy && *nextToken == '(')
+        type = ConfigParser::FunctionNameToken;
+    else
+        type = ConfigParser::SimpleToken;
+
+    if (*nextToken != '\0') {
+        *nextToken = '\0';
+        ++nextToken;
+    }
+
+    if (*token == '\0')
+        return NULL;
+
+    return token;
+}
+
+char *
+ConfigParser::NextElement(ConfigParser::TokenType &type, bool legacy)
+{
+    char *token = TokenParse(CfgPos, type, legacy);
+    return token;
+}
+
+char *
+ConfigParser::NextToken()
+{
+    if ((LastToken = ConfigParser::Undo()))
+        return LastToken;
+
+    char *token = NULL;
+    do {
+        while (token == NULL && !CfgFiles.empty()) {
+            ConfigParser::CfgFile *wordfile = CfgFiles.top();
+            token = wordfile->parse(LastTokenType);
+            if (!token) {
+                assert(!wordfile->isOpen());
+                CfgFiles.pop();
+                delete wordfile;
+            }
+        }
+
+        if (!token)
+            token = NextElement(LastTokenType);
 
-    var->reset(token+1);
+        if (token &&  LastTokenType == ConfigParser::FunctionNameToken && strcmp("parameters", token) == 0) {
+            char *path = NextToken();
+            if (LastTokenType != ConfigParser::QuotedToken) {
+                debugs(3, DBG_CRITICAL, "Quoted filename missing: " << token);
+                self_destruct();
+                return NULL;
+            }
+
+            // The next token in current cfg file line must be a ")"
+            char *end = NextToken();
+            if (LastTokenType != ConfigParser::SimpleToken || strcmp(end, ")") != 0) {
+                debugs(3, DBG_CRITICAL, "missing ')' after " << token << "(\"" << path << "\"");
+                self_destruct();
+                return NULL;
+            }
+
+            if (CfgFiles.size() > 16) {
+                debugs(3, DBG_CRITICAL, "WARNING: can't open %s for reading parameters: includes are nested too deeply (>16)!\n" << path);
+                self_destruct();
+                return NULL;
+            }
+
+            ConfigParser::CfgFile *wordfile = new ConfigParser::CfgFile();
+            if (!path || !wordfile->startParse(path)) {
+                debugs(3, DBG_CRITICAL, "Error opening config file: " << token);
+                delete wordfile;
+                self_destruct();
+                return NULL;
+            }
+            CfgFiles.push(wordfile);
+            token = NULL;
+        } else if (token &&  LastTokenType == ConfigParser::FunctionNameToken) {
+            debugs(3, DBG_CRITICAL, "Unknown cfg function: " << token);
+            self_destruct();
+            return NULL;
+        }
+    } while (token == NULL && !CfgFiles.empty());
+
+    return (LastToken = token);
+}
+
+char *
+ConfigParser::NextQuotedOrToEol()
+{
+    char *token;
+
+    if ((token = CfgPos) == NULL) {
+        debugs(3, DBG_CRITICAL, "token is missing");
+        self_destruct();
+        return NULL;
+    }
+    token += strspn(token, w_space);
+
+    if (*token == '\"' || *token == '\'') {
+        //TODO: eat the spaces at the end and check if it is untill the end of file.
+        char *end;
+        token = UnQuote(token, &end);
+        *end = '\0';
+        CfgPos = end + 1;
+        LastTokenType = ConfigParser::QuotedToken;
+    } else
+        LastTokenType = ConfigParser::SimpleToken;
+
+    CfgPos = NULL;
+    return (LastToken = token);
 }
 
 const char *
@@ -210,3 +370,66 @@ ConfigParser::QuoteString(const String &var)
     quotedStr.append('"');
     return quotedStr.termedBuf();
 }
+
+bool
+ConfigParser::CfgFile::startParse(char *path)
+{
+    assert(wordFile == NULL);
+    if ((wordFile = fopen(path, "r")) == NULL) {
+        debugs(3, DBG_CRITICAL, "file :" << path << " not found");
+        return false;
+    }
+
+#if _SQUID_WINDOWS_
+    setmode(fileno(wordFile), O_TEXT);
+#endif
+
+    filePath = path;
+    return getFileLine();
+}
+
+bool
+ConfigParser::CfgFile::getFileLine()
+{
+    // Else get the next line
+    if (fgets(parseBuffer, CONFIG_LINE_LIMIT, wordFile) == NULL) {
+        /* stop reading from file */
+        fclose(wordFile);
+        wordFile = NULL;
+        parseBuffer[0] = '\0';
+        return false;
+    }
+    parsePos = parseBuffer;
+    currentLine = parseBuffer;
+    lineNo++;
+    return true;
+}
+
+char *
+ConfigParser::CfgFile::parse(ConfigParser::TokenType &type)
+{
+    if (!wordFile)
+        return NULL;
+
+    if (!*parseBuffer)
+        return NULL;
+
+    char *token;
+    while (!(token = nextElement(type))) {
+        if (!getFileLine())
+            return NULL;
+    }
+    return token;
+}
+
+char *
+ConfigParser::CfgFile::nextElement(ConfigParser::TokenType &type)
+{
+    return TokenParse(parsePos, type);
+}
+
+ConfigParser::CfgFile::~CfgFile()
+{
+    if (wordFile)
+        fclose(wordFile);
+}
index f313a5a6c2db306e1fda9153f23ea82158735fd6..1175bdce97f2af61d05b2a0afe190ec38413c70d 100644 (file)
@@ -36,6 +36,7 @@
 
 #include "SquidString.h"
 #include <queue>
+#include <stack>
 #if HAVE_STRING
 #include <string>
 #endif
@@ -65,26 +66,143 @@ class ConfigParser
 {
 
 public:
+    /**
+     * Parsed tokens type: simple tokens, quoted tokens or function
+     * like parameters.
+     */
+    enum TokenType {SimpleToken, QuotedToken, FunctionNameToken};
+
     void destruct();
     static void ParseUShort(unsigned short *var);
     static void ParseBool(bool *var);
-    static void ParseString(char **var);
-    static void ParseString(String *var);
-    /// Parse an unquoted token (no spaces) or a "quoted string" that
-    /// may include spaces. In some contexts, quotes strings may also
-    /// include macros. Quoted strings may escape any character with
-    /// a backslash (\), which is currently only useful for inner
-    /// quotes. TODO: support quoted strings anywhere a token is accepted.
-    static void ParseQuotedString(char **var, bool *wasQuoted = NULL);
-    static void ParseQuotedString(String *var, bool *wasQuoted = NULL);
     static const char *QuoteString(const String &var);
     static void ParseWordList(wordlist **list);
+
+    /**
+     * Backward compatibility wrapper for the ConfigParser::NextToken method.
+     * If the configuration_includes_quoted_values configuration parameter is
+     * set to 'off' this interprets the quoted tokens as filenames.
+     */
     static char * strtokFile();
-    static void strtokFileUndo();
-    static void strtokFilePutBack(const char *);
-private:
-    static char *lastToken;
-    static std::queue<std::string> undo;
+
+    /**
+     * 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();
+
+    /// \return true if the last parsed token was quoted
+    static bool LastTokenWasQuoted() {return (LastTokenType == ConfigParser::QuotedToken);}
+
+    /**
+     * \return the next quoted string or the raw string data until the end of line.
+     * This method allows %macros in unquoted strings to keep compatibility
+     * for the logformat option.
+     */
+    static char *NextQuotedOrToEol();
+
+    /**
+     * Undo last NextToken call. The next call to NextToken() method will return
+     * again the last parsed element.
+     * Can not be called repeatedly to undo multiple NextToken calls. In this case
+     * the behaviour is undefined.
+     */
+    static void TokenUndo();
+
+    /**
+     * The next NextToken call will return the token as next element
+     * It can be used repeatedly to add more than one tokens in a FIFO list.
+     */
+    static void TokenPutBack(const char *token);
+
+    /// Set the configuration file line to parse.
+    static void SetCfgLine(char *line);
+
+    /// Allow %macros inside quoted strings
+    static void EnableMacros() {AllowMacros_ = true;}
+
+    /// Do not allow %macros inside quoted strings
+    static void DisableMacros() {AllowMacros_ = false;}
+
+    /// configuration_includes_quoted_values in squid.conf
+    static int RecognizeQuotedValues;
+
+protected:
+    /**
+     * Class used to store required information for the current
+     * configuration file.
+     */
+    class CfgFile
+    {
+    public:
+        CfgFile(): wordFile(NULL), parsePos(NULL), lineNo(0) { parseBuffer[0] = '\0';}
+        ~CfgFile();
+        /// True if the configuration file is open
+        bool isOpen() {return wordFile != NULL;}
+
+        /**
+         * Open the file given by 'path' and initializes the CfgFile object
+         * to start parsing
+         */
+        bool startParse(char *path);
+
+        /**
+         * Do the next parsing step:
+         * reads the next line from file if required.
+         * \return the body of next element or a NULL pointer if there are no more token elements in the file.
+         * \param type will be filled with the ConfigParse::TokenType for any element found, or left unchanged if NULL is returned.
+         */
+        char *parse(TokenType &type);
+
+    private:
+        bool getFileLine();   ///< Read the next line from the file
+        /**
+         * Return the body of the next element. If the wasQuoted is given
+         * set to true if the element was quoted.
+         */
+        char *nextElement(TokenType &type);
+        FILE *wordFile; ///< Pointer to the file.
+        char parseBuffer[CONFIG_LINE_LIMIT]; ///< Temporary buffer to store data to parse
+        char *parsePos; ///< The next element position in parseBuffer string
+    public:
+        std::string filePath; ///< The file path
+        std::string currentLine; ///< The current line to parse
+        int lineNo; ///< Current line number
+    };
+
+    /**
+     * Return the last TokenUndo() or TokenPutBack() queued element, or NULL
+     * if none exist
+     */
+    static char *Undo();
+
+    /**
+     * Unquotes the token, which must be quoted.
+     * \param end if it is not NULL, it is set to the end of token.
+     */
+    static char *UnQuote(char *token, char **end = NULL);
+
+    /**
+     * Does the real tokens parsing job: Ignore comments, unquote an
+     * element if required.
+     * \return the next token, or NULL if there are no available tokens in the nextToken string.
+     * \param nextToken updated to point to the pos after parsed token.
+     * \param type      The token type
+     * \param legacy    If it is true function-like parameters are not allowed
+     */
+    static char *TokenParse(char * &nextToken, TokenType &type, bool legacy = false);
+
+    /// Wrapper method for TokenParse.
+    static char *NextElement(TokenType &type, bool legacy = false);
+    static std::stack<CfgFile *> CfgFiles; ///< The stack of open cfg files
+    static TokenType LastTokenType; ///< The type of last parsed element
+    static char *LastToken; ///< Points to the last parsed token
+    static char *CfgLine; ///< The current line to parse
+    static char *CfgPos; ///< Pointer to the next element in cfgLine string
+    static std::queue<std::string> Undo_; ///< The list with TokenUndo() or TokenPutBack() queued elements
+    static bool AllowMacros_;
 };
 
 int parseConfigFile(const char *file_name);
index c82b9b5d85595fe99d3e42766afe12a147050d16..ba46f0411182bf140d46a1aefb6bbb96eb2ffa4b 100644 (file)
@@ -1,5 +1,6 @@
 #include "squid.h"
 #include "cache_cf.h"
+#include "ConfigParser.h"
 #include "Debug.h"
 #include "HelperChildConfig.h"
 #include "globals.h"
@@ -44,7 +45,7 @@ HelperChildConfig::needNew() const
 void
 HelperChildConfig::parseConfig()
 {
-    char const *token = strtok(NULL, w_space);
+    char const *token = ConfigParser::NextToken();
 
     if (!token)
         self_destruct();
@@ -58,7 +59,7 @@ HelperChildConfig::parseConfig()
     }
 
     /* Parse extension options */
-    for (; (token = strtok(NULL, w_space)) ;) {
+    for (; (token = ConfigParser::NextToken()) ;) {
         if (strncmp(token, "startup=", 8) == 0) {
             n_startup = xatoui(token + 8);
         } else if (strncmp(token, "idle=", 5) == 0) {
index 1258da77d813379beffbf400b9a7381c89ff7388..3152910e76ba4439552687bfbc91eaa6a2c3644c 100644 (file)
@@ -92,9 +92,8 @@ Notes::add(const String &noteKey)
 Note::Pointer
 Notes::parse(ConfigParser &parser)
 {
-    String key, value;
-    ConfigParser::ParseString(&key);
-    ConfigParser::ParseQuotedString(&value);
+    String key = ConfigParser::NextToken();
+    String value = ConfigParser::NextToken();
     Note::Pointer note = add(key);
     Note::Value::Pointer noteValue = note->addValue(value);
 
index 2e9b75d0dfbb05b0f2cb336cb55d05a1e004926f..267ed6775633e6bde13ff1089685c88ad3619608 100644 (file)
@@ -147,7 +147,7 @@ xatos(const char *token)
 int64_t
 GetInteger64(void)
 {
-    char *token = strtok(NULL, w_space);
+    char *token = ConfigParser::NextToken();
 
     if (token == NULL)
         self_destruct();
@@ -162,7 +162,7 @@ GetInteger64(void)
 int
 GetInteger(void)
 {
-    char *token = ConfigParser::strtokFile();
+    char *token = ConfigParser::NextToken();
     int i;
 
     if (token == NULL)
@@ -216,7 +216,7 @@ GetPercentage(void)
 unsigned short
 GetShort(void)
 {
-    char *token = strtok(NULL, w_space);
+    char *token = ConfigParser::NextToken();
 
     if (token == NULL)
         self_destruct();
index efa3e0665a740d3120c6a119535a0ec1d5d11935..2bb712ee9ff9dbf27deece803285dec4220c7aa1 100644 (file)
@@ -34,6 +34,7 @@
 #include "cache_cf.h"
 #include "compat/strtoll.h"
 #include "ConfigOption.h"
+#include "ConfigParser.h"
 #include "globals.h"
 #include "Parsing.h"
 #include "SquidConfig.h"
@@ -276,7 +277,7 @@ SwapDir::parseOptions(int isaReconfig)
 
     ConfigOption *newOption = getOptionTree();
 
-    while ((name = strtok(NULL, w_space)) != NULL) {
+    while ((name = ConfigParser::NextToken()) != NULL) {
         value = strchr(name, '=');
 
         if (value) {
index b5e1c31fd346494f8959d62b7fb44c273a05fb12..839e8b0c80d53ca39647000728f7d1b2f4680344 100644 (file)
@@ -73,10 +73,10 @@ ACLFlags::parseFlags()
 
     /*Regex code needs to parse -i file*/
     if ( isSet(ACL_F_REGEX_CASE))
-        ConfigParser::strtokFilePutBack("-i");
+        ConfigParser::TokenPutBack("-i");
 
     if (nextToken != NULL && strcmp(nextToken, "--") != 0 )
-        ConfigParser::strtokFileUndo();
+        ConfigParser::TokenUndo();
 }
 
 const char *
@@ -200,7 +200,7 @@ ACL::ParseAclLine(ConfigParser &parser, ACL ** head)
 
     /* snarf the ACL name */
 
-    if ((t = strtok(NULL, w_space)) == NULL) {
+    if ((t = ConfigParser::NextToken()) == NULL) {
         debugs(28, DBG_CRITICAL, "aclParseAclLine: missing ACL name.");
         parser.destruct();
         return;
@@ -217,7 +217,7 @@ ACL::ParseAclLine(ConfigParser &parser, ACL ** head)
     /* snarf the ACL type */
     const char *theType;
 
-    if ((theType = strtok(NULL, w_space)) == NULL) {
+    if ((theType = ConfigParser::NextToken()) == NULL) {
         debugs(28, DBG_CRITICAL, "aclParseAclLine: missing ACL type.");
         parser.destruct();
         return;
index d43f89f58c3841f34f19839cdbc5b9eeb1e3bd18..8d3c0a5681fea68cb9f3737a7487c85ae085ca04 100644 (file)
@@ -120,7 +120,7 @@ aclParseDenyInfoLine(AclDenyInfoList ** head)
 
     /* first expect a page name */
 
-    if ((t = strtok(NULL, w_space)) == NULL) {
+    if ((t = ConfigParser::NextToken()) == NULL) {
         debugs(28, DBG_CRITICAL, "aclParseDenyInfoLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
         debugs(28, DBG_CRITICAL, "aclParseDenyInfoLine: missing 'error page' parameter.");
         return;
@@ -133,7 +133,7 @@ aclParseDenyInfoLine(AclDenyInfoList ** head)
     /* next expect a list of ACL names */
     Tail = &A->acl_list;
 
-    while ((t = strtok(NULL, w_space))) {
+    while ((t = ConfigParser::NextToken())) {
         L = (AclNameList *)memAllocate(MEM_ACL_NAME_LIST);
         xstrncpy(L->name, t, ACL_NAME_SZ-1);
         *Tail = L;
@@ -157,7 +157,7 @@ void
 aclParseAccessLine(const char *directive, ConfigParser &, acl_access **treep)
 {
     /* first expect either 'allow' or 'deny' */
-    const char *t = ConfigParser::strtokFile();
+    const char *t = ConfigParser::NextToken();
 
     if (!t) {
         debugs(28, DBG_CRITICAL, "aclParseAccessLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
index 2908a4101b2bbe973496d0676df297edc03e76ed..d84eabddee3ded55b8e7ffae8be53a41fbd645db 100644 (file)
@@ -264,8 +264,7 @@ Adaptation::Config::DumpServiceGroups(StoreEntry *entry, const char *name)
 void
 Adaptation::Config::ParseAccess(ConfigParser &parser)
 {
-    String groupId;
-    ConfigParser::ParseString(&groupId);
+    String groupId = ConfigParser::NextToken();
     AccessRule *r;
     if (!(r=FindRuleByGroupId(groupId))) {
         r = new AccessRule(groupId);
index cc73254dee7ba88626939457362267a156e669e1..f6ecd79cf088ba177a29454e2184e44dca08e875 100644 (file)
@@ -61,10 +61,8 @@ Adaptation::ServiceConfig::parseVectPoint(const char *service_configConfig) cons
 bool
 Adaptation::ServiceConfig::parse()
 {
-    String method_point;
-
-    ConfigParser::ParseString(&key);
-    ConfigParser::ParseString(&method_point);
+    key = ConfigParser::NextToken();
+    String method_point = ConfigParser::NextToken();
     method = parseMethod(method_point.termedBuf());
     point = parseVectPoint(method_point.termedBuf());
 
@@ -76,7 +74,7 @@ Adaptation::ServiceConfig::parse()
     bool onOverloadSet = false;
     std::set<std::string> options;
 
-    while (char *option = strtok(NULL, w_space)) {
+    while (char *option = ConfigParser::NextToken()) {
         const char *name = option;
         const char *value = "";
         if (strcmp(option, "0") == 0) { // backward compatibility
index 4fee139d7477f5e0613df0af8cbf46262262f318..ad196bc1a9a45b74fae1a68b142474ac11770856 100644 (file)
@@ -23,7 +23,7 @@ Adaptation::ServiceGroup::~ServiceGroup()
 void
 Adaptation::ServiceGroup::parse()
 {
-    ConfigParser::ParseString(&id);
+    id = ConfigParser::NextToken();
 
     wordlist *names = NULL;
     ConfigParser::ParseWordList(&names);
index cd2233f62bbc611645c3696e0bd468718182da31..447f85156348b7f63bccb81f662af9f09ceb0ccb 100644 (file)
@@ -1023,7 +1023,7 @@ parseTimeLine(time_msec_t * tptr, const char *units,  bool allowMsec)
     if ((u = parseTimeUnits(units, allowMsec)) == 0)
         self_destruct();
 
-    if ((token = strtok(NULL, w_space)) == NULL)
+    if ((token = ConfigParser::NextToken()) == NULL)
         self_destruct();
 
     d = xatof(token);
@@ -1032,7 +1032,7 @@ parseTimeLine(time_msec_t * tptr, const char *units,  bool allowMsec)
 
     if (0 == d)
         (void) 0;
-    else if ((token = strtok(NULL, w_space)) == NULL)
+    else if ((token = ConfigParser::NextToken()) == NULL)
         debugs(3, DBG_CRITICAL, "WARNING: No units on '" <<
                config_input_line << "', assuming " <<
                d << " " << units  );
@@ -1099,7 +1099,7 @@ parseBytesLine64(int64_t * bptr, const char *units)
         return;
     }
 
-    if ((token = strtok(NULL, w_space)) == NULL) {
+    if ((token = ConfigParser::NextToken()) == NULL) {
         self_destruct();
         return;
     }
@@ -1115,7 +1115,7 @@ parseBytesLine64(int64_t * bptr, const char *units)
 
     if (0.0 == d)
         (void) 0;
-    else if ((token = strtok(NULL, w_space)) == NULL)
+    else if ((token = ConfigParser::NextToken()) == NULL)
         debugs(3, DBG_CRITICAL, "WARNING: No units on '" <<
                config_input_line << "', assuming " <<
                d << " " <<  units  );
@@ -1146,7 +1146,7 @@ parseBytesLine(size_t * bptr, const char *units)
         return;
     }
 
-    if ((token = strtok(NULL, w_space)) == NULL) {
+    if ((token = ConfigParser::NextToken()) == NULL) {
         self_destruct();
         return;
     }
@@ -1162,7 +1162,7 @@ parseBytesLine(size_t * bptr, const char *units)
 
     if (0.0 == d)
         (void) 0;
-    else if ((token = strtok(NULL, w_space)) == NULL)
+    else if ((token = ConfigParser::NextToken()) == NULL)
         debugs(3, DBG_CRITICAL, "WARNING: No units on '" <<
                config_input_line << "', assuming " <<
                d << " " <<  units  );
@@ -1194,7 +1194,7 @@ parseBytesLineSigned(ssize_t * bptr, const char *units)
         return;
     }
 
-    if ((token = strtok(NULL, w_space)) == NULL) {
+    if ((token = ConfigParser::NextToken()) == NULL) {
         self_destruct();
         return;
     }
@@ -1210,7 +1210,7 @@ parseBytesLineSigned(ssize_t * bptr, const char *units)
 
     if (0.0 == d)
         (void) 0;
-    else if ((token = strtok(NULL, w_space)) == NULL)
+    else if ((token = ConfigParser::NextToken()) == NULL)
         debugs(3, DBG_CRITICAL, "WARNING: No units on '" <<
                config_input_line << "', assuming " <<
                d << " " <<  units  );
@@ -1367,7 +1367,7 @@ dump_address(StoreEntry * entry, const char *name, Ip::Address &addr)
 static void
 parse_address(Ip::Address *addr)
 {
-    char *token = strtok(NULL, w_space);
+    char *token = ConfigParser::NextToken();
 
     if (!token) {
         self_destruct();
@@ -1475,7 +1475,7 @@ parse_acl_tos(acl_tos ** head)
     acl_tos *l;
     acl_tos **tail = head;     /* sane name below */
     unsigned int tos;           /* Initially uint for strtoui. Casted to tos_t before return */
-    char *token = strtok(NULL, w_space);
+    char *token = ConfigParser::NextToken();
 
     if (!token) {
         self_destruct();
@@ -1546,7 +1546,7 @@ parse_acl_nfmark(acl_nfmark ** head)
     acl_nfmark *l;
     acl_nfmark **tail = head;  /* sane name below */
     nfmark_t mark;
-    char *token = strtok(NULL, w_space);
+    char *token = ConfigParser::NextToken();
 
     if (!token) {
         self_destruct();
@@ -1748,7 +1748,7 @@ parse_http_header_access(HeaderManglers **pm)
 {
     char *t = NULL;
 
-    if ((t = strtok(NULL, w_space)) == NULL) {
+    if ((t = ConfigParser::NextToken()) == NULL) {
         debugs(3, DBG_CRITICAL, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
         debugs(3, DBG_CRITICAL, "parse_http_header_access: missing header name.");
         return;
@@ -1787,7 +1787,7 @@ parse_http_header_replace(HeaderManglers **pm)
 {
     char *t = NULL;
 
-    if ((t = strtok(NULL, w_space)) == NULL) {
+    if ((t = ConfigParser::NextToken()) == NULL) {
         debugs(3, DBG_CRITICAL, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
         debugs(3, DBG_CRITICAL, "parse_http_header_replace: missing header name.");
         return;
@@ -1832,10 +1832,10 @@ parse_authparam(Auth::ConfigVector * config)
     char *type_str;
     char *param_str;
 
-    if ((type_str = strtok(NULL, w_space)) == NULL)
+    if ((type_str = ConfigParser::NextToken()) == NULL)
         self_destruct();
 
-    if ((param_str = strtok(NULL, w_space)) == NULL)
+    if ((param_str = ConfigParser::NextToken()) == NULL)
         self_destruct();
 
     /* find a configuration for the scheme in the currently parsed configs... */
@@ -1906,10 +1906,10 @@ parse_cachedir(SquidConfig::_cacheSwap * swap)
     int i;
     int fs;
 
-    if ((type_str = strtok(NULL, w_space)) == NULL)
+    if ((type_str = ConfigParser::NextToken()) == NULL)
         self_destruct();
 
-    if ((path_str = strtok(NULL, w_space)) == NULL)
+    if ((path_str = ConfigParser::NextToken()) == NULL)
         self_destruct();
 
     fs = find_fstype(type_str);
@@ -2064,7 +2064,7 @@ GetService(const char *proto)
 {
     struct servent *port = NULL;
     /** Parses a port number or service name from the squid.conf */
-    char *token = strtok(NULL, w_space);
+    char *token = ConfigParser::NextToken();
     if (token == NULL) {
         self_destruct();
         return 0; /* NEVER REACHED */
@@ -2112,14 +2112,14 @@ parse_peer(CachePeer ** head)
     p->basetime = 0;
     p->stats.logged_state = PEER_ALIVE;
 
-    if ((token = strtok(NULL, w_space)) == NULL)
+    if ((token = ConfigParser::NextToken()) == NULL)
         self_destruct();
 
     p->host = xstrdup(token);
 
     p->name = xstrdup(token);
 
-    if ((token = strtok(NULL, w_space)) == NULL)
+    if ((token = ConfigParser::NextToken()) == NULL)
         self_destruct();
 
     p->type = parseNeighborType(token);
@@ -2137,7 +2137,7 @@ parse_peer(CachePeer ** head)
     p->icp.port = GetUdpService();
     p->connection_auth = 2;    /* auto */
 
-    while ((token = strtok(NULL, w_space))) {
+    while ((token = ConfigParser::NextToken())) {
         if (!strcmp(token, "proxy-only")) {
             p->options.proxy_only = true;
         } else if (!strcmp(token, "no-query")) {
@@ -2521,7 +2521,7 @@ parse_peer_access(void)
     char *host = NULL;
     CachePeer *p;
 
-    if (!(host = strtok(NULL, w_space)))
+    if (!(host = ConfigParser::NextToken()))
         self_destruct();
 
     if ((p = peerFindByName(host)) == NULL) {
@@ -2540,10 +2540,10 @@ parse_hostdomain(void)
     char *host = NULL;
     char *domain = NULL;
 
-    if (!(host = strtok(NULL, w_space)))
+    if (!(host = ConfigParser::NextToken()))
         self_destruct();
 
-    while ((domain = strtok(NULL, list_sep))) {
+    while ((domain = ConfigParser::NextToken())) {
         CachePeerDomainList *l = NULL;
         CachePeerDomainList **L = NULL;
         CachePeer *p;
@@ -2575,13 +2575,13 @@ parse_hostdomaintype(void)
     char *type = NULL;
     char *domain = NULL;
 
-    if (!(host = strtok(NULL, w_space)))
+    if (!(host = ConfigParser::NextToken()))
         self_destruct();
 
-    if (!(type = strtok(NULL, w_space)))
+    if (!(type = ConfigParser::NextToken()))
         self_destruct();
 
-    while ((domain = strtok(NULL, list_sep))) {
+    while ((domain = ConfigParser::NextToken())) {
         NeighborTypeDomainList *l = NULL;
         NeighborTypeDomainList **L = NULL;
         CachePeer *p;
@@ -2629,7 +2629,7 @@ dump_onoff(StoreEntry * entry, const char *name, int var)
 void
 parse_onoff(int *var)
 {
-    char *token = strtok(NULL, w_space);
+    char *token = ConfigParser::NextToken();
 
     if (token == NULL)
         self_destruct();
@@ -2670,7 +2670,7 @@ dump_tristate(StoreEntry * entry, const char *name, int var)
 static void
 parse_tristate(int *var)
 {
-    char *token = strtok(NULL, w_space);
+    char *token = ConfigParser::NextToken();
 
     if (token == NULL)
         self_destruct();
@@ -2710,7 +2710,7 @@ parse_pipelinePrefetch(int *var)
         debugs(0, DBG_PARSE_NOTE(2), "WARNING: 'pipeline_prefetch off' is deprecated. Please update to use '0'.");
         *var = 0;
     } else {
-        ConfigParser::strtokFileUndo();
+        ConfigParser::TokenUndo();
         parse_int(var);
     }
 }
@@ -2803,17 +2803,17 @@ parse_refreshpattern(RefreshPattern ** head)
     int errcode;
     int flags = REG_EXTENDED | REG_NOSUB;
 
-    if ((token = strtok(NULL, w_space)) == NULL) {
+    if ((token = ConfigParser::NextToken()) == NULL) {
         self_destruct();
         return;
     }
 
     if (strcmp(token, "-i") == 0) {
         flags |= REG_ICASE;
-        token = strtok(NULL, w_space);
+        token = ConfigParser::NextToken();
     } else if (strcmp(token, "+i") == 0) {
         flags &= ~REG_ICASE;
-        token = strtok(NULL, w_space);
+        token = ConfigParser::NextToken();
     }
 
     if (token == NULL) {
@@ -2856,7 +2856,7 @@ parse_refreshpattern(RefreshPattern ** head)
     max = (time_t) (i * 60);   /* convert minutes to seconds */
 
     /* Options */
-    while ((token = strtok(NULL, w_space)) != NULL) {
+    while ((token = ConfigParser::NextToken()) != NULL) {
         if (!strcmp(token, "refresh-ims")) {
             refresh_ims = 1;
         } else if (!strcmp(token, "store-stale")) {
@@ -2987,7 +2987,7 @@ dump_string(StoreEntry * entry, const char *name, char *var)
 static void
 parse_string(char **var)
 {
-    char *token = strtok(NULL, w_space);
+    char *token = ConfigParser::NextToken();
     safe_free(*var);
 
     if (token == NULL)
@@ -2996,23 +2996,6 @@ parse_string(char **var)
     *var = xstrdup(token);
 }
 
-void
-ConfigParser::ParseString(char **var)
-{
-    parse_string(var);
-}
-
-void
-ConfigParser::ParseString(String *var)
-{
-    char *token = strtok(NULL, w_space);
-
-    if (token == NULL)
-        self_destruct();
-
-    var->reset(token);
-}
-
 static void
 free_string(char **var)
 {
@@ -3027,7 +3010,7 @@ parse_eol(char *volatile *var)
         return;
     }
 
-    unsigned char *token = (unsigned char *) strtok(NULL, null_string);
+    unsigned char *token = (unsigned char *) ConfigParser::NextQuotedOrToEol();
     safe_free(*var);
 
     if (!token) {
@@ -3261,9 +3244,7 @@ void
 parse_wordlist(wordlist ** list)
 {
     char *token;
-    char *t = strtok(NULL, "");
-
-    while ((token = strwordtok(NULL, &t)))
+    while ((token = ConfigParser::NextToken()))
         wordlistAdd(list, token);
 }
 
@@ -3288,7 +3269,7 @@ check_null_acl_access(acl_access * a)
 static void
 parse_uri_whitespace(int *var)
 {
-    char *token = strtok(NULL, w_space);
+    char *token = ConfigParser::NextToken();
 
     if (token == NULL)
         self_destruct();
@@ -3401,7 +3382,7 @@ free_memcachemode(SquidConfig * config)
 static void
 parse_memcachemode(SquidConfig * config)
 {
-    char *token = strtok(NULL, w_space);
+    char *token = ConfigParser::NextToken();
     if (!token)
         self_destruct();
 
@@ -3471,7 +3452,7 @@ parse_IpAddress_list(Ip::Address_list ** head)
     Ip::Address_list *s;
     Ip::Address ipa;
 
-    while ((token = strtok(NULL, w_space))) {
+    while ((token = ConfigParser::NextToken())) {
         if (GetHostWithPort(token, &ipa)) {
 
             while (*head)
@@ -3812,7 +3793,7 @@ parsePortCfg(AnyP::PortCfg ** head, const char *optionName)
         return;
     }
 
-    char *token = strtok(NULL, w_space);
+    char *token = ConfigParser::NextToken();
 
     if (!token) {
         self_destruct();
@@ -3823,7 +3804,7 @@ parsePortCfg(AnyP::PortCfg ** head, const char *optionName)
     parsePortSpecification(s, token);
 
     /* parse options ... */
-    while ((token = strtok(NULL, w_space))) {
+    while ((token = ConfigParser::NextToken())) {
         parse_port_option(s, token);
     }
 
@@ -4071,7 +4052,7 @@ parse_access_log(CustomLog ** logs)
 
     /* determine configuration style */
 
-    const char *filename = strtok(NULL, w_space);
+    const char *filename = ConfigParser::NextToken();
     if (!filename) {
         self_destruct();
         return;
@@ -4096,7 +4077,7 @@ parse_access_log(CustomLog ** logs)
         // if logformat name is not recognized,
         // put back the token; it must be an ACL name
         if (!setLogformat(cl, token, false))
-            ConfigParser::strtokFileUndo();
+            ConfigParser::TokenUndo();
     } else { // style #4
         do {
             if (strncasecmp(token, "on-error=", 9) == 0) {
@@ -4115,7 +4096,7 @@ parse_access_log(CustomLog ** logs)
                 setLogformat(cl, token+10, true);
             } else if (!strchr(token, '=')) {
                 // put back the token; it must be an ACL name
-                ConfigParser::strtokFileUndo();
+                ConfigParser::TokenUndo();
                 break; // done with name=value options, now to ACLs
             } else {
                 debugs(3, DBG_CRITICAL, "Unknown access_log option " << token);
@@ -4308,8 +4289,8 @@ parse_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap)
     if (!*cpuAffinityMap)
         *cpuAffinityMap = new CpuAffinityMap;
 
-    const char *const pToken = strtok(NULL, w_space);
-    const char *const cToken = strtok(NULL, w_space);
+    const char *const pToken = ConfigParser::NextToken();
+    const char *const cToken = ConfigParser::NextToken();
     Vector<int> processes, cores;
     if (!parseNamedIntList(pToken, "process_numbers", processes)) {
         debugs(3, DBG_CRITICAL, "FATAL: bad 'process_numbers' parameter " <<
@@ -4441,7 +4422,7 @@ static void parse_icap_service_failure_limit(Adaptation::Icap::Config *cfg)
     time_t m;
     cfg->service_failure_limit = GetInteger();
 
-    if ((token = strtok(NULL, w_space)) == NULL)
+    if ((token = ConfigParser::NextToken()) == NULL)
         return;
 
     if (strcmp(token,"in") != 0) {
@@ -4449,7 +4430,7 @@ static void parse_icap_service_failure_limit(Adaptation::Icap::Config *cfg)
         self_destruct();
     }
 
-    if ((token = strtok(NULL, w_space)) == NULL) {
+    if ((token = ConfigParser::NextToken()) == NULL) {
         self_destruct();
     }
 
@@ -4459,7 +4440,7 @@ static void parse_icap_service_failure_limit(Adaptation::Icap::Config *cfg)
 
     if (0 == d)
         (void) 0;
-    else if ((token = strtok(NULL, w_space)) == NULL) {
+    else if ((token = ConfigParser::NextToken()) == NULL) {
         debugs(3, DBG_CRITICAL, "No time-units on '" << config_input_line << "'");
         self_destruct();
     } else if ((m = parseTimeUnits(token, false)) == 0)
@@ -4489,7 +4470,7 @@ static void parse_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt)
 {
     char *al;
     sslproxy_cert_adapt *ca = (sslproxy_cert_adapt *) xcalloc(1, sizeof(sslproxy_cert_adapt));
-    if ((al = strtok(NULL, w_space)) == NULL) {
+    if ((al = ConfigParser::NextToken()) == NULL) {
         self_destruct();
         return;
     }
@@ -4567,7 +4548,7 @@ static void parse_sslproxy_cert_sign(sslproxy_cert_sign **cert_sign)
 {
     char *al;
     sslproxy_cert_sign *cs = (sslproxy_cert_sign *) xcalloc(1, sizeof(sslproxy_cert_sign));
-    if ((al = strtok(NULL, w_space)) == NULL) {
+    if ((al = ConfigParser::NextToken()) == NULL) {
         self_destruct();
         return;
     }
@@ -4659,7 +4640,7 @@ static void parse_sslproxy_ssl_bump(acl_access **ssl_bump)
     static BumpCfgStyle bumpCfgStyleLast = bcsNone;
     BumpCfgStyle bumpCfgStyleNow = bcsNone;
     char *bm;
-    if ((bm = strtok(NULL, w_space)) == NULL) {
+    if ((bm = ConfigParser::NextToken()) == NULL) {
         self_destruct();
         return;
     }
@@ -4761,7 +4742,7 @@ static void parse_HeaderWithAclList(HeaderWithAclList **headers)
     if (!*headers) {
         *headers = new HeaderWithAclList;
     }
-    if ((fn = strtok(NULL, w_space)) == NULL) {
+    if ((fn = ConfigParser::NextToken()) == NULL) {
         self_destruct();
         return;
     }
@@ -4771,20 +4752,20 @@ static void parse_HeaderWithAclList(HeaderWithAclList **headers)
     if (hwa.fieldId == HDR_BAD_HDR)
         hwa.fieldId = HDR_OTHER;
 
-    String buf;
-    bool wasQuoted;
-    ConfigParser::ParseQuotedString(&buf, &wasQuoted);
+    Format::Format *nlf =  new ::Format::Format("hdrWithAcl");
+    ConfigParser::EnableMacros();
+    String buf = ConfigParser::NextToken();
+    ConfigParser::DisableMacros();
     hwa.fieldValue = buf.termedBuf();
-    hwa.quoted = wasQuoted;
+    hwa.quoted = ConfigParser::LastTokenWasQuoted();
     if (hwa.quoted) {
-        Format::Format *nlf =  new ::Format::Format("hdrWithAcl");
         if (!nlf->parse(hwa.fieldValue.c_str())) {
             self_destruct();
             return;
         }
         hwa.valueFormat = nlf;
-    }
-
+    } else
+        delete nlf;
     aclParseAclList(LegacyParser, &hwa.aclList, (hwa.fieldName + ':' + hwa.fieldValue).c_str());
     (*headers)->push_back(hwa);
 }
index 23cbc881c9a5374aec8c02efe454bf5a762eff93..b08964493e3c2ecab574ab3718b8a83ab5b29573 100644 (file)
@@ -65,6 +65,19 @@ COMMENT_START
   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.
+
+       Squid supports reading configuration option parameters from external
+       files using the syntax:
+               parameters("/path/filename")
+       For example:
+               acl whitelist dstdomain parameters("/etc/squid/whitelist.txt")
+
   Conditional configuration
 
        If-statements can be used to make configuration directives
@@ -8448,6 +8461,19 @@ COMMENT_START
  -----------------------------------------------------------------------------
 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" after a configuration
+       directive as a single parameter. The quotes are stripped before the
+       parameter value is interpreted or used.
+       See "Values with spaces, quotes, and other special characters"
+       section for more details.
+DOC_END
+
 NAME: memory_pools
 COMMENT: on|off
 TYPE: onoff
index 7d9e5591d183c73788aea98dc078ec37256e948f..246b3d940536f6bc7503bf774eba9014c1629ae7 100644 (file)
@@ -681,7 +681,8 @@ gen_parse(const EntryList &head, std::ostream &fout)
     "{\n"
     "\tchar\t*token;\n"
     "\tif ((token = strtok(buff, w_space)) == NULL) \n"
-    "\t\treturn 1;\t/* ignore empty lines */\n";
+    "\t\treturn 1;\t/* ignore empty lines */\n"
+    "\tConfigParser::SetCfgLine(strtok(NULL, \"\"));\n";
 
     for (EntryList::const_iterator e = head.begin(); e != head.end(); ++e)
         e->genParse(fout);
index f4e04766f85e63cc8bf73e596a03189d51894fb4..d8f85a1e96d114ab4635c545818118a4438fa299 100644 (file)
@@ -44,6 +44,7 @@
 #include "cache_cf.h"
 #include "client_side.h"
 #include "comm/Connection.h"
+#include "ConfigParser.h"
 #include "ExternalACL.h"
 #include "ExternalACLEntry.h"
 #include "fde.h"
@@ -330,14 +331,16 @@ parse_externalAclHelper(external_acl ** list)
     a->local_addr.setLocalhost();
     a->quote = external_acl::QUOTE_METHOD_URL;
 
-    token = strtok(NULL, w_space);
+    token = ConfigParser::NextToken();
 
     if (!token)
         self_destruct();
 
     a->name = xstrdup(token);
 
-    token = strtok(NULL, w_space);
+    // Allow supported %macros inside quoted tokens
+    ConfigParser::EnableMacros();
+    token = ConfigParser::NextToken();
 
     /* Parse options */
     while (token) {
@@ -386,8 +389,9 @@ parse_externalAclHelper(external_acl ** list)
             break;
         }
 
-        token = strtok(NULL, w_space);
+        token = ConfigParser::NextToken();
     }
+    ConfigParser::DisableMacros();
 
     /* check that child startup value is sane. */
     if (a->children.n_startup > a->children.n_max)
@@ -503,7 +507,7 @@ parse_externalAclHelper(external_acl ** list)
 
         *p = format;
         p = &format->next;
-        token = strtok(NULL, w_space);
+        token = ConfigParser::NextToken();
     }
 
     /* There must be at least one format token */
index 17c730933c36a5d99613d1868dfc90d729214d29..cb955a0bd8a2a5fc7a9fbfc9ec50d21ffeed6f78 100644 (file)
@@ -1,4 +1,5 @@
 #include "squid.h"
+#include "ConfigParser.h"
 #include "cache_cf.h"
 #include "Debug.h"
 #include "format/Config.h"
@@ -11,10 +12,10 @@ Format::FmtConfig::parseFormats()
 {
     char *name, *def;
 
-    if ((name = strtok(NULL, w_space)) == NULL)
+    if ((name = ConfigParser::NextToken()) == NULL)
         self_destruct();
 
-    if ((def = strtok(NULL, "\r\n")) == NULL) {
+    if ((def = ConfigParser::NextQuotedOrToEol()) == NULL) {
         self_destruct();
         return;
     }
index a998327cad70e0dcc50b8809caa083f509afc49a..4b4e6836f82a5bbe7f88b5db813aa274a5391e1a 100644 (file)
@@ -2,6 +2,7 @@
 #define _SQUID_FORMAT_FORMAT_H
 
 #include "base/RefCount.h"
+#include "ConfigParser.h"
 /*
  * Squid configuration allows users to define custom formats in
  * several components.
@@ -29,7 +30,7 @@ class Format
 {
 public:
     Format(const char *name);
-    ~Format();
+    virtual ~Format();
 
     /* very inefficent parser, but who cares, this needs to be simple */
     /* First off, let's tokenize, we'll optimize in a second pass.
index 04c2acca2ea78cfdc7bd00e78b43a01e00ea82d6..b300a4c20dc634cc0834b05b85c9961f4d1e494c 100644 (file)
@@ -209,7 +209,7 @@ Ip::Qos::Config::parseConfigLine()
     self_destruct();
 #endif
 
-    while ( (token = strtok(NULL, w_space)) ) {
+    while ( (token = ConfigParser::NextToken()) ) {
 
         // Work out TOS or mark. Default to TOS for backwards compatibility
         if (!(mark || tos)) {
index fdac505793e93025e2ea4d78f26b3b9190347401..bb0a872b75d60ad91c9246fb7b29b5cf0930377d 100644 (file)
@@ -1,5 +1,6 @@
 #include "squid.h"
 #include "cache_cf.h"
+#include "ConfigParser.h"
 #include "Debug.h"
 #include "log/Config.h"
 
@@ -10,18 +11,20 @@ Log::LogConfig::parseFormats()
 {
     char *name, *def;
 
-    if ((name = strtok(NULL, w_space)) == NULL)
+    if ((name = ConfigParser::NextToken()) == NULL)
         self_destruct();
 
-    if ((def = strtok(NULL, "\r\n")) == NULL) {
+    ::Format::Format *nlf = new ::Format::Format(name);
+
+    ConfigParser::EnableMacros();
+    if ((def = ConfigParser::NextQuotedOrToEol()) == NULL) {
         self_destruct();
         return;
     }
+    ConfigParser::DisableMacros();
 
     debugs(3, 2, "Log Format for '" << name << "' is '" << def << "'");
 
-    ::Format::Format *nlf = new ::Format::Format(name);
-
     if (!nlf->parse(def)) {
         self_destruct();
         return;
index 9bc906a2a9464338aca6cc018e80c20759af0e35..86217471340d7a86b81c0bff1846a21bdc8de3fe 100644 (file)
@@ -48,7 +48,6 @@ void requirePathnameExists(const char *name, const char *path) STUB_NOP
 void parse_time_t(time_t * var) STUB
 char * strtokFile(void) STUB_RETVAL(NULL)
 void ConfigParser::ParseUShort(unsigned short *var) STUB
-void ConfigParser::ParseString(String*) STUB
 void dump_acl_access(StoreEntry * entry, const char *name, acl_access * head) STUB
 void dump_acl_list(StoreEntry*, ACLList*) STUB
 YesNoNone::operator void*() const { STUB_NOP; return NULL; }
index db34cad0e3f3e948af945a437c03aebea8b76978..c1e4fce924c3cfbb42737905c4f67153fffead43 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "testACLMaxUserIP.h"
 #include "auth/AclMaxUserIp.h"
+#include "ConfigParser.h"
 
 #if HAVE_STDEXCEPT
 #include <stdexcept>
@@ -29,9 +30,9 @@ void
 testACLMaxUserIP::testParseLine()
 {
     /* a config line to pass with a lead-in token to seed the parser. */
-    char * line = xstrdup("token -s 1");
+    char * line = xstrdup("-s 1");
     /* seed the parser */
-    strtok(line, w_space);
+    ConfigParser::SetCfgLine(line);
     ACLMaxUserIP anACL("max_user_ip");
     anACL.parse();
     /* we want a maximum of one, and strict to be true */
index f0fb6dd417d0dc250fed19cc89a00b08179b869f..bb1cffc9eefa63cb5a1366aa04bf6f87f503a6f4 100644 (file)
@@ -9,6 +9,7 @@
 #include "auth/UserRequest.h"
 #include "auth/Scheme.h"
 #include "auth/Config.h"
+#include "ConfigParser.h"
 #include "Mem.h"
 
 CPPUNIT_TEST_SUITE_REGISTRATION( testAuth );
@@ -92,6 +93,7 @@ setup_scheme(Auth::Config *scheme, char const **params, unsigned param_count)
     for (unsigned position=0; position < param_count; ++position) {
         char *param_str=xstrdup(params[position]);
         strtok(param_str, w_space);
+        ConfigParser::SetCfgLine(strtok(NULL, ""));
         scheme->parse(scheme, config.size(), param_str);
     }
 }
index 2ac31e67d1ffc2178b587b6511c887ed509b1a09..a7cd80dbcd8f7e63d27bf5826ed7e5474f5fc2c7 100644 (file)
@@ -21,24 +21,15 @@ bool testConfigParser::doParseQuotedTest(const char *s, const char *expectInterp
 {
     char cfgline[2048];
     char cfgparam[2048];
-    snprintf(cfgline, 2048, "Config %s", s);
-
-    // Points to the start of quoted string
-    const char *tmp = strchr(cfgline, ' ');
-
-    if (tmp == NULL) {
-        fprintf(stderr, "Invalid config line: %s\n", s);
-        return false;
-    }
+    snprintf(cfgline, 2048, "%s", s);
 
     // Keep the initial value on cfgparam. The ConfigParser  methods will write on cfgline
-    strncpy(cfgparam, tmp+1, sizeof(cfgparam)-1);
+    strncpy(cfgparam, cfgline, sizeof(cfgparam)-1);
     cfgparam[sizeof(cfgparam)-1] = '\0';
 
     // Initialize parser to point to the start of quoted string
-    strtok(cfgline, w_space);
-    String unEscaped;
-    ConfigParser::ParseQuotedString(&unEscaped);
+    ConfigParser::SetCfgLine(cfgline);
+    String unEscaped = ConfigParser::NextToken();
 
     const bool interpOk = (unEscaped.cmp(expectInterp) == 0);
     if (!interpOk) {
index 72752186b8eae0bb17535f325a10fa52dac0ec7b..ffec2b4c90b1bf7493ba311d50cc811664322443 100644 (file)
@@ -1,5 +1,6 @@
 #define SQUID_UNIT_TEST 1
 #include "squid.h"
+#include "ConfigParser.h"
 #include "testCoss.h"
 #include "Store.h"
 #include "SwapDir.h"
@@ -91,9 +92,9 @@ testCoss::testCossCreate()
 
     char *path=xstrdup(TESTDIR);
 
-    char *config_line=xstrdup("foo 100 max-size=102400 block-size=512 IOEngine=Blocking");
+    char *config_line=xstrdup("100 max-size=102400 block-size=512 IOEngine=Blocking");
 
-    strtok(config_line, w_space);
+    ConfigParser::SetCfgLine(config_line);
 
     aStore->parse(0, path);
 
@@ -155,9 +156,9 @@ testCoss::testCossSearch()
 
     char *path=xstrdup(TESTDIR);
 
-    char *config_line=xstrdup("foo 100 max-size=102400 block-size=512 IOEngine=Blocking");
+    char *config_line=xstrdup("100 max-size=102400 block-size=512 IOEngine=Blocking");
 
-    strtok(config_line, w_space);
+    ConfigParser::SetCfgLine(config_line);
 
     aStore->parse(0, path);
 
@@ -283,8 +284,8 @@ testCoss::testDefaultEngine()
     commonInit();
 
     char *path=xstrdup(TESTDIR);
-    char *config_line=xstrdup("foo 100 max-size=102400 block-size=512");
-    strtok(config_line, w_space);
+    char *config_line=xstrdup("100 max-size=102400 block-size=512");
+    ConfigParser::SetCfgLine(config_line);
     aStore->parse(0, path);
     safe_free(path);
     safe_free(config_line);
index a15e3faf321a186fa7f92ca945af60b8414689ad..f1d7e3b1b3399000bccf7f41984d3651a6160d64 100644 (file)
@@ -1,6 +1,7 @@
 #define SQUID_UNIT_TEST 1
 #include "squid.h"
 
+#include "ConfigParser.h"
 #include "DiskIO/DiskIOModule.h"
 #include "fs/rock/RockSwapDir.h"
 #include "globals.h"
@@ -66,9 +67,9 @@ testRock::setUp()
 
     char *path=xstrdup(TESTDIR);
 
-    char *config_line=xstrdup("foo 10 max-size=16384");
+    char *config_line=xstrdup("10 max-size=16384");
 
-    strtok(config_line, w_space);
+    ConfigParser::SetCfgLine(config_line);
 
     store->parse(0, path);
     store_maxobjsize = 1024*1024*2;
index 7e8563fc9a38d11e568885ca2e980bde6a3aed64..92c89c60975a2b0f334f9cf3de39bb9c27e9450e 100644 (file)
@@ -104,11 +104,11 @@ testUfs::testUfsSearch()
 
     char *path=xstrdup(TESTDIR);
 
-    char *config_line=xstrdup("foo 100 1 1");
+    char *config_line=xstrdup("100 1 1");
 
     visible_appname_string = xstrdup(PACKAGE "/" VERSION);
 
-    strtok(config_line, w_space);
+    ConfigParser::SetCfgLine(config_line);
 
     aStore->parse(0, path);
     store_maxobjsize = 1024*1024*2;
@@ -244,8 +244,8 @@ testUfs::testUfsDefaultEngine()
     mem_policy = createRemovalPolicy(Config.replPolicy);
 
     char *path=xstrdup(TESTDIR);
-    char *config_line=xstrdup("foo 100 1 1");
-    strtok(config_line, w_space);
+    char *config_line=xstrdup("100 1 1");
+    ConfigParser::SetCfgLine(config_line);
     aStore->parse(0, path);
     safe_free(path);
     safe_free(config_line);
index b2c695a3a986610e4fd10c1c5c5038c37307ee6b..c710bccc4dae340aa4dd573b2982962b936a4a53 100644 (file)
@@ -39,6 +39,7 @@
 #include "comm/Connection.h"
 #include "comm/Loops.h"
 #include "compat/strsep.h"
+#include "ConfigParser.h"
 #include "event.h"
 #include "ip/Address.h"
 #include "md5.h"
@@ -2013,7 +2014,7 @@ parse_wccp2_method(int *method)
     char *t;
 
     /* Snarf the method */
-    if ((t = strtok(NULL, w_space)) == NULL) {
+    if ((t = ConfigParser::NextToken()) == NULL) {
         debugs(80, DBG_CRITICAL, "wccp2_*_method: missing setting.");
         self_destruct();
     }
@@ -2060,7 +2061,7 @@ parse_wccp2_amethod(int *method)
     char *t;
 
     /* Snarf the method */
-    if ((t = strtok(NULL, w_space)) == NULL) {
+    if ((t = ConfigParser::NextToken()) == NULL) {
         debugs(80, DBG_CRITICAL, "wccp2_assignment_method: missing setting.");
         self_destruct();
     }
@@ -2116,7 +2117,7 @@ parse_wccp2_service(void *v)
     }
 
     /* Snarf the type */
-    if ((t = strtok(NULL, w_space)) == NULL) {
+    if ((t = ConfigParser::NextToken()) == NULL) {
         debugs(80, DBG_CRITICAL, "wccp2ParseServiceInfo: missing service info type (standard|dynamic)");
         self_destruct();
     }
@@ -2141,7 +2142,7 @@ parse_wccp2_service(void *v)
     memset(wccp_password, 0, sizeof(wccp_password));
     /* Handle password, if any */
 
-    if ((t = strtok(NULL, w_space)) != NULL) {
+    if ((t = ConfigParser::NextToken()) != NULL) {
         if (strncmp(t, "password=", 9) == 0) {
             security_type = WCCP2_MD5_SECURITY;
             strncpy(wccp_password, t + 9, WCCP2_PASSWORD_LEN);
@@ -2317,7 +2318,7 @@ parse_wccp2_service_info(void *v)
     }
 
     /* Next: loop until we don't have any more tokens */
-    while ((t = strtok(NULL, w_space)) != NULL) {
+    while ((t = ConfigParser::NextToken()) != NULL) {
         if (strncmp(t, "flags=", 6) == 0) {
             /* XXX eww, string pointer math */
             flags = parse_wccp2_service_flags(t + 6);