=== modified file 'src/ConfigParser.cc'
--- src/ConfigParser.cc	2013-07-22 01:26:09 +0000
+++ src/ConfigParser.cc	2013-08-07 07:12:25 +0000
@@ -21,377 +21,495 @@
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  *
  * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
  */
 
 #include "squid.h"
 #include "cache_cf.h"
 #include "ConfigParser.h"
 #include "Debug.h"
 #include "fatal.h"
 #include "globals.h"
 
-int ConfigParser::RecognizeQuotedValues = true;
+bool ConfigParser::RecognizeQuotedValues = true;
+bool ConfigParser::StrictMode = 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;
+const char *ConfigParser::CfgLine = NULL;
+const char *ConfigParser::CfgPos = NULL;
+std::queue<char *> ConfigParser::CfgLineTokens_;
 std::queue<std::string> ConfigParser::Undo_;
 bool ConfigParser::AllowMacros_ = false;
+bool ConfigParser::ParseRegex_ = false;
+bool ConfigParser::ParseQuotedOrToEOL_ = false;
+bool ConfigParser::PreviewMode_ = false;
+
+static const char *SQUID_ERROR_TOKEN = "SQUID_ERROR_TOKEN";
 
 void
 ConfigParser::destruct()
 {
     shutting_down = 1;
     if (!CfgFiles.empty()) {
         std::ostringstream message;
         CfgFile *f = CfgFiles.top();
-        message << "Bungled " << f->filePath << " line " << f->lineNo <<
+        message << "Bungled (#1)" << 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",
+        fatalf("Bungled (#2) %s line %d: %s",
                cfg_filename, config_lineno, config_input_line);
 }
 
 void
-ConfigParser::TokenUndo()
-{
-    assert(LastToken);
-    Undo_.push(LastToken);
-}
-
-void
 ConfigParser::TokenPutBack(const char *tok)
 {
     assert(tok);
     Undo_.push(tok);
 }
 
 char *
 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();
+        if (!PreviewMode_)
+            Undo_.pop();
         return undoToken;
     }
     return NULL;
 }
 
 char *
 ConfigParser::strtokFile()
 {
     if (RecognizeQuotedValues)
         return ConfigParser::NextToken();
 
     static int fromFile = 0;
     static FILE *wordFile = NULL;
 
     char *t;
     LOCAL_ARRAY(char, buf, CONFIG_LINE_LIMIT);
 
-    if ((LastToken = ConfigParser::Undo()))
-        return LastToken;
+    if ((t = ConfigParser::Undo()))
+        return t;
 
     do {
 
         if (!fromFile) {
             ConfigParser::TokenType tokenType;
-            t = ConfigParser::NextElement(tokenType, true);
+            t = ConfigParser::NextElement(tokenType);
             if (!t) {
                 return NULL;
-            } else if (tokenType == ConfigParser::QuotedToken) {
-                /* quote found, start reading from file */
+            } else if (*t == '\"' || *t == '\'') {
+                /* quote found, start reading from file */                
                 debugs(3, 8,"Quoted token found : " << t);
+                char *fn = ++t;
 
-                if ((wordFile = fopen(t, "r")) == NULL) {
+                while (*t && *t != '\"' && *t != '\'')
+                    ++t;
+
+                *t = '\0';
+
+                if ((wordFile = fopen(fn, "r")) == NULL) {
                     debugs(3, DBG_CRITICAL, "Can not open file " << t << " for reading");
                     return NULL;
                 }
 
 #if _SQUID_WINDOWS_
                 setmode(fileno(wordFile), O_TEXT);
 #endif
 
                 fromFile = 1;
             } else {
-                return LastToken = t;
+                return t;
             }
         }
 
         /* fromFile */
         if (fgets(buf, CONFIG_LINE_LIMIT, wordFile) == NULL) {
             /* stop reading from file */
             fclose(wordFile);
             wordFile = NULL;
             fromFile = 0;
             return NULL;
         } else {
             char *t2, *t3;
             t = buf;
             /* skip leading and trailing white space */
             t += strspn(buf, w_space);
             t2 = t + strcspn(t, w_space);
             t3 = t2 + strspn(t2, w_space);
 
             while (*t3 && *t3 != '#') {
                 t2 = t3 + strcspn(t3, w_space);
                 t3 = t2 + strspn(t2, w_space);
             }
 
             *t2 = '\0';
         }
 
         /* skip comments */
         /* skip blank lines */
     } while ( *t == '#' || !*t );
 
-    return LastToken = t;
+    return t;
 }
 
 char *
-ConfigParser::UnQuote(char *token, char **end)
+ConfigParser::UnQuote(const char *token, const char **next)
 {
+    const char *errorStr = NULL;
+    const char *errorPos = NULL;
     char quoteChar = *token;
     assert(quoteChar == '"' || quoteChar == '\'');
-    char  *s = token + 1;
+    LOCAL_ARRAY(char, UnQuoted, CONFIG_LINE_LIMIT);
+    const char  *s = token + 1;
+    char *d = UnQuoted;
     /* scan until the end of the quoted string, unescaping " and \  */
-    while (*s && *s != quoteChar) {
-        if (*s == '\\' && isalnum(*( s + 1))) {
-            debugs(3, DBG_CRITICAL, "Unsupported escape sequence: " << s);
-            self_destruct();
+    while (*s && *s != quoteChar && !errorStr && (d - UnQuoted) < sizeof(UnQuoted)) {
+        if (*s == '\\') {
+            s++;
+            switch (*s) {
+            case 'r':
+                *d = '\r';
+                break;
+            case 'n':
+                *d = '\n';
+                break;
+            case 't':
+                *d = '\t';
+                break;
+            default:
+                if (isalnum(*s)) {
+                    errorStr = "Unsupported escape sequence";
+                    errorPos = s; 
+                }
+                *d = *s;
+                break;
+            }
         } else if (*s == '$' && quoteChar == '"') {
-            debugs(3, DBG_CRITICAL, "Unsupported cfg macro: " << s);
-            self_destruct();
+            errorStr = "Unsupported cfg macro";
+            errorPos = s;
         } 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);
-        }
+            errorStr = "Macros are not supported here";
+            errorPos = s;
+        } else
+            *d = *s;
         ++s;
+        ++d;
+    }
+
+    if (*s != quoteChar && !errorStr) {
+        errorStr = "missing quote char at the end of quoted string";
+        errorPos = s - 1;
     }
+    // The end of token
+    *d = '\0';
 
-    if (*s != quoteChar) {
-        debugs(3, DBG_CRITICAL, "missing '" << quoteChar << "' at the end of quoted string: " << (s-1));
-        self_destruct();
+    // We are expecting a separator after quoted string, space or one of "()#"
+    if (*(s + 1) != '\0' && !strchr(w_space "()#", *(s + 1)) && !errorStr) {
+        errorStr = "Expecting space after the end of quoted token";
+        errorPos = token;
+    }
+
+    if (errorStr) {
+        if (PreviewMode_)
+            strncpy(UnQuoted, SQUID_ERROR_TOKEN, sizeof(UnQuoted));
+        else {
+            debugs(3, DBG_CRITICAL, errorStr << ": " << errorPos);
+            self_destruct();
+        }
     }
-    *end = s;
-    return (token+1);
+
+    if (next)
+        *next = s + 1;
+    return UnQuoted;
 }
 
 void
 ConfigParser::SetCfgLine(char *line)
 {
     CfgLine = line;
     CfgPos = line;
+    while (!CfgLineTokens_.empty()) {
+        char *token = CfgLineTokens_.front();
+        CfgLineTokens_.pop();
+        free(token);
+    }
 }
 
 char *
-ConfigParser::TokenParse(char * &nextToken, ConfigParser::TokenType &type, bool legacy)
+ConfigParser::TokenParse(const char * &nextToken, ConfigParser::TokenType &type)
 {
     if (!nextToken || *nextToken == '\0')
         return NULL;
     type = ConfigParser::SimpleToken;
     nextToken += strspn(nextToken, w_space);
-    if (*nextToken == '"' || *nextToken == '\'') {
+
+    if (*nextToken == '#')
+        return NULL;
+
+    if (!ConfigParser::ParseRegex_ && ConfigParser::RecognizeQuotedValues && (*nextToken == '"' || *nextToken == '\'')) {
         type = ConfigParser::QuotedToken;
-        char *token = UnQuote(nextToken, &nextToken);
-        *nextToken = '\0';
-        ++nextToken;
+        char *token = xstrdup(UnQuote(nextToken, &nextToken));
+        CfgLineTokens_.push(token);
         return token;
     }
 
-    char *token = nextToken;
-    if (char *t = strchr(nextToken, '#'))
-        *t = '\0';
+    const char *tokenStart = nextToken;
     const char *sep;
-    if (legacy)
+    if (ConfigParser::ParseQuotedOrToEOL_)
+        sep = "\n";
+    else if (!ConfigParser::RecognizeQuotedValues || ConfigParser::ParseRegex_ || *nextToken == '(')
         sep = w_space;
     else
         sep = w_space "(";
     nextToken += strcspn(nextToken, sep);
 
-    if (!legacy && *nextToken == '(')
-        type = ConfigParser::FunctionNameToken;
-    else
-        type = ConfigParser::SimpleToken;
+    if (ConfigParser::RecognizeQuotedValues && *nextToken == '(') {
+        if (strncmp(tokenStart, "parameters", nextToken - tokenStart) == 0)
+            type = ConfigParser::FunctionParameters;
+        else {
+            if (PreviewMode_) {
+                char *err = xstrdup(SQUID_ERROR_TOKEN);
+                CfgLineTokens_.push(err);
+                return err;
+            } else {
+                debugs(3, DBG_CRITICAL, "Unknown cfg function: " << tokenStart);
+                self_destruct();
+            }
+        }
+    } else
+        type = (ConfigParser::ParseRegex_ ? ConfigParser::RegexPatternToken : ConfigParser::SimpleToken);
 
-    if (*nextToken != '\0') {
-        *nextToken = '\0';
-        ++nextToken;
+    char *token = NULL;
+    if (nextToken - tokenStart) {
+        if (ConfigParser::StrictMode && type == ConfigParser::SimpleToken) {
+            for (const char *s = tokenStart; s != nextToken; ++s) {
+                if (!isalnum(*s) && !strchr(".,()-=_%/:", *s)) {
+                    if (PreviewMode_) {
+                        char *err = xstrdup(SQUID_ERROR_TOKEN);
+                        CfgLineTokens_.push(err);
+                        return err;
+                    } else {
+                        debugs(3, DBG_CRITICAL, "Not alphanumeric character '"<< *s << "' in unquoted token " << tokenStart);
+                        self_destruct();
+                    }
+                }
+            }
+        }
+        token = xstrndup(tokenStart, nextToken - tokenStart + 1);
+        CfgLineTokens_.push(token);
     }
 
-    if (*token == '\0')
-        return NULL;
+    if (*nextToken != '\0' && *nextToken != '#') {
+        ++nextToken;
+    }
 
     return token;
 }
 
 char *
-ConfigParser::NextElement(ConfigParser::TokenType &type, bool legacy)
+ConfigParser::NextElement(ConfigParser::TokenType &type)
 {
-    char *token = TokenParse(CfgPos, type, legacy);
+    const char *pos = CfgPos;
+    char *token = TokenParse(pos, type);
+    if (!PreviewMode_ || type == FunctionParameters)
+        CfgPos = pos;
+    // else next call will read the same token
     return token;
 }
 
 char *
 ConfigParser::NextToken()
 {
-    if ((LastToken = ConfigParser::Undo()))
-        return LastToken;
-
     char *token = NULL;
+    if ((token = ConfigParser::Undo())) {
+        debugs(3, 6, "TOKEN (undone): " << token);
+        return token;
+    }
+
     do {
         while (token == NULL && !CfgFiles.empty()) {
             ConfigParser::CfgFile *wordfile = CfgFiles.top();
             token = wordfile->parse(LastTokenType);
             if (!token) {
                 assert(!wordfile->isOpen());
                 CfgFiles.pop();
+                debugs(3, 4, "CfgFiles.pop " << wordfile->filePath);
                 delete wordfile;
             }
         }
 
         if (!token)
             token = NextElement(LastTokenType);
 
-        if (token &&  LastTokenType == ConfigParser::FunctionNameToken && strcmp("parameters", token) == 0) {
+        if (token &&  LastTokenType == ConfigParser::FunctionParameters) {
+            //Disable temporary preview mode, we need to parse function parameters
+            bool savePreview = ConfigParser::PreviewMode_;
+            ConfigParser::PreviewMode_ = false;
+
             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();
+            ConfigParser::PreviewMode_ = savePreview;
             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);
+    return token;
 }
 
 char *
-ConfigParser::NextQuotedOrToEol()
+ConfigParser::NextTokenPreview()
 {
-    char *token;
+    PreviewMode_ = true;
+    char *token = NextToken();
+    PreviewMode_ = false;
+    return token;
+}
 
-    if ((token = CfgPos) == NULL) {
-        debugs(3, DBG_CRITICAL, "token is missing");
-        self_destruct();
-        return NULL;
+char *
+ConfigParser::NextQuotedOrToEol()
+{
+    ParseQuotedOrToEOL_ = true;
+    char *token = NextToken();
+    ParseQuotedOrToEOL_ = false;
+
+    // Assume end of current config line
+    // Close all open configuration files for this config line
+    while (!CfgFiles.empty()) {
+        ConfigParser::CfgFile *wordfile = CfgFiles.top();
+        CfgFiles.pop();
+        delete wordfile;
     }
-    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;
+    return token;
+}
+
+char *
+ConfigParser::RegexStrtokFile()
+{
+    ParseRegex_ = true;
+    char * token = strtokFile();
+    ParseRegex_ = false;
+    return token;
+}
 
-    CfgPos = NULL;
-    return (LastToken = token);
+char *
+ConfigParser::RegexPattern()
+{
+    ParseRegex_ = true;
+    char * token = NextToken();
+    ParseRegex_ = false;
+    return token;
+}
+
+char *
+ConfigParser::NextQuotedToken()
+{
+    bool saveRecognizeQuotedValues = ConfigParser::RecognizeQuotedValues;
+    ConfigParser::RecognizeQuotedValues = true;
+    char *token = NextToken();
+    ConfigParser::RecognizeQuotedValues = saveRecognizeQuotedValues;
+    return token;
 }
 
 const char *
 ConfigParser::QuoteString(const String &var)
 {
     static String quotedStr;
     const char *s = var.termedBuf();
     bool  needQuote = false;
 
     for (const char *l = s; !needQuote &&  *l != '\0'; ++l  )
         needQuote = !isalnum(*l);
 
     if (!needQuote)
         return s;
 
     quotedStr.clean();
     quotedStr.append('"');
     for (; *s != '\0'; ++s) {
         if (*s == '"' || *s == '\\')
             quotedStr.append('\\');
         quotedStr.append(*s);
     }
     quotedStr.append('"');
     return quotedStr.termedBuf();
 }
 
 bool
 ConfigParser::CfgFile::startParse(char *path)
 {
     assert(wordFile == NULL);
+    debugs(3, 3, "Parsing from " << path);
     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);
@@ -408,28 +526,33 @@
 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);
+    const char *pos = parsePos;
+    char *token = TokenParse(pos, type);
+    if (!PreviewMode_ || type == FunctionParameters)
+        parsePos = pos;
+    // else next call will read the same token;
+    return token;
 }
 
 ConfigParser::CfgFile::~CfgFile()
 {
     if (wordFile)
         fclose(wordFile);
 }

=== modified file 'src/ConfigParser.h'
--- src/ConfigParser.h	2013-07-21 19:24:35 +0000
+++ src/ConfigParser.h	2013-08-07 06:39:13 +0000
@@ -53,158 +53,182 @@
 #define CONFIG_LINE_LIMIT	2048
 
 /**
  * A configuration file Parser. Instances of this class track
  * parsing state and perform tokenisation. Syntax is currently
  * taken care of outside this class.
  *
  * One reason for this class is to allow testing of configuration
  * using modules without linking cache_cf.o in - because that drags
  * in all of squid by reference. Instead the tokeniser only is
  * brought in.
  */
 class ConfigParser
 {
 
 public:
     /**
      * Parsed tokens type: simple tokens, quoted tokens or function
      * like parameters.
      */
-    enum TokenType {SimpleToken, QuotedToken, FunctionNameToken};
+    enum TokenType {SimpleToken, QuotedToken, RegexPatternToken, FunctionParameters};
 
     void destruct();
     static void ParseUShort(unsigned short *var);
     static void ParseBool(bool *var);
     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();
 
     /**
      * 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();
 
+    /**
+     * Backward compatibility wrapper for ConfigParser::RegexPattern method.
+     * If the configuration_includes_quoted_values configuration parameter is
+     * set to 'off' this interprets the quoted tokens as filenames.
+     */
+    static char *RegexStrtokFile();
+
+    /**
+     * Parse the next token as a regex patern. The regex patterns are non quoted
+     * tokens.
+     */
+    static char *RegexPattern();
+
+    /**
+     * Parse the next token with support for quoted values enabled even if 
+     * the configuration_includes_quoted_values is set to off
+     */
+    static char *NextQuotedToken();
+
     /// \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.
+     * Preview the next token. The next NextToken() and strtokFile() call
+     * will return the same token.
+     * On parse error (eg invalid characters in token) will return an
+     * error message as token.
      */
-    static void TokenUndo();
+    static char *NextTokenPreview();
 
     /**
      * 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;
+    static bool RecognizeQuotedValues;
+
+    /// Strict syntax mode. Does not allow not alphanumeric characters in unquoted tokens
+    static bool StrictMode;
 
 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
+        const 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
+     * Return the last 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.
+     * \param next if it is not NULL, it is set after the end of token.
      */
-    static char *UnQuote(char *token, char **end = NULL);
+    static char *UnQuote(const char *token, const char **next = 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);
+    static char *TokenParse(const char * &nextToken, TokenType &type);
 
     /// Wrapper method for TokenParse.
-    static char *NextElement(TokenType &type, bool legacy = false);
+    static char *NextElement(TokenType &type);
     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 const char *CfgLine; ///< The current line to parse
+    static const char *CfgPos; ///< Pointer to the next element in cfgLine string
+    static std::queue<char *> CfgLineTokens_; ///< Store the list of tokens for current configuration line
+    static std::queue<std::string> Undo_; ///< The list with TokenPutBack() queued elements
     static bool AllowMacros_;
+    static bool ParseRegex_; ///< The next tokens will be handled as regex patterns
+    static bool ParseQuotedOrToEOL_; ///< The next tokens will be handled as quoted or to_eol token
+    static bool PreviewMode_; ///< The next token will not poped from cfg files, will just previewd.
 };
 
 int parseConfigFile(const char *file_name);
 
 #endif /* SQUID_CONFIGPARSER_H */

=== modified file 'src/Notes.cc'
--- src/Notes.cc	2013-07-21 19:24:35 +0000
+++ src/Notes.cc	2013-08-05 20:05:41 +0000
@@ -76,41 +76,41 @@
 }
 
 Note::Pointer
 Notes::add(const String &noteKey)
 {
     typedef Notes::NotesList::iterator AMLI;
     for (AMLI i = notes.begin(); i != notes.end(); ++i) {
         if ((*i)->key == noteKey)
             return (*i);
     }
 
     Note::Pointer note = new Note(noteKey);
     notes.push_back(note);
     return note;
 }
 
 Note::Pointer
 Notes::parse(ConfigParser &parser)
 {
     String key = ConfigParser::NextToken();
-    String value = ConfigParser::NextToken();
+    String value = ConfigParser::NextQuotedToken();
     Note::Pointer note = add(key);
     Note::Value::Pointer noteValue = note->addValue(value);
 
     String label(key);
     label.append('=');
     label.append(value);
     aclParseAclList(parser, &noteValue->aclList, label.termedBuf());
 
     if (blacklisted) {
         for (int i = 0; blacklisted[i] != NULL; ++i) {
             if (note->key.caseCmp(blacklisted[i]) == 0) {
                 fatalf("%s:%d: meta key \"%s\" is a reserved %s name",
                        cfg_filename, config_lineno, note->key.termedBuf(),
                        descr ? descr : "");
             }
         }
     }
 
     return note;
 }

=== modified file 'src/acl/Acl.cc'
--- src/acl/Acl.cc	2013-07-21 19:24:35 +0000
+++ src/acl/Acl.cc	2013-08-06 19:24:10 +0000
@@ -38,62 +38,59 @@
 #include "dlink.h"
 #include "globals.h"
 #include "profiler/Profiler.h"
 #include "SquidConfig.h"
 
 const ACLFlag ACLFlags::NoFlags[1] = {ACL_F_END};
 
 const char *AclMatchedName = NULL;
 
 bool ACLFlags::supported(const ACLFlag f) const
 {
     if (f == ACL_F_REGEX_CASE)
         return true;
     return (supported_.find(f) != std::string::npos);
 }
 
 void
 ACLFlags::parseFlags()
 {
     char *nextToken;
-    while ((nextToken = ConfigParser::strtokFile()) != NULL && nextToken[0] == '-') {
-
+    while ((nextToken = ConfigParser::NextTokenPreview()) != NULL && nextToken[0] == '-') {
+        (void)ConfigParser::NextToken(); //Get token fron cfg line
         //if token is the "--" break flag
         if (strcmp(nextToken, "--") == 0)
             break;
 
         for (const char *flg = nextToken+1; *flg!='\0'; flg++ ) {
             if (supported(*flg)) {
                 makeSet(*flg);
             } else {
                 debugs(28, 0, HERE << "Flag '" << *flg << "' not supported");
                 self_destruct();
             }
         }
     }
 
     /*Regex code needs to parse -i file*/
     if ( isSet(ACL_F_REGEX_CASE))
         ConfigParser::TokenPutBack("-i");
-
-    if (nextToken != NULL && strcmp(nextToken, "--") != 0 )
-        ConfigParser::TokenUndo();
 }
 
 const char *
 ACLFlags::flagsStr() const
 {
     static char buf[64];
     if (flags_ == 0)
         return "";
 
     char *s = buf;
     *s++ = '-';
     for (ACLFlag f = 'A'; f <= 'z'; f++) {
         // ACL_F_REGEX_CASE (-i) flag handled by ACLRegexData class, ignore
         if (isSet(f) && f != ACL_F_REGEX_CASE)
             *s++ = f;
     }
     *s = '\0';
     return buf;
 }
 

=== modified file 'src/acl/RegexData.cc'
--- src/acl/RegexData.cc	2012-09-06 11:56:46 +0000
+++ src/acl/RegexData.cc	2013-08-05 09:51:23 +0000
@@ -305,41 +305,41 @@
             flags &= ~REG_ICASE;
         } else {
             newTail = compileRE( Tail, wl->key , flags );
             if (newTail == NULL)
                 debugs(28, DBG_CRITICAL, "ERROR: Skipping regular expression. Compile failed: '" << wl->key << "'");
             else
                 Tail = newTail;
         }
         wl = wl->next;
     }
 }
 
 static void
 aclParseRegexList(RegexList **curlist)
 {
     char *t;
     wordlist *wl = NULL;
 
     debugs(28, 2, HERE << "aclParseRegexList: new Regex line or file");
 
-    while ((t = ConfigParser::strtokFile()) != NULL) {
+    while ((t = ConfigParser::RegexStrtokFile()) != NULL) {
         const char *clean = removeUnnecessaryWildcards(t);
         if (strlen(clean) > BUFSIZ-1) {
             debugs(28, DBG_CRITICAL, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
             debugs(28, DBG_CRITICAL, "ERROR: Skipping regular expression. Larger than " << BUFSIZ-1 << " characters: '" << clean << "'");
         } else {
             debugs(28, 3, "aclParseRegexList: buffering RE '" << clean << "'");
             wordlistAdd(&wl, clean);
         }
     }
 
     if (!compileOptimisedREs(curlist, wl)) {
         debugs(28, DBG_IMPORTANT, "WARNING: optimisation of regular expressions failed; using fallback method without optimisation");
         compileUnoptimisedREs(curlist, wl);
     }
 
     wordlistDestroy(&wl);
 }
 
 void
 ACLRegexData::parse()

=== modified file 'src/cache_cf.cc'
--- src/cache_cf.cc	2013-07-30 00:44:04 +0000
+++ src/cache_cf.cc	2013-08-06 19:29:07 +0000
@@ -243,40 +243,44 @@
 static void free_sslproxy_cert_sign(sslproxy_cert_sign **cert_sign);
 static void parse_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt);
 static void dump_sslproxy_cert_adapt(StoreEntry *entry, const char *name, sslproxy_cert_adapt *cert_adapt);
 static void free_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt);
 static void parse_sslproxy_ssl_bump(acl_access **ssl_bump);
 static void dump_sslproxy_ssl_bump(StoreEntry *entry, const char *name, acl_access *ssl_bump);
 static void free_sslproxy_ssl_bump(acl_access **ssl_bump);
 #endif /* USE_SSL */
 
 static void parse_b_size_t(size_t * var);
 static void parse_b_int64_t(int64_t * var);
 
 static bool parseNamedIntList(const char *data, const String &name, Vector<int> &list);
 
 static void parse_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap);
 static void dump_CpuAffinityMap(StoreEntry *const entry, const char *const name, const CpuAffinityMap *const cpuAffinityMap);
 static void free_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap);
 
 static int parseOneConfigFile(const char *file_name, unsigned int depth);
 
+static void parse_configuration_includes_quoted_values(bool *recognizeQuotedValues);
+static void dump_configuration_includes_quoted_values(StoreEntry *const entry, const char *const name, bool recognizeQuotedValues);
+static void free_configuration_includes_quoted_values(bool *recognizeQuotedValues);
+
 /*
  * LegacyParser is a parser for legacy code that uses the global
  * approach.  This is static so that it is only exposed to cache_cf.
  * Other modules needing access to a ConfigParser should have it
  * provided to them in their parserFOO methods.
  */
 static ConfigParser LegacyParser = ConfigParser();
 
 void
 self_destruct(void)
 {
     LegacyParser.destruct();
 }
 
 static void
 update_maxobjsize(void)
 {
     int64_t ms = -1;
 
     // determine the maximum size object that can be stored to disk
@@ -1777,41 +1781,41 @@
 }
 
 static void
 dump_http_header_replace(StoreEntry * entry, const char *name, const HeaderManglers *manglers)
 {
     if (manglers)
         manglers->dumpReplacement(entry, name);
 }
 
 static void
 parse_http_header_replace(HeaderManglers **pm)
 {
     char *t = 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;
     }
 
-    const char *value = t + strlen(t) + 1;
+    const char *value = ConfigParser::NextQuotedOrToEol();
 
     if (!*pm)
         *pm = new HeaderManglers;
     HeaderManglers *manglers = *pm;
     manglers->setReplacement(t, value);
 }
 
 #endif
 
 static void
 dump_cachedir(StoreEntry * entry, const char *name, SquidConfig::_cacheSwap swap)
 {
     SwapDir *s;
     int i;
     assert (entry);
 
     for (i = 0; i < swap.n_configured; ++i) {
         s = dynamic_cast<SwapDir *>(swap.swapDirs[i].getRaw());
         if (!s) continue;
         storeAppendPrintf(entry, "%s %s %s", name, s->type(), s->path);
@@ -2682,55 +2686,57 @@
         debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'enable' is deprecated. Please update to use value 'on'.");
         *var = 1;
     } else if (!strcmp(token, "warn")) {
         *var = -1;
     } else if (!strcmp(token, "off")) {
         *var = 0;
     } else if (!strcmp(token, "disable")) {
         debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'disable' is deprecated. Please update to use value 'off'.");
         *var = 0;
     } else {
         debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: Invalid option: Tristate options can only be 'on', 'off', or 'warn'.");
         self_destruct();
     }
 }
 
 #define free_tristate free_int
 
 void
 parse_pipelinePrefetch(int *var)
 {
-    char *token = ConfigParser::strtokFile();
+    char *token = ConfigParser::NextTokenPreview();
 
     if (token == NULL)
         self_destruct();
 
     if (!strcmp(token, "on")) {
         debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'pipeline_prefetch on' is deprecated. Please update to use 1 (or a higher number).");
         *var = 1;
+        //pop the token
+        (void)ConfigParser::NextToken();
     } else if (!strcmp(token, "off")) {
         debugs(0, DBG_PARSE_NOTE(2), "WARNING: 'pipeline_prefetch off' is deprecated. Please update to use '0'.");
         *var = 0;
-    } else {
-        ConfigParser::TokenUndo();
+        //pop the token
+        (void)ConfigParser::NextToken();
+    } else
         parse_int(var);
-    }
 }
 
 #define free_pipelinePrefetch free_int
 #define dump_pipelinePrefetch dump_int
 
 static void
 dump_refreshpattern(StoreEntry * entry, const char *name, RefreshPattern * head)
 {
     while (head != NULL) {
         storeAppendPrintf(entry, "%s%s %s %d %d%% %d",
                           name,
                           head->flags.icase ? " -i" : null_string,
                           head->pattern,
                           (int) head->min / 60,
                           (int) (100.0 * head->pct + 0.5),
                           (int) head->max / 60);
 
         if (head->max_stale >= 0)
             storeAppendPrintf(entry, " max-stale=%d", head->max_stale);
 
@@ -2787,48 +2793,48 @@
     int max_stale = -1;
 
 #if USE_HTTP_VIOLATIONS
 
     int override_expire = 0;
     int override_lastmod = 0;
     int reload_into_ims = 0;
     int ignore_reload = 0;
     int ignore_no_store = 0;
     int ignore_must_revalidate = 0;
     int ignore_private = 0;
     int ignore_auth = 0;
 #endif
 
     int i;
     RefreshPattern *t;
     regex_t comp;
     int errcode;
     int flags = REG_EXTENDED | REG_NOSUB;
 
-    if ((token = ConfigParser::NextToken()) != NULL) {
+    if ((token = ConfigParser::RegexPattern()) != NULL) {
 
         if (strcmp(token, "-i") == 0) {
             flags |= REG_ICASE;
-            token = ConfigParser::NextToken();
+            token = ConfigParser::RegexPattern();
         } else if (strcmp(token, "+i") == 0) {
             flags &= ~REG_ICASE;
-            token = ConfigParser::NextToken();
+            token = ConfigParser::RegexPattern();
         }
 
     }
 
     if (token == NULL) {
         debugs(3, DBG_CRITICAL, "FATAL: refresh_pattern missing the regex pattern parameter");
         self_destruct();
         return;
     }
 
     pattern = xstrdup(token);
 
     i = GetInteger();		/* token: min */
 
     /* catch negative and insanely huge values close to 32-bit wrap */
     if (i < 0) {
         debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern minimum age negative. Cropped back to zero.");
         i = 0;
     }
     if (i > 60*24*365) {
@@ -3228,41 +3234,41 @@
 
 static void
 dump_wordlist(StoreEntry * entry, const char *name, wordlist * list)
 {
     while (list != NULL) {
         storeAppendPrintf(entry, "%s %s\n", name, list->key);
         list = list->next;
     }
 }
 
 void
 ConfigParser::ParseWordList(wordlist ** list)
 {
     parse_wordlist(list);
 }
 
 void
 parse_wordlist(wordlist ** list)
 {
     char *token;
-    while ((token = ConfigParser::NextToken()))
+    while ((token = ConfigParser::NextQuotedToken()))
         wordlistAdd(list, token);
 }
 
 #if 0 /* now unused */
 static int
 check_null_wordlist(wordlist * w)
 {
     return w == NULL;
 }
 #endif
 
 static int
 check_null_acl_access(acl_access * a)
 {
     return a == NULL;
 }
 
 #define free_wordlist wordlistDestroy
 
 #define free_uri_whitespace free_int
@@ -4059,73 +4065,75 @@
     /* determine configuration style */
 
     const char *filename = ConfigParser::NextToken();
     if (!filename) {
         self_destruct();
         return;
     }
 
     if (strcmp(filename, "none") == 0) {
         cl->type = Log::Format::CLF_NONE;
         aclParseAclList(LegacyParser, &cl->aclList, filename);
         while (*logs)
             logs = &(*logs)->next;
         *logs = cl;
         return;
     }
 
     cl->filename = xstrdup(filename);
     cl->type = Log::Format::CLF_UNKNOWN;
 
-    const char *token = ConfigParser::strtokFile();
+    const char *token = ConfigParser::NextTokenPreview();
     if (!token) { // style #1
         // no options to deal with
     } else if (!strchr(token, '=')) { // style #3
-        // if logformat name is not recognized,
-        // put back the token; it must be an ACL name
-        if (!setLogformat(cl, token, false))
-            ConfigParser::TokenUndo();
+        // if logformat name is recognized,
+        // pop the previewed token; Else it must be an ACL name
+        if (setLogformat(cl, token, false))
+            (void)ConfigParser::NextToken();
     } else { // style #4
         do {
             if (strncasecmp(token, "on-error=", 9) == 0) {
                 if (strncasecmp(token+9, "die", 3) == 0) {
                     cl->fatal = true;
                 } else if (strncasecmp(token+9, "drop", 4) == 0) {
                     cl->fatal = false;
                 } else {
                     debugs(3, DBG_CRITICAL, "Unknown value for on-error '" <<
                            token << "' expected 'drop' or 'die'");
                     self_destruct();
                 }
             } else if (strncasecmp(token, "buffer-size=", 12) == 0) {
                 parseBytesOptionValue(&cl->bufferSize, B_BYTES_STR, token+12);
             } else if (strncasecmp(token, "logformat=", 10) == 0) {
                 setLogformat(cl, token+10, true);
             } else if (!strchr(token, '=')) {
-                // put back the token; it must be an ACL name
-                ConfigParser::TokenUndo();
+                // Do not pop the token; it must be an ACL name
                 break; // done with name=value options, now to ACLs
             } else {
                 debugs(3, DBG_CRITICAL, "Unknown access_log option " << token);
                 self_destruct();
             }
-        } while ((token = ConfigParser::strtokFile()) != NULL);
+            // Pop the token, it was a valid "name=value" option
+            (void)ConfigParser::NextToken();
+            // Get next with preview ConfigParser::NextToken call.
+        } while ((token = ConfigParser::NextTokenPreview()) != NULL);
     }
 
     // set format if it has not been specified explicitly
     if (cl->type == Log::Format::CLF_UNKNOWN)
         setLogformat(cl, "squid", true);
 
     aclParseAclList(LegacyParser, &cl->aclList, cl->filename);
 
     while (*logs)
         logs = &(*logs)->next;
 
     *logs = cl;
 }
 
 /// sets CustomLog::type and, if needed, CustomLog::lf
 /// returns false iff there is no named log format
 static bool
 setLogformat(CustomLog *cl, const char *logdef_name, const bool dieWhenMissing)
 {
     assert(cl);
@@ -4743,41 +4751,41 @@
 }
 
 static void parse_HeaderWithAclList(HeaderWithAclList **headers)
 {
     char *fn;
     if (!*headers) {
         *headers = new HeaderWithAclList;
     }
     if ((fn = ConfigParser::NextToken()) == NULL) {
         self_destruct();
         return;
     }
     HeaderWithAcl hwa;
     hwa.fieldName = fn;
     hwa.fieldId = httpHeaderIdByNameDef(fn, strlen(fn));
     if (hwa.fieldId == HDR_BAD_HDR)
         hwa.fieldId = HDR_OTHER;
 
     Format::Format *nlf =  new ::Format::Format("hdrWithAcl");
     ConfigParser::EnableMacros();
-    String buf = ConfigParser::NextToken();
+    String buf = ConfigParser::NextQuotedToken();
     ConfigParser::DisableMacros();
     hwa.fieldValue = buf.termedBuf();
     hwa.quoted = ConfigParser::LastTokenWasQuoted();
     if (hwa.quoted) {
         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);
 }
 
 static void free_HeaderWithAclList(HeaderWithAclList **header)
 {
     if (!(*header))
         return;
 
@@ -4792,20 +4800,50 @@
     }
     delete *header;
     *header = NULL;
 }
 
 static void parse_note(Notes *notes)
 {
     assert(notes);
     notes->parse(LegacyParser);
 }
 
 static void dump_note(StoreEntry *entry, const char *name, Notes &notes)
 {
     notes.dump(entry, name);
 }
 
 static void free_note(Notes *notes)
 {
     notes->clean();
 }
+
+static void
+parse_configuration_includes_quoted_values(bool *recognizeQuotedValues)
+{
+    int val = 0;
+    parse_onoff(&val);
+
+    // If quoted values is set to on then enable new strict mode parsing
+    if (val) {
+        ConfigParser::RecognizeQuotedValues = true;
+        ConfigParser::StrictMode = true;
+    } else {
+        ConfigParser::RecognizeQuotedValues = false;
+        ConfigParser::StrictMode = false;
+    }
+}
+
+static void
+dump_configuration_includes_quoted_values(StoreEntry *const entry, const char *const name, bool recognizeQuotedValues)
+{
+    int val = ConfigParser::RecognizeQuotedValues ? 1 : 0;
+    dump_onoff(entry, name, val);
+}
+
+static void
+free_configuration_includes_quoted_values(bool *recognizeQuotedValues)
+{
+    ConfigParser::RecognizeQuotedValues = false;
+    ConfigParser::StrictMode = false;
+}

=== modified file 'src/cf.data.depend'
--- src/cf.data.depend	2013-05-26 01:57:47 +0000
+++ src/cf.data.depend	2013-08-06 06:47:45 +0000
@@ -1,36 +1,37 @@
 # type			dependencies
 access_log		acl	logformat
 acl			external_acl_type auth_param
 acl_access		acl
 acl_address		acl
 acl_b_size_t		acl
 acl_tos			acl
 acl_nfmark		acl
 address
 authparam
 b_int64_t
 b_size_t
 b_ssize_t
 cachedir		cache_replacement_policy
 cachemgrpasswd
 ConfigAclTos
+configuration_includes_quoted_values
 CpuAffinityMap
 debug
 delay_pool_access	acl	delay_class
 delay_pool_class	delay_pools
 delay_pool_count
 delay_pool_rates	delay_class
 client_delay_pool_access	acl
 client_delay_pool_count
 client_delay_pool_rates
 denyinfo		acl
 eol
 externalAclHelper	auth_param
 HelperChildConfig
 hostdomain		cache_peer
 hostdomaintype		cache_peer
 http_header_access	acl
 http_header_replace
 HeaderWithAclList	acl
 adaptation_access_type	adaptation_service_set adaptation_service_chain acl icap_service icap_class
 adaptation_service_set_type	icap_service ecap_service

=== modified file 'src/cf.data.pre'
--- src/cf.data.pre	2013-07-27 13:37:29 +0000
+++ src/cf.data.pre	2013-08-06 06:54:23 +0000
@@ -8452,42 +8452,42 @@
 DOC_START
 	The size, low-, and high-water marks for the IP cache.
 DOC_END
 
 NAME: fqdncache_size
 COMMENT: (number of entries)
 TYPE: int
 DEFAULT: 1024
 LOC: Config.fqdncache.size
 DOC_START
 	Maximum number of FQDN cache entries.
 DOC_END
 
 COMMENT_START
  MISCELLANEOUS
  -----------------------------------------------------------------------------
 COMMENT_END
 
 NAME: configuration_includes_quoted_values
 COMMENT: on|off
-TYPE: onoff
-DEFAULT: on
+TYPE: configuration_includes_quoted_values
+DEFAULT: off
 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
 DEFAULT: on
 LOC: Config.onoff.mem_pools
 DOC_START
 	If set, Squid will keep pools of allocated (but unused) memory
 	available for future use.  If memory is a premium on your
 	system and you believe your malloc library outperforms Squid
 	routines, disable this.
 DOC_END


