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