zend_ini_scanner.l 17 KB

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