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