Rename runtime/base/zend_* to zend-
[hiphop-php.git] / hphp / runtime / base / zend-ini.x
blob894c00517fad1a9df43954a9d3fdfbb831d02d75
1 %{
2 /*
3    +----------------------------------------------------------------------+
4    | HipHop for PHP                                                       |
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    +----------------------------------------------------------------------+
19 #include <errno.h>
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>
25 using namespace HPHP;
27 /* Globals Macros */
28 struct ZendINIGlobals {
29   int scanner_mode;
30   std::string filename;
31   int lineno;
32   IniSetting::PFN_PARSER_CALLBACK callback;
33   void *arg;
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] == ' ')                    \
46   ) {                                             \
47     yyleng--;                                     \
48   }
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);       \
55   return type;                                    \
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();
62   SCNG(lineno) = 1;
63   SCNG(callback) = callback;
64   SCNG(arg) = arg;
66   BEGIN(INITIAL);
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);
71   } else {
72     yy_scan_string(str.data());
73   }
76 void zend_ini_callback(String *arg1, String *arg2, String *arg3,
77                        int callback_type) {
78   SCNG(callback)(arg1, arg2, arg3, callback_type, SCNG(arg));
81 static void zend_ini_escape_string(String &lval, char *str, int len,
82                                    char quote_type) {
83   register char *s, *t;
84   char *end;
86   String sval(str, len, CopyString);
87   lval = sval;
89   /* convert escape sequences */
90   s = t = (char*)sval.data();
91   end = s + sval.size();
93   while (s < end) {
94     if (*s == '\\') {
95       s++;
96       if (s >= end) {
97         *t++ = '\\';
98         continue;
99       }
100       switch (*s) {
101         case '"':
102           if (*s != quote_type) {
103             *t++ = '\\';
104             *t++ = *s;
105             break;
106           }
107         case '\\':
108         case '$':
109           *t++ = *s;
110           lval = lval.substr(0, lval.size() - 1);
111           break;
112         default:
113           *t++ = '\\';
114           *t++ = *s;
115           break;
116       }
117     } else {
118       *t++ = *s;
119     }
120     if (*s == '\n' || (*s == '\r' && (*(s+1) != '\n'))) {
121       SCNG(lineno)++;
122     }
123     s++;
124   }
125   *t = 0;
128 void ini_error(char *msg) {
129   StringBuffer smsg;
130   if (!SCNG(filename).empty()) {
131     smsg.printf("%s in %s on line %d\n", msg, SCNG(filename).data(),
132                 SCNG(lineno));
133   } else {
134     smsg.append("Invalid configuration directive\n");
135   }
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) {
147 restart:
148   int ret = ini_lex_impl(ini_lval);
149   if (ret == GOTO_RESTART) goto restart;
150   return ret;
155 %x ST_OFFSET
156 %x ST_SECTION_VALUE
157 %x ST_VALUE
158 %x ST_SECTION_RAW
159 %x ST_DOUBLE_QUOTES
160 %x ST_VARNAME
161 %x ST_RAW
162 %option noyywrap
163 %option stack
165 LNUM [0-9]+
166 DNUM ([0-9]*[\.][0-9]+)|([0-9]+[\.][0-9]*)
167 NUMBER [-]?{LNUM}|{DNUM}
168 ANY_CHAR (.|[\n\t])
169 NEWLINE  ("\r"|"\n"|"\r\n")
170 TABS_AND_SPACES [ \t]
171 WHITESPACE [ \t]+
172 CONSTANT [a-zA-Z][a-zA-Z0-9_]*
173 LABEL [a-zA-Z0-9_][a-zA-Z0-9*._-]*
174 TOKENS [:,.\[\]"'()|^&+-/*=%$!~<>?@{}]
175 OPERATORS [&|~()!]
176 DOLLAR_CURLY "${"
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])
189 <INITIAL>"[" {
190 /* Section start */
191   /* Enter section data lookup state */
192   if (SCNG(scanner_mode) == IniSetting::RawScanner) {
193     yy_push_state(ST_SECTION_RAW);
194   } else {
195     yy_push_state(ST_SECTION_VALUE);
196   }
197   return TC_SECTION;
200 <ST_VALUE,ST_SECTION_VALUE,ST_OFFSET>"'"{SINGLE_QUOTED_CHARS}+"'" {
201 /* Raw string */
202   /* Eat leading and trailing single quotes */
203   if (yytext[0] == '\'' && yytext[yyleng - 1] == '\'') {
204     yytext++;
205     yyleng = yyleng - 2;
206   }
207   RETURN_TOKEN(TC_RAW, yytext, yyleng);
210 <ST_SECTION_RAW,ST_SECTION_VALUE>"]"{TABS_AND_SPACES}*{NEWLINE}? {
211 /* End of section */
212   BEGIN(INITIAL);
213   SCNG(lineno)++;
214   return ']';
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 */
230   BEGIN(INITIAL);
231   return ']';
234 <ST_DOUBLE_QUOTES,ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{DOLLAR_CURLY} {
235 /* Variable start */
236   yy_push_state(ST_VARNAME);
237   return TC_DOLLAR_CURLY;
240 <ST_VARNAME>{LABEL} {
241 /* Variable name */
242   RETURN_TOKEN(TC_VARNAME, yytext, yyleng);
245 <ST_VARNAME>"}" { /* Variable end */
246   yy_pop_state();
247   return '}';
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);
260 <INITIAL>{LABEL} {
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);
269   } else {
270     yy_push_state(ST_VALUE);
271   }
272   return '=';
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] == '"') {
279     yytext++;
280     yyleng = yyleng - 2;
281   }
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 */
292   BEGIN(INITIAL);
293   SCNG(lineno)++;
294   return END_OF_LINE;
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);
307 <INITIAL>{TOKENS} {
308 /* Disallow these chars outside option values */
309   return yytext[0];
312 <ST_VALUE>{OPERATORS}{TABS_AND_SPACES}* {
313 /* Boolean operators */
314   return yytext[0];
317 <ST_VALUE>[=] {
318 /* Make = used in option value to trigger error */
319   yyless(0);
320   BEGIN(INITIAL);
321   return END_OF_LINE;
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);
337   return '"';
340 <ST_DOUBLE_QUOTES>{DOUBLE_QUOTES_CHARS}+("\\"["])? {
341 /* Escape double quoted string contents */
342   if (yyleng > 1 && yytext[yyleng-1] == '"' && yytext[yyleng-2] == '\\') {
343     yyless(yyleng-1);
344     yyleng--;
345   }
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 */
352   yy_pop_state();
353   return '"';
356 <ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{WHITESPACE} {
357   RETURN_TOKEN(TC_WHITESPACE, yytext, yyleng);
360 <INITIAL,ST_RAW>{TABS_AND_SPACES}+ {
361   /* eat whitespace */
362   return GOTO_RESTART;
365 <INITIAL>{TABS_AND_SPACES}*{NEWLINE} {
366   SCNG(lineno)++;
367   return END_OF_LINE;
370 <INITIAL,ST_VALUE,ST_RAW>{TABS_AND_SPACES}*[;][^\r\n]*{NEWLINE} {
371 /* Comment */
372   BEGIN(INITIAL);
373   SCNG(lineno)++;
374   return END_OF_LINE;
377 <INITIAL>{TABS_AND_SPACES}*[#][^\r\n]*{NEWLINE} {
378 /* #Comment */
379   Logger::Error("Comments starting with '#' are deprecated in %s on line %d",
380                 SCNG(filename).data(), SCNG(lineno));
381   BEGIN(INITIAL);
382   SCNG(lineno)++;
383   return END_OF_LINE;
386 <ST_VALUE,ST_RAW><<EOF>> {
387 /* End of option value (if EOF is reached before EOL) */
388   BEGIN(INITIAL);
389   return END_OF_LINE;
394 static void __attribute__((__unused__))
395 suppress_defined_but_not_used_warnings() {
396   yyunput(0, 0);
397   yy_top_state();