3 +----------------------------------------------------------------------+
5 +----------------------------------------------------------------------+
6 | Copyright (c) 2010 Facebook, Inc. (http://www.facebook.com) |
7 | Copyright (c) 1998-2010 Zend Technologies Ltd. (http://www.zend.com) |
8 +----------------------------------------------------------------------+
9 | This source file is subject to version 2.00 of the Zend license, |
10 | that is bundled with this package in the file LICENSE, and is |
11 | available through the world-wide-web at the following url: |
12 | http://www.zend.com/license/2_00.txt. |
13 | If you did not receive a copy of the Zend license and are unable to |
14 | obtain it through the world-wide-web, please send a note to |
15 | license@zend.com so we can mail you a copy immediately. |
16 +----------------------------------------------------------------------+
20 #include <hphp/runtime/base/zend-ini.tab.hpp>
21 #include <hphp/runtime/base/string_buffer.h>
22 #include <hphp/runtime/base/ini_setting.h>
23 #include <hphp/util/logger.h>
28 struct ZendINIGlobals {
32 IniSetting::PFN_PARSER_CALLBACK callback;
35 static ZendINIGlobals s_zend_ini;
36 #define SCNG(v) s_zend_ini.v
38 /* Eat trailing whitespace + extra char */
39 #define EAT_TRAILING_WHITESPACE_EX(ch) \
40 while (yyleng > 0 && ( \
41 (ch != 'X' && yytext[yyleng - 1] == ch) || \
42 yytext[yyleng - 1] == '\n' || \
43 yytext[yyleng - 1] == '\r' || \
44 yytext[yyleng - 1] == '\t' || \
45 yytext[yyleng - 1] == ' ') \
50 /* Eat trailing whitespace */
51 #define EAT_TRAILING_WHITESPACE() EAT_TRAILING_WHITESPACE_EX('X')
53 #define RETURN_TOKEN(type, str, len) { \
54 *ini_lval = String(str, len, CopyString); \
58 void zend_ini_scan(CStrRef str, int scanner_mode, CStrRef filename,
59 IniSetting::PFN_PARSER_CALLBACK callback, void *arg) {
60 SCNG(scanner_mode) = scanner_mode;
61 SCNG(filename) = filename.data();
63 SCNG(callback) = callback;
68 /* Eat any UTF-8 BOM we find in the first 3 bytes */
69 if (memcmp(str.data(), "\xef\xbb\xbf", 3) == 0) {
70 yy_scan_string(str.data() + 3);
72 yy_scan_string(str.data());
76 void zend_ini_callback(String *arg1, String *arg2, String *arg3,
78 SCNG(callback)(arg1, arg2, arg3, callback_type, SCNG(arg));
81 static void zend_ini_escape_string(String &lval, char *str, int len,
86 String sval(str, len, CopyString);
89 /* convert escape sequences */
90 s = t = (char*)sval.data();
91 end = s + sval.size();
102 if (*s != quote_type) {
110 lval = lval.substr(0, lval.size() - 1);
120 if (*s == '\n' || (*s == '\r' && (*(s+1) != '\n'))) {
128 void ini_error(char *msg) {
130 if (!SCNG(filename).empty()) {
131 smsg.printf("%s in %s on line %d\n", msg, SCNG(filename).data(),
134 smsg.append("Invalid configuration directive\n");
137 Logger::Warning("%s", smsg.data());
140 #define YY_USE_PROTOS
141 #define YY_DECL int ini_lex_impl YY_PROTO((String *ini_lval))
143 #define GOTO_RESTART 9999
145 int ini_lex_impl(String *ini_lval);
146 int ini_lex(String *ini_lval) {
148 int ret = ini_lex_impl(ini_lval);
149 if (ret == GOTO_RESTART) goto restart;
166 DNUM ([0-9]*[\.][0-9]+)|([0-9]+[\.][0-9]*)
167 NUMBER [-]?{LNUM}|{DNUM}
169 NEWLINE ("\r"|"\n"|"\r\n")
170 TABS_AND_SPACES [ \t]
172 CONSTANT [a-zA-Z][a-zA-Z0-9_]*
173 LABEL [a-zA-Z0-9_][a-zA-Z0-9*._-]*
174 TOKENS [:,.\[\]"'()|^&+-/*=%$!~<>?@{}]
178 SECTION_RAW_CHARS [^\]\n\r]
179 SINGLE_QUOTED_CHARS [^']
180 RAW_VALUE_CHARS [^=\n\r;]
182 LITERAL_DOLLAR ("$"([^{\000]|("\\"{ANY_CHAR})))
183 VALUE_CHARS ([^$= \t\n\r;&|~()!"'\000]|{LITERAL_DOLLAR})
184 SECTION_VALUE_CHARS ([^$\n\r;"'\]\\]|("\\"{ANY_CHAR})|{LITERAL_DOLLAR})
185 DOUBLE_QUOTES_CHARS ([^$"\\]|("\\"[^"])|{LITERAL_DOLLAR}|"\\"["][^\r\n])
191 /* Enter section data lookup state */
192 if (SCNG(scanner_mode) == IniSetting::RawScanner) {
193 yy_push_state(ST_SECTION_RAW);
195 yy_push_state(ST_SECTION_VALUE);
200 <ST_VALUE,ST_SECTION_VALUE,ST_OFFSET>"'"{SINGLE_QUOTED_CHARS}+"'" {
202 /* Eat leading and trailing single quotes */
203 if (yytext[0] == '\'' && yytext[yyleng - 1] == '\'') {
207 RETURN_TOKEN(TC_RAW, yytext, yyleng);
210 <ST_SECTION_RAW,ST_SECTION_VALUE>"]"{TABS_AND_SPACES}*{NEWLINE}? {
217 <INITIAL>{LABEL}"["{TABS_AND_SPACES}* {
218 /* Start of option with offset */
219 /* Eat trailing whitespace and [ */
220 EAT_TRAILING_WHITESPACE_EX('[');
222 /* Enter offset lookup state */
223 yy_push_state(ST_OFFSET);
225 RETURN_TOKEN(TC_OFFSET, yytext, yyleng);
228 <ST_OFFSET>{TABS_AND_SPACES}*"]" {
229 /* End of section or an option offset */
234 <ST_DOUBLE_QUOTES,ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{DOLLAR_CURLY} {
236 yy_push_state(ST_VARNAME);
237 return TC_DOLLAR_CURLY;
240 <ST_VARNAME>{LABEL} {
242 RETURN_TOKEN(TC_VARNAME, yytext, yyleng);
245 <ST_VARNAME>"}" { /* Variable end */
250 <INITIAL,ST_VALUE>("true"|"on"|"yes"){TABS_AND_SPACES}* {
251 /* TRUE value (when used outside option value/offset this causes error!) */
252 RETURN_TOKEN(BOOL_TRUE, "1", 1);
255 <INITIAL,ST_VALUE>("false"|"off"|"no"|"none"|"null"){TABS_AND_SPACES}* {
256 /* FALSE value (when used outside option value/offset this causes error!)*/
257 RETURN_TOKEN(BOOL_FALSE, "", 0);
261 /* Get option name */
262 RETURN_TOKEN(TC_LABEL, yytext, yyleng);
265 <INITIAL>{TABS_AND_SPACES}*[=]{TABS_AND_SPACES}* {
266 /* Start option value */
267 if (SCNG(scanner_mode) == IniSetting::RawScanner) {
268 yy_push_state(ST_RAW);
270 yy_push_state(ST_VALUE);
275 <ST_RAW>{RAW_VALUE_CHARS}+ {
276 /* Raw value, only used when SCNG(scanner_mode) == IniSetting::RawScanner. */
277 /* Eat leading and trailing double quotes */
278 if (yytext[0] == '"' && yytext[yyleng - 1] == '"') {
282 RETURN_TOKEN(TC_RAW, yytext, yyleng);
285 <ST_SECTION_RAW>{SECTION_RAW_CHARS}+ {
286 /* Raw value, only used when SCNG(scanner_mode) == IniSetting::RawScanner. */
287 RETURN_TOKEN(TC_RAW, yytext, yyleng);
290 <ST_VALUE,ST_RAW>{TABS_AND_SPACES}*{NEWLINE} {
291 /* End of option value */
297 <ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{CONSTANT} {
298 /* Get constant option value */
299 RETURN_TOKEN(TC_CONSTANT, yytext, yyleng);
302 <ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{NUMBER} {
303 /* Get number option value as string */
304 RETURN_TOKEN(TC_NUMBER, yytext, yyleng);
308 /* Disallow these chars outside option values */
312 <ST_VALUE>{OPERATORS}{TABS_AND_SPACES}* {
313 /* Boolean operators */
318 /* Make = used in option value to trigger error */
324 <ST_VALUE>{VALUE_CHARS}+ {
325 /* Get everything else as option/offset value */
326 RETURN_TOKEN(TC_STRING, yytext, yyleng);
329 <ST_SECTION_VALUE,ST_OFFSET>{SECTION_VALUE_CHARS}+ {
330 /* Get rest as section/offset value */
331 RETURN_TOKEN(TC_STRING, yytext, yyleng);
334 <ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{TABS_AND_SPACES}*["] {
335 /* Double quoted '"' string start */
336 yy_push_state(ST_DOUBLE_QUOTES);
340 <ST_DOUBLE_QUOTES>{DOUBLE_QUOTES_CHARS}+("\\"["])? {
341 /* Escape double quoted string contents */
342 if (yyleng > 1 && yytext[yyleng-1] == '"' && yytext[yyleng-2] == '\\') {
346 zend_ini_escape_string(*ini_lval, yytext, yyleng, '"');
347 return TC_QUOTED_STRING;
350 <ST_DOUBLE_QUOTES>["]{TABS_AND_SPACES}* {
351 /* Double quoted '"' string ends */
356 <ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{WHITESPACE} {
357 RETURN_TOKEN(TC_WHITESPACE, yytext, yyleng);
360 <INITIAL,ST_RAW>{TABS_AND_SPACES}+ {
365 <INITIAL>{TABS_AND_SPACES}*{NEWLINE} {
370 <INITIAL,ST_VALUE,ST_RAW>{TABS_AND_SPACES}*[;][^\r\n]*{NEWLINE} {
377 <INITIAL>{TABS_AND_SPACES}*[#][^\r\n]*{NEWLINE} {
379 Logger::Error("Comments starting with '#' are deprecated in %s on line %d",
380 SCNG(filename).data(), SCNG(lineno));
386 <ST_VALUE,ST_RAW><<EOF>> {
387 /* End of option value (if EOF is reached before EOL) */
394 static void __attribute__((__unused__))
395 suppress_defined_but_not_used_warnings() {