]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/ConfigParser.cc
4 * SQUID Web Proxy Cache http://www.squid-cache.org/
5 * ----------------------------------------------------------
7 * Squid is the result of efforts by numerous individuals from
8 * the Internet community; see the CONTRIBUTORS file for full
9 * details. Many organizations have provided support for Squid's
10 * development; see the SPONSORS file for full details. Squid is
11 * Copyrighted (C) 2001 by the Regents of the University of
12 * California; see the COPYRIGHT file for full details. Squid
13 * incorporates software developed and/or copyrighted by other
14 * sources; see the CREDITS file for full details.
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
31 * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
36 #include "ConfigParser.h"
41 int ConfigParser::RecognizeQuotedValues
= true;
42 std::stack
<ConfigParser::CfgFile
*> ConfigParser::CfgFiles
;
43 ConfigParser::TokenType
ConfigParser::LastTokenType
= ConfigParser::SimpleToken
;
44 char *ConfigParser::LastToken
= NULL
;
45 char *ConfigParser::CfgLine
= NULL
;
46 char *ConfigParser::CfgPos
= NULL
;
47 std::queue
<std::string
> ConfigParser::Undo_
;
48 bool ConfigParser::AllowMacros_
= false;
51 ConfigParser::destruct()
54 if (!CfgFiles
.empty()) {
55 std::ostringstream message
;
56 CfgFile
*f
= CfgFiles
.top();
57 message
<< "Bungled " << f
->filePath
<< " line " << f
->lineNo
<<
58 ": " << f
->currentLine
<< std::endl
;
61 while (!CfgFiles
.empty()) {
63 message
<< " included from " << f
->filePath
<< " line " <<
64 f
->lineNo
<< ": " << f
->currentLine
<< std::endl
;
68 message
<< " included from " << cfg_filename
<< " line " <<
69 config_lineno
<< ": " << config_input_line
<< std::endl
;
70 std::string msg
= message
.str();
71 fatalf("%s", msg
.c_str());
73 fatalf("Bungled %s line %d: %s",
74 cfg_filename
, config_lineno
, config_input_line
);
78 ConfigParser::TokenUndo()
81 Undo_
.push(LastToken
);
85 ConfigParser::TokenPutBack(const char *tok
)
94 LOCAL_ARRAY(char, undoToken
, CONFIG_LINE_LIMIT
);
96 strncpy(undoToken
, Undo_
.front().c_str(), sizeof(undoToken
));
97 undoToken
[sizeof(undoToken
) - 1] = '\0';
105 ConfigParser::strtokFile()
107 if (RecognizeQuotedValues
)
108 return ConfigParser::NextToken();
110 static int fromFile
= 0;
111 static FILE *wordFile
= NULL
;
114 LOCAL_ARRAY(char, buf
, CONFIG_LINE_LIMIT
);
116 if ((LastToken
= ConfigParser::Undo()))
122 ConfigParser::TokenType tokenType
;
123 t
= ConfigParser::NextElement(tokenType
, true);
126 } else if (tokenType
== ConfigParser::QuotedToken
) {
127 /* quote found, start reading from file */
128 debugs(3, 8,"Quoted token found : " << t
);
130 if ((wordFile
= fopen(t
, "r")) == NULL
) {
131 debugs(3, DBG_CRITICAL
, "Can not open file " << t
<< " for reading");
136 setmode(fileno(wordFile
), O_TEXT
);
141 return LastToken
= t
;
146 if (fgets(buf
, CONFIG_LINE_LIMIT
, wordFile
) == NULL
) {
147 /* stop reading from file */
155 /* skip leading and trailing white space */
156 t
+= strspn(buf
, w_space
);
157 t2
= t
+ strcspn(t
, w_space
);
158 t3
= t2
+ strspn(t2
, w_space
);
160 while (*t3
&& *t3
!= '#') {
161 t2
= t3
+ strcspn(t3
, w_space
);
162 t3
= t2
+ strspn(t2
, w_space
);
169 /* skip blank lines */
170 } while ( *t
== '#' || !*t
);
172 return LastToken
= t
;
176 ConfigParser::UnQuote(char *token
, char **end
)
178 char quoteChar
= *token
;
179 assert(quoteChar
== '"' || quoteChar
== '\'');
181 /* scan until the end of the quoted string, unescaping " and \ */
182 while (*s
&& *s
!= quoteChar
) {
183 if (*s
== '\\' && isalnum(*( s
+ 1))) {
184 debugs(3, DBG_CRITICAL
, "Unsupported escape sequence: " << s
);
186 } else if (*s
== '$' && quoteChar
== '"') {
187 debugs(3, DBG_CRITICAL
, "Unsupported cfg macro: " << s
);
189 } else if (*s
== '%' && quoteChar
== '"' && (!AllowMacros_
)) {
190 debugs(3, DBG_CRITICAL
, "Macros are not supported here: " << s
);
192 } else if (*s
== '\\') {
193 const char * next
= s
+1; // may point to 0
194 memmove(s
, next
, strlen(next
) + 1);
199 if (*s
!= quoteChar
) {
200 debugs(3, DBG_CRITICAL
, "missing '" << quoteChar
<< "' at the end of quoted string: " << (s
-1));
208 ConfigParser::SetCfgLine(char *line
)
215 ConfigParser::TokenParse(char * &nextToken
, ConfigParser::TokenType
&type
, bool legacy
)
217 if (!nextToken
|| *nextToken
== '\0')
219 type
= ConfigParser::SimpleToken
;
220 nextToken
+= strspn(nextToken
, w_space
);
221 if (*nextToken
== '"' || *nextToken
== '\'') {
222 type
= ConfigParser::QuotedToken
;
223 char *token
= UnQuote(nextToken
, &nextToken
);
229 char *token
= nextToken
;
230 if (char *t
= strchr(nextToken
, '#'))
237 nextToken
+= strcspn(nextToken
, sep
);
239 if (!legacy
&& *nextToken
== '(')
240 type
= ConfigParser::FunctionNameToken
;
242 type
= ConfigParser::SimpleToken
;
244 if (*nextToken
!= '\0') {
256 ConfigParser::NextElement(ConfigParser::TokenType
&type
, bool legacy
)
258 char *token
= TokenParse(CfgPos
, type
, legacy
);
263 ConfigParser::NextToken()
265 if ((LastToken
= ConfigParser::Undo()))
270 while (token
== NULL
&& !CfgFiles
.empty()) {
271 ConfigParser::CfgFile
*wordfile
= CfgFiles
.top();
272 token
= wordfile
->parse(LastTokenType
);
274 assert(!wordfile
->isOpen());
281 token
= NextElement(LastTokenType
);
283 if (token
&& LastTokenType
== ConfigParser::FunctionNameToken
&& strcmp("parameters", token
) == 0) {
284 char *path
= NextToken();
285 if (LastTokenType
!= ConfigParser::QuotedToken
) {
286 debugs(3, DBG_CRITICAL
, "Quoted filename missing: " << token
);
291 // The next token in current cfg file line must be a ")"
292 char *end
= NextToken();
293 if (LastTokenType
!= ConfigParser::SimpleToken
|| strcmp(end
, ")") != 0) {
294 debugs(3, DBG_CRITICAL
, "missing ')' after " << token
<< "(\"" << path
<< "\"");
299 if (CfgFiles
.size() > 16) {
300 debugs(3, DBG_CRITICAL
, "WARNING: can't open %s for reading parameters: includes are nested too deeply (>16)!\n" << path
);
305 ConfigParser::CfgFile
*wordfile
= new ConfigParser::CfgFile();
306 if (!path
|| !wordfile
->startParse(path
)) {
307 debugs(3, DBG_CRITICAL
, "Error opening config file: " << token
);
312 CfgFiles
.push(wordfile
);
314 } else if (token
&& LastTokenType
== ConfigParser::FunctionNameToken
) {
315 debugs(3, DBG_CRITICAL
, "Unknown cfg function: " << token
);
319 } while (token
== NULL
&& !CfgFiles
.empty());
321 return (LastToken
= token
);
325 ConfigParser::NextQuotedOrToEol()
329 if ((token
= CfgPos
) == NULL
) {
330 debugs(3, DBG_CRITICAL
, "token is missing");
334 token
+= strspn(token
, w_space
);
336 if (*token
== '\"' || *token
== '\'') {
337 //TODO: eat the spaces at the end and check if it is untill the end of file.
339 token
= UnQuote(token
, &end
);
342 LastTokenType
= ConfigParser::QuotedToken
;
344 LastTokenType
= ConfigParser::SimpleToken
;
347 return (LastToken
= token
);
351 ConfigParser::QuoteString(const String
&var
)
353 static String quotedStr
;
354 const char *s
= var
.termedBuf();
355 bool needQuote
= false;
357 for (const char *l
= s
; !needQuote
&& *l
!= '\0'; ++l
)
358 needQuote
= !isalnum(*l
);
364 quotedStr
.append('"');
365 for (; *s
!= '\0'; ++s
) {
366 if (*s
== '"' || *s
== '\\')
367 quotedStr
.append('\\');
368 quotedStr
.append(*s
);
370 quotedStr
.append('"');
371 return quotedStr
.termedBuf();
375 ConfigParser::CfgFile::startParse(char *path
)
377 assert(wordFile
== NULL
);
378 if ((wordFile
= fopen(path
, "r")) == NULL
) {
379 debugs(3, DBG_CRITICAL
, "file :" << path
<< " not found");
384 setmode(fileno(wordFile
), O_TEXT
);
388 return getFileLine();
392 ConfigParser::CfgFile::getFileLine()
394 // Else get the next line
395 if (fgets(parseBuffer
, CONFIG_LINE_LIMIT
, wordFile
) == NULL
) {
396 /* stop reading from file */
399 parseBuffer
[0] = '\0';
402 parsePos
= parseBuffer
;
403 currentLine
= parseBuffer
;
409 ConfigParser::CfgFile::parse(ConfigParser::TokenType
&type
)
418 while (!(token
= nextElement(type
))) {
426 ConfigParser::CfgFile::nextElement(ConfigParser::TokenType
&type
)
428 return TokenParse(parsePos
, type
);
431 ConfigParser::CfgFile::~CfgFile()