Annotation of embedaddon/php/Zend/zend_ini_scanner.l, revision 1.1.1.1
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | Zend Engine |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1998-2012 Zend Technologies Ltd. (http://www.zend.com) |
6: +----------------------------------------------------------------------+
7: | This source file is subject to version 2.00 of the Zend license, |
8: | that is bundled with this package in the file LICENSE, and is |
9: | available through the world-wide-web at the following url: |
10: | http://www.zend.com/license/2_00.txt. |
11: | If you did not receive a copy of the Zend license and are unable to |
12: | obtain it through the world-wide-web, please send a note to |
13: | license@zend.com so we can mail you a copy immediately. |
14: +----------------------------------------------------------------------+
15: | Authors: Zeev Suraski <zeev@zend.com> |
16: | Jani Taskinen <jani@php.net> |
17: | Marcus Boerger <helly@php.net> |
18: | Nuno Lopes <nlopess@php.net> |
19: | Scott MacVicar <scottmac@php.net> |
20: +----------------------------------------------------------------------+
21: */
22:
23: /* $Id: zend_ini_scanner.l 321634 2012-01-01 13:15:04Z felipe $ */
24:
25: #include <errno.h>
26: #include "zend.h"
27: #include "zend_globals.h"
28: #include <zend_ini_parser.h>
29: #include "zend_ini_scanner.h"
30:
31: #if 0
32: # define YYDEBUG(s, c) printf("state: %d char: %c\n", s, c)
33: #else
34: # define YYDEBUG(s, c)
35: #endif
36:
37: #include "zend_ini_scanner_defs.h"
38:
39: #define YYCTYPE unsigned char
40: /* allow the scanner to read one null byte after the end of the string (from ZEND_MMAP_AHEAD)
41: * so that if will be able to terminate to match the current token (e.g. non-enclosed string) */
42: #define YYFILL(n) { if (YYCURSOR > YYLIMIT) return 0; }
43: #define YYCURSOR SCNG(yy_cursor)
44: #define YYLIMIT SCNG(yy_limit)
45: #define YYMARKER SCNG(yy_marker)
46:
47: #define YYGETCONDITION() SCNG(yy_state)
48: #define YYSETCONDITION(s) SCNG(yy_state) = s
49:
50: #define STATE(name) yyc##name
51:
52: /* emulate flex constructs */
53: #define BEGIN(state) YYSETCONDITION(STATE(state))
54: #define YYSTATE YYGETCONDITION()
55: #define yytext ((char*)SCNG(yy_text))
56: #define yyleng SCNG(yy_leng)
57: #define yyless(x) do { YYCURSOR = (unsigned char*)yytext + x; \
58: yyleng = (unsigned int)x; } while(0)
59:
60: /* #define yymore() goto yymore_restart */
61:
62: /* perform sanity check. If this message is triggered you should
63: increase the ZEND_MMAP_AHEAD value in the zend_streams.h file */
64: /*!max:re2c */
65: #if ZEND_MMAP_AHEAD < (YYMAXFILL + 1)
66: # error ZEND_MMAP_AHEAD should be greater than YYMAXFILL
67: #endif
68:
69:
70: /* How it works (for the core ini directives):
71: * ===========================================
72: *
73: * 1. Scanner scans file for tokens and passes them to parser.
74: * 2. Parser parses the tokens and passes the name/value pairs to the callback
75: * function which stores them in the configuration hash table.
76: * 3. Later REGISTER_INI_ENTRIES() is called which triggers the actual
77: * registering of ini entries and uses zend_get_configuration_directive()
78: * to fetch the previously stored name/value pair from configuration hash table
79: * and registers the static ini entries which match the name to the value
80: * into EG(ini_directives) hash table.
81: * 4. PATH section entries are used per-request from down to top, each overriding
82: * previous if one exists. zend_alter_ini_entry() is called for each entry.
83: * Settings in PATH section are ZEND_INI_SYSTEM accessible and thus mimics the
84: * php_admin_* directives used within Apache httpd.conf when PHP is compiled as
85: * module for Apache.
86: * 5. User defined ini files (like .htaccess for apache) are parsed for each request and
87: * stored in separate hash defined by SAPI.
88: */
89:
90: /* TODO: (ordered by importance :-)
91: * ===============================================================================
92: *
93: * - Separate constant lookup totally from plain strings (using CONSTANT pattern)
94: * - Add #if .. #else .. #endif and ==, !=, <, > , <=, >= operators
95: * - Add #include "some.ini"
96: * - Allow variables to refer to options also when using parse_ini_file()
97: *
98: */
99:
100: /* Globals Macros */
101: #define SCNG INI_SCNG
102: #ifdef ZTS
103: ZEND_API ts_rsrc_id ini_scanner_globals_id;
104: #else
105: ZEND_API zend_ini_scanner_globals ini_scanner_globals;
106: #endif
107:
108: /* Eat leading whitespace */
109: #define EAT_LEADING_WHITESPACE() \
110: while (yytext[0]) { \
111: if (yytext[0] == ' ' || yytext[0] == '\t') { \
112: SCNG(yy_text)++; \
113: yyleng--; \
114: } else { \
115: break; \
116: } \
117: }
118:
119: /* Eat trailing whitespace + extra char */
120: #define EAT_TRAILING_WHITESPACE_EX(ch) \
121: while (yyleng > 0 && ( \
122: (ch != 'X' && yytext[yyleng - 1] == ch) || \
123: yytext[yyleng - 1] == '\n' || \
124: yytext[yyleng - 1] == '\r' || \
125: yytext[yyleng - 1] == '\t' || \
126: yytext[yyleng - 1] == ' ') \
127: ) { \
128: yyleng--; \
129: }
130:
131: /* Eat trailing whitespace */
132: #define EAT_TRAILING_WHITESPACE() EAT_TRAILING_WHITESPACE_EX('X')
133:
134: #define zend_ini_copy_value(retval, str, len) { \
135: Z_STRVAL_P(retval) = zend_strndup(str, len); \
136: Z_STRLEN_P(retval) = len; \
137: Z_TYPE_P(retval) = IS_STRING; \
138: }
139:
140: #define RETURN_TOKEN(type, str, len) { \
141: zend_ini_copy_value(ini_lval, str, len); \
142: return type; \
143: }
144:
145: static void _yy_push_state(int new_state TSRMLS_DC)
146: {
147: zend_stack_push(&SCNG(state_stack), (void *) &YYGETCONDITION(), sizeof(int));
148: YYSETCONDITION(new_state);
149: }
150:
151: #define yy_push_state(state_and_tsrm) _yy_push_state(yyc##state_and_tsrm)
152:
153: static void yy_pop_state(TSRMLS_D)
154: {
155: int *stack_state;
156: zend_stack_top(&SCNG(state_stack), (void **) &stack_state);
157: YYSETCONDITION(*stack_state);
158: zend_stack_del_top(&SCNG(state_stack));
159: }
160:
161: static void yy_scan_buffer(char *str, unsigned int len TSRMLS_DC)
162: {
163: YYCURSOR = (YYCTYPE*)str;
164: SCNG(yy_start) = YYCURSOR;
165: YYLIMIT = YYCURSOR + len;
166: }
167:
168: #define ini_filename SCNG(filename)
169:
170: /* {{{ init_ini_scanner()
171: */
172: static int init_ini_scanner(int scanner_mode, zend_file_handle *fh TSRMLS_DC)
173: {
174: /* Sanity check */
175: if (scanner_mode != ZEND_INI_SCANNER_NORMAL && scanner_mode != ZEND_INI_SCANNER_RAW) {
176: zend_error(E_WARNING, "Invalid scanner mode");
177: return FAILURE;
178: }
179:
180: SCNG(lineno) = 1;
181: SCNG(scanner_mode) = scanner_mode;
182: SCNG(yy_in) = fh;
183:
184: if (fh != NULL) {
185: ini_filename = zend_strndup(fh->filename, strlen(fh->filename));
186: } else {
187: ini_filename = NULL;
188: }
189:
190: zend_stack_init(&SCNG(state_stack));
191: BEGIN(INITIAL);
192:
193: return SUCCESS;
194: }
195: /* }}} */
196:
197: /* {{{ shutdown_ini_scanner()
198: */
199: void shutdown_ini_scanner(TSRMLS_D)
200: {
201: zend_stack_destroy(&SCNG(state_stack));
202: if (ini_filename) {
203: free(ini_filename);
204: }
205: }
206: /* }}} */
207:
208: /* {{{ zend_ini_scanner_get_lineno()
209: */
210: int zend_ini_scanner_get_lineno(TSRMLS_D)
211: {
212: return SCNG(lineno);
213: }
214: /* }}} */
215:
216: /* {{{ zend_ini_scanner_get_filename()
217: */
218: char *zend_ini_scanner_get_filename(TSRMLS_D)
219: {
220: return ini_filename ? ini_filename : "Unknown";
221: }
222: /* }}} */
223:
224: /* {{{ zend_ini_open_file_for_scanning()
225: */
226: int zend_ini_open_file_for_scanning(zend_file_handle *fh, int scanner_mode TSRMLS_DC)
227: {
228: char *buf;
229: size_t size;
230:
231: if (zend_stream_fixup(fh, &buf, &size TSRMLS_CC) == FAILURE ||
232: init_ini_scanner(scanner_mode, fh TSRMLS_CC) == FAILURE
233: ) {
234: return FAILURE;
235: }
236:
237: yy_scan_buffer(buf, size TSRMLS_CC);
238:
239: return SUCCESS;
240: }
241: /* }}} */
242:
243: /* {{{ zend_ini_prepare_string_for_scanning()
244: */
245: int zend_ini_prepare_string_for_scanning(char *str, int scanner_mode TSRMLS_DC)
246: {
247: int len = strlen(str);
248:
249: if (init_ini_scanner(scanner_mode, NULL TSRMLS_CC) == FAILURE) {
250: return FAILURE;
251: }
252:
253: yy_scan_buffer(str, len TSRMLS_CC);
254:
255: return SUCCESS;
256: }
257: /* }}} */
258:
259: /* {{{ zend_ini_escape_string()
260: */
261: static void zend_ini_escape_string(zval *lval, char *str, int len, char quote_type TSRMLS_DC)
262: {
263: register char *s, *t;
264: char *end;
265:
266: zend_ini_copy_value(lval, str, len);
267:
268: /* convert escape sequences */
269: s = t = Z_STRVAL_P(lval);
270: end = s + Z_STRLEN_P(lval);
271:
272: while (s < end) {
273: if (*s == '\\') {
274: s++;
275: if (s >= end) {
276: *t++ = '\\';
277: continue;
278: }
279: switch (*s) {
280: case '"':
281: if (*s != quote_type) {
282: *t++ = '\\';
283: *t++ = *s;
284: break;
285: }
286: case '\\':
287: case '$':
288: *t++ = *s;
289: Z_STRLEN_P(lval)--;
290: break;
291: default:
292: *t++ = '\\';
293: *t++ = *s;
294: break;
295: }
296: } else {
297: *t++ = *s;
298: }
299: if (*s == '\n' || (*s == '\r' && (*(s+1) != '\n'))) {
300: SCNG(lineno)++;
301: }
302: s++;
303: }
304: *t = 0;
305: }
306: /* }}} */
307:
308: int ini_lex(zval *ini_lval TSRMLS_DC)
309: {
310: restart:
311: SCNG(yy_text) = YYCURSOR;
312:
313: /* yymore_restart: */
314: /* detect EOF */
315: if (YYCURSOR >= YYLIMIT) {
316: if (YYSTATE == STATE(ST_VALUE) || YYSTATE == STATE(ST_RAW)) {
317: BEGIN(INITIAL);
318: return END_OF_LINE;
319: }
320: return 0;
321: }
322:
323: /* Eat any UTF-8 BOM we find in the first 3 bytes */
324: if (YYCURSOR == SCNG(yy_start) && YYCURSOR + 3 < YYLIMIT) {
325: if (memcmp(YYCURSOR, "\xef\xbb\xbf", 3) == 0) {
326: YYCURSOR += 3;
327: goto restart;
328: }
329: }
330: /*!re2c
331: re2c:yyfill:check = 0;
332: LNUM [0-9]+
333: DNUM ([0-9]*[\.][0-9]+)|([0-9]+[\.][0-9]*)
334: NUMBER [-]?{LNUM}|{DNUM}
335: ANY_CHAR (.|[\n\t])
336: NEWLINE ("\r"|"\n"|"\r\n")
337: TABS_AND_SPACES [ \t]
338: WHITESPACE [ \t]+
339: CONSTANT [a-zA-Z_][a-zA-Z0-9_]*
340: LABEL [^=\n\r\t;|&$~(){}!"\[]+
341: TOKENS [:,.\[\]"'()|^&+-/*=%$!~<>?@{}]
342: OPERATORS [&|~()!]
343: DOLLAR_CURLY "${"
344:
345: SECTION_RAW_CHARS [^\]\n\r]
346: SINGLE_QUOTED_CHARS [^']
347: RAW_VALUE_CHARS [^\n\r;\000]
348:
349: LITERAL_DOLLAR ("$"([^{\000]|("\\"{ANY_CHAR})))
350: VALUE_CHARS ([^$= \t\n\r;&|~()!"'\000]|{LITERAL_DOLLAR})
351: SECTION_VALUE_CHARS ([^$\n\r;"'\]\\]|("\\"{ANY_CHAR})|{LITERAL_DOLLAR})
352:
353: <!*> := yyleng = YYCURSOR - SCNG(yy_text);
354:
355: <INITIAL>"[" { /* Section start */
356: /* Enter section data lookup state */
357: if (SCNG(scanner_mode) == ZEND_INI_SCANNER_RAW) {
358: yy_push_state(ST_SECTION_RAW TSRMLS_CC);
359: } else {
360: yy_push_state(ST_SECTION_VALUE TSRMLS_CC);
361: }
362: return TC_SECTION;
363: }
364:
365: <ST_VALUE,ST_SECTION_VALUE,ST_OFFSET>"'"{SINGLE_QUOTED_CHARS}+"'" { /* Raw string */
366: /* Eat leading and trailing single quotes */
367: if (yytext[0] == '\'' && yytext[yyleng - 1] == '\'') {
368: SCNG(yy_text)++;
369: yyleng = yyleng - 2;
370: }
371: RETURN_TOKEN(TC_RAW, yytext, yyleng);
372: }
373:
374: <ST_SECTION_RAW,ST_SECTION_VALUE>"]"{TABS_AND_SPACES}*{NEWLINE}? { /* End of section */
375: BEGIN(INITIAL);
376: SCNG(lineno)++;
377: return ']';
378: }
379:
380: <INITIAL>{LABEL}"["{TABS_AND_SPACES}* { /* Start of option with offset */
381: /* Eat leading whitespace */
382: EAT_LEADING_WHITESPACE();
383:
384: /* Eat trailing whitespace and [ */
385: EAT_TRAILING_WHITESPACE_EX('[');
386:
387: /* Enter offset lookup state */
388: yy_push_state(ST_OFFSET TSRMLS_CC);
389:
390: RETURN_TOKEN(TC_OFFSET, yytext, yyleng);
391: }
392:
393: <ST_OFFSET>{TABS_AND_SPACES}*"]" { /* End of section or an option offset */
394: BEGIN(INITIAL);
395: return ']';
396: }
397:
398: <ST_DOUBLE_QUOTES,ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{DOLLAR_CURLY} { /* Variable start */
399: yy_push_state(ST_VARNAME TSRMLS_CC);
400: return TC_DOLLAR_CURLY;
401: }
402:
403: <ST_VARNAME>{LABEL} { /* Variable name */
404: /* Eat leading whitespace */
405: EAT_LEADING_WHITESPACE();
406:
407: /* Eat trailing whitespace */
408: EAT_TRAILING_WHITESPACE();
409:
410: RETURN_TOKEN(TC_VARNAME, yytext, yyleng);
411: }
412:
413: <ST_VARNAME>"}" { /* Variable end */
414: yy_pop_state(TSRMLS_C);
415: return '}';
416: }
417:
418: <INITIAL,ST_VALUE>("true"|"on"|"yes"){TABS_AND_SPACES}* { /* TRUE value (when used outside option value/offset this causes parse error!) */
419: RETURN_TOKEN(BOOL_TRUE, "1", 1);
420: }
421:
422: <INITIAL,ST_VALUE>("false"|"off"|"no"|"none"|"null"){TABS_AND_SPACES}* { /* FALSE value (when used outside option value/offset this causes parse error!)*/
423: RETURN_TOKEN(BOOL_FALSE, "", 0);
424: }
425:
426: <INITIAL>{LABEL} { /* Get option name */
427: /* Eat leading whitespace */
428: EAT_LEADING_WHITESPACE();
429:
430: /* Eat trailing whitespace */
431: EAT_TRAILING_WHITESPACE();
432:
433: RETURN_TOKEN(TC_LABEL, yytext, yyleng);
434: }
435:
436: <INITIAL>{TABS_AND_SPACES}*[=]{TABS_AND_SPACES}* { /* Start option value */
437: if (SCNG(scanner_mode) == ZEND_INI_SCANNER_RAW) {
438: yy_push_state(ST_RAW TSRMLS_CC);
439: } else {
440: yy_push_state(ST_VALUE TSRMLS_CC);
441: }
442: return '=';
443: }
444:
445: <ST_RAW>{RAW_VALUE_CHARS}+ { /* Raw value, only used when SCNG(scanner_mode) == ZEND_INI_SCANNER_RAW. */
446: /* Eat leading and trailing double quotes */
447: if (yytext[0] == '"' && yytext[yyleng - 1] == '"') {
448: SCNG(yy_text)++;
449: yyleng = yyleng - 2;
450: }
451: RETURN_TOKEN(TC_RAW, yytext, yyleng);
452: }
453:
454: <ST_SECTION_RAW>{SECTION_RAW_CHARS}+ { /* Raw value, only used when SCNG(scanner_mode) == ZEND_INI_SCANNER_RAW. */
455: RETURN_TOKEN(TC_RAW, yytext, yyleng);
456: }
457:
458: <ST_VALUE,ST_RAW>{TABS_AND_SPACES}*{NEWLINE} { /* End of option value */
459: BEGIN(INITIAL);
460: SCNG(lineno)++;
461: return END_OF_LINE;
462: }
463:
464: <ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{CONSTANT} { /* Get constant option value */
465: RETURN_TOKEN(TC_CONSTANT, yytext, yyleng);
466: }
467:
468: <ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{NUMBER} { /* Get number option value as string */
469: RETURN_TOKEN(TC_NUMBER, yytext, yyleng);
470: }
471:
472: <INITIAL>{TOKENS} { /* Disallow these chars outside option values */
473: return yytext[0];
474: }
475:
476: <ST_VALUE>{OPERATORS}{TABS_AND_SPACES}* { /* Boolean operators */
477: return yytext[0];
478: }
479:
480: <ST_VALUE>[=] { /* Make = used in option value to trigger error */
481: yyless(0);
482: BEGIN(INITIAL);
483: return END_OF_LINE;
484: }
485:
486: <ST_VALUE>{VALUE_CHARS}+ { /* Get everything else as option/offset value */
487: RETURN_TOKEN(TC_STRING, yytext, yyleng);
488: }
489:
490: <ST_SECTION_VALUE,ST_OFFSET>{SECTION_VALUE_CHARS}+ { /* Get rest as section/offset value */
491: RETURN_TOKEN(TC_STRING, yytext, yyleng);
492: }
493:
494: <ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{TABS_AND_SPACES}*["] { /* Double quoted '"' string start */
495: yy_push_state(ST_DOUBLE_QUOTES TSRMLS_CC);
496: return '"';
497: }
498:
499: <ST_DOUBLE_QUOTES>["]{TABS_AND_SPACES}* { /* Double quoted '"' string ends */
500: yy_pop_state(TSRMLS_C);
501: return '"';
502: }
503:
504: <ST_DOUBLE_QUOTES>[^] { /* Escape double quoted string contents */
505: if (YYCURSOR > YYLIMIT) {
506: return 0;
507: }
508:
509: while (YYCURSOR < YYLIMIT) {
510: switch (*YYCURSOR++) {
511: case '"':
512: if (YYCURSOR < YYLIMIT && YYCURSOR[-2] == '\\' && *YYCURSOR != '\r' && *YYCURSOR != '\n') {
513: continue;
514: }
515: break;
516: case '$':
517: if (*YYCURSOR == '{') {
518: break;
519: }
520: continue;
521: case '\\':
522: if (YYCURSOR < YYLIMIT && *YYCURSOR != '"') {
523: YYCURSOR++;
524: }
525: /* fall through */
526: default:
527: continue;
528: }
529:
530: YYCURSOR--;
531: break;
532: }
533:
534: yyleng = YYCURSOR - SCNG(yy_text);
535:
536: zend_ini_escape_string(ini_lval, yytext, yyleng, '"' TSRMLS_CC);
537: return TC_QUOTED_STRING;
538: }
539:
540: <ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{WHITESPACE} {
541: RETURN_TOKEN(TC_WHITESPACE, yytext, yyleng);
542: }
543:
544: <INITIAL,ST_RAW>{TABS_AND_SPACES}+ {
545: /* eat whitespace */
546: goto restart;
547: }
548:
549: <INITIAL>{TABS_AND_SPACES}*{NEWLINE} {
550: SCNG(lineno)++;
551: return END_OF_LINE;
552: }
553:
554: <INITIAL,ST_VALUE,ST_RAW>{TABS_AND_SPACES}*[;][^\r\n]*{NEWLINE} { /* Comment */
555: BEGIN(INITIAL);
556: SCNG(lineno)++;
557: return END_OF_LINE;
558: }
559:
560: <INITIAL>{TABS_AND_SPACES}*[#][^\r\n]*{NEWLINE} { /* #Comment */
561: zend_error(E_DEPRECATED, "Comments starting with '#' are deprecated in %s on line %d", zend_ini_scanner_get_filename(TSRMLS_C), SCNG(lineno));
562: BEGIN(INITIAL);
563: SCNG(lineno)++;
564: return END_OF_LINE;
565: }
566:
567: <ST_VALUE,ST_RAW>[^] { /* End of option value (if EOF is reached before EOL */
568: BEGIN(INITIAL);
569: return END_OF_LINE;
570: }
571:
572: <*>[^] {
573: return 0;
574: }
575:
576: */
577: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>