zend_ini_scanner.l 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  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. /* $Id$ */
  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. #if 0
  30. # define YYDEBUG(s, c) printf("state: %d char: %c\n", s, c)
  31. #else
  32. # define YYDEBUG(s, c)
  33. #endif
  34. #include "zend_ini_scanner_defs.h"
  35. #define YYCTYPE unsigned char
  36. /* allow the scanner to read one null byte after the end of the string (from ZEND_MMAP_AHEAD)
  37. * so that if will be able to terminate to match the current token (e.g. non-enclosed string) */
  38. #define YYFILL(n) { if (YYCURSOR > YYLIMIT) return 0; }
  39. #define YYCURSOR SCNG(yy_cursor)
  40. #define YYLIMIT SCNG(yy_limit)
  41. #define YYMARKER SCNG(yy_marker)
  42. #define YYGETCONDITION() SCNG(yy_state)
  43. #define YYSETCONDITION(s) SCNG(yy_state) = s
  44. #define STATE(name) yyc##name
  45. /* emulate flex constructs */
  46. #define BEGIN(state) YYSETCONDITION(STATE(state))
  47. #define YYSTATE YYGETCONDITION()
  48. #define yytext ((char*)SCNG(yy_text))
  49. #define yyleng SCNG(yy_leng)
  50. #define yyless(x) do { YYCURSOR = (unsigned char*)yytext + x; \
  51. yyleng = (unsigned int)x; } while(0)
  52. /* #define yymore() goto yymore_restart */
  53. /* perform sanity check. If this message is triggered you should
  54. increase the ZEND_MMAP_AHEAD value in the zend_streams.h file */
  55. /*!max:re2c */
  56. #if ZEND_MMAP_AHEAD < (YYMAXFILL + 1)
  57. # error ZEND_MMAP_AHEAD should be greater than YYMAXFILL
  58. #endif
  59. /* How it works (for the core ini directives):
  60. * ===========================================
  61. *
  62. * 1. Scanner scans file for tokens and passes them to parser.
  63. * 2. Parser parses the tokens and passes the name/value pairs to the callback
  64. * function which stores them in the configuration hash table.
  65. * 3. Later REGISTER_INI_ENTRIES() is called which triggers the actual
  66. * registering of ini entries and uses zend_get_configuration_directive()
  67. * to fetch the previously stored name/value pair from configuration hash table
  68. * and registers the static ini entries which match the name to the value
  69. * into EG(ini_directives) hash table.
  70. * 4. PATH section entries are used per-request from down to top, each overriding
  71. * previous if one exists. zend_alter_ini_entry() is called for each entry.
  72. * Settings in PATH section are ZEND_INI_SYSTEM accessible and thus mimics the
  73. * php_admin_* directives used within Apache httpd.conf when PHP is compiled as
  74. * module for Apache.
  75. * 5. User defined ini files (like .htaccess for apache) are parsed for each request and
  76. * stored in separate hash defined by SAPI.
  77. */
  78. /* TODO: (ordered by importance :-)
  79. * ===============================================================================
  80. *
  81. * - Separate constant lookup totally from plain strings (using CONSTANT pattern)
  82. * - Add #if .. #else .. #endif and ==, !=, <, > , <=, >= operators
  83. * - Add #include "some.ini"
  84. * - Allow variables to refer to options also when using parse_ini_file()
  85. *
  86. */
  87. /* Globals Macros */
  88. #define SCNG INI_SCNG
  89. #ifdef ZTS
  90. ZEND_API ts_rsrc_id ini_scanner_globals_id;
  91. #else
  92. ZEND_API zend_ini_scanner_globals ini_scanner_globals;
  93. #endif
  94. /* Eat leading whitespace */
  95. #define EAT_LEADING_WHITESPACE() \
  96. while (yyleng) { \
  97. if (yytext[0] == ' ' || yytext[0] == '\t') { \
  98. SCNG(yy_text)++; \
  99. yyleng--; \
  100. } else { \
  101. break; \
  102. } \
  103. }
  104. /* Eat trailing whitespace + extra char */
  105. #define EAT_TRAILING_WHITESPACE_EX(ch) \
  106. while (yyleng && ( \
  107. (ch != 'X' && yytext[yyleng - 1] == ch) || \
  108. yytext[yyleng - 1] == '\n' || \
  109. yytext[yyleng - 1] == '\r' || \
  110. yytext[yyleng - 1] == '\t' || \
  111. yytext[yyleng - 1] == ' ') \
  112. ) { \
  113. yyleng--; \
  114. }
  115. /* Eat trailing whitespace */
  116. #define EAT_TRAILING_WHITESPACE() EAT_TRAILING_WHITESPACE_EX('X')
  117. #define zend_ini_copy_value(retval, str, len) { \
  118. Z_STRVAL_P(retval) = zend_strndup(str, len); \
  119. Z_STRLEN_P(retval) = len; \
  120. Z_TYPE_P(retval) = IS_STRING; \
  121. }
  122. #define RETURN_TOKEN(type, str, len) { \
  123. if (SCNG(scanner_mode) == ZEND_INI_SCANNER_TYPED) { \
  124. zend_ini_copy_typed_value(ini_lval, type, str, len); \
  125. } else { \
  126. zend_ini_copy_value(ini_lval, str, len); \
  127. } \
  128. return type; \
  129. }
  130. static inline int convert_to_number(zval *retval, const char *str, const int str_len)
  131. {
  132. zend_uchar type;
  133. int overflow;
  134. long lval;
  135. double dval;
  136. if ((type = is_numeric_string_ex(str, str_len, &lval, &dval, 0, &overflow)) != 0) {
  137. if (type == IS_LONG) {
  138. ZVAL_LONG(retval, lval);
  139. return SUCCESS;
  140. } else if (type == IS_DOUBLE && !overflow) {
  141. ZVAL_DOUBLE(retval, dval);
  142. return SUCCESS;
  143. }
  144. }
  145. return FAILURE;
  146. }
  147. static void zend_ini_copy_typed_value(zval *retval, const int type, const char *str, int len)
  148. {
  149. switch (type) {
  150. case BOOL_FALSE:
  151. case BOOL_TRUE:
  152. ZVAL_BOOL(retval, type == BOOL_TRUE);
  153. break;
  154. case NULL_NULL:
  155. ZVAL_NULL(retval);
  156. break;
  157. case TC_NUMBER:
  158. if (convert_to_number(retval, str, len) == SUCCESS) {
  159. break;
  160. }
  161. /* intentional fall-through */
  162. default:
  163. zend_ini_copy_value(retval, str, len);
  164. }
  165. }
  166. static void _yy_push_state(int new_state TSRMLS_DC)
  167. {
  168. zend_stack_push(&SCNG(state_stack), (void *) &YYGETCONDITION(), sizeof(int));
  169. YYSETCONDITION(new_state);
  170. }
  171. #define yy_push_state(state_and_tsrm) _yy_push_state(yyc##state_and_tsrm)
  172. static void yy_pop_state(TSRMLS_D)
  173. {
  174. int *stack_state;
  175. zend_stack_top(&SCNG(state_stack), (void **) &stack_state);
  176. YYSETCONDITION(*stack_state);
  177. zend_stack_del_top(&SCNG(state_stack));
  178. }
  179. static void yy_scan_buffer(char *str, unsigned int len TSRMLS_DC)
  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 TSRMLS_DC)
  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));
  204. BEGIN(INITIAL);
  205. return SUCCESS;
  206. }
  207. /* }}} */
  208. /* {{{ shutdown_ini_scanner()
  209. */
  210. void shutdown_ini_scanner(TSRMLS_D)
  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. int zend_ini_scanner_get_lineno(TSRMLS_D)
  221. {
  222. return SCNG(lineno);
  223. }
  224. /* }}} */
  225. /* {{{ zend_ini_scanner_get_filename()
  226. */
  227. char *zend_ini_scanner_get_filename(TSRMLS_D)
  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 TSRMLS_DC)
  235. {
  236. char *buf;
  237. size_t size;
  238. if (zend_stream_fixup(fh, &buf, &size TSRMLS_CC) == FAILURE) {
  239. return FAILURE;
  240. }
  241. if (init_ini_scanner(scanner_mode, fh TSRMLS_CC) == FAILURE) {
  242. zend_file_handle_dtor(fh TSRMLS_CC);
  243. return FAILURE;
  244. }
  245. yy_scan_buffer(buf, size TSRMLS_CC);
  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 TSRMLS_DC)
  252. {
  253. int len = strlen(str);
  254. if (init_ini_scanner(scanner_mode, NULL TSRMLS_CC) == FAILURE) {
  255. return FAILURE;
  256. }
  257. yy_scan_buffer(str, len TSRMLS_CC);
  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 TSRMLS_DC)
  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 TSRMLS_DC)
  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. yy_push_state(ST_SECTION_RAW TSRMLS_CC);
  351. } else {
  352. yy_push_state(ST_SECTION_VALUE TSRMLS_CC);
  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. yy_push_state(ST_OFFSET TSRMLS_CC);
  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 TSRMLS_CC);
  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(TSRMLS_C);
  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. yy_push_state(ST_RAW TSRMLS_CC);
  416. } else {
  417. yy_push_state(ST_VALUE TSRMLS_CC);
  418. }
  419. return '=';
  420. }
  421. <ST_RAW>{RAW_VALUE_CHARS} { /* Raw value, only used when SCNG(scanner_mode) == ZEND_INI_SCANNER_RAW. */
  422. char *sc = NULL;
  423. while (YYCURSOR < YYLIMIT) {
  424. switch (*YYCURSOR) {
  425. case '\n':
  426. case '\r':
  427. goto end_raw_value_chars;
  428. break;
  429. case ';':
  430. if (sc == NULL) {
  431. sc = YYCURSOR;
  432. }
  433. /* no break */
  434. default:
  435. YYCURSOR++;
  436. break;
  437. }
  438. }
  439. end_raw_value_chars:
  440. yyleng = YYCURSOR - SCNG(yy_text);
  441. /* Eat trailing semicolons */
  442. while (yytext[yyleng - 1] == ';') {
  443. yyleng--;
  444. }
  445. /* Eat leading and trailing double quotes */
  446. if (yyleng > 1 && yytext[0] == '"' && yytext[yyleng - 1] == '"') {
  447. SCNG(yy_text)++;
  448. yyleng = yyleng - 2;
  449. } else if (sc) {
  450. YYCURSOR = sc;
  451. yyleng = YYCURSOR - SCNG(yy_text);
  452. }
  453. RETURN_TOKEN(TC_RAW, yytext, yyleng);
  454. }
  455. <ST_SECTION_RAW>{SECTION_RAW_CHARS}+ { /* Raw value, only used when SCNG(scanner_mode) == ZEND_INI_SCANNER_RAW. */
  456. RETURN_TOKEN(TC_RAW, yytext, yyleng);
  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. <ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{CONSTANT} { /* Get constant option value */
  464. RETURN_TOKEN(TC_CONSTANT, yytext, yyleng);
  465. }
  466. <ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{NUMBER} { /* Get number option value as string */
  467. RETURN_TOKEN(TC_NUMBER, yytext, yyleng);
  468. }
  469. <INITIAL>{TOKENS} { /* Disallow these chars outside option values */
  470. return yytext[0];
  471. }
  472. <ST_VALUE>{OPERATORS}{TABS_AND_SPACES}* { /* Boolean operators */
  473. return yytext[0];
  474. }
  475. <ST_VALUE>[=] { /* Make = used in option value to trigger error */
  476. yyless(0);
  477. BEGIN(INITIAL);
  478. return END_OF_LINE;
  479. }
  480. <ST_VALUE>{VALUE_CHARS}+ { /* Get everything else as option/offset value */
  481. RETURN_TOKEN(TC_STRING, yytext, yyleng);
  482. }
  483. <ST_SECTION_VALUE,ST_OFFSET>{SECTION_VALUE_CHARS}+ { /* Get rest as section/offset value */
  484. RETURN_TOKEN(TC_STRING, yytext, yyleng);
  485. }
  486. <ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{TABS_AND_SPACES}*["] { /* Double quoted '"' string start */
  487. yy_push_state(ST_DOUBLE_QUOTES TSRMLS_CC);
  488. return '"';
  489. }
  490. <ST_DOUBLE_QUOTES>["]{TABS_AND_SPACES}* { /* Double quoted '"' string ends */
  491. yy_pop_state(TSRMLS_C);
  492. return '"';
  493. }
  494. <ST_DOUBLE_QUOTES>[^] { /* Escape double quoted string contents */
  495. if (YYCURSOR > YYLIMIT) {
  496. return 0;
  497. }
  498. while (YYCURSOR < YYLIMIT) {
  499. switch (*YYCURSOR++) {
  500. case '"':
  501. if (YYCURSOR < YYLIMIT && YYCURSOR[-2] == '\\' && *YYCURSOR != '\r' && *YYCURSOR != '\n') {
  502. continue;
  503. }
  504. break;
  505. case '$':
  506. if (*YYCURSOR == '{') {
  507. break;
  508. }
  509. continue;
  510. case '\\':
  511. if (YYCURSOR < YYLIMIT && *YYCURSOR != '"') {
  512. YYCURSOR++;
  513. }
  514. /* fall through */
  515. default:
  516. continue;
  517. }
  518. YYCURSOR--;
  519. break;
  520. }
  521. yyleng = YYCURSOR - SCNG(yy_text);
  522. zend_ini_escape_string(ini_lval, yytext, yyleng, '"' TSRMLS_CC);
  523. return TC_QUOTED_STRING;
  524. }
  525. <ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{WHITESPACE} {
  526. RETURN_TOKEN(TC_WHITESPACE, yytext, yyleng);
  527. }
  528. <INITIAL,ST_RAW>{TABS_AND_SPACES}+ {
  529. /* eat whitespace */
  530. goto restart;
  531. }
  532. <INITIAL>{TABS_AND_SPACES}*{NEWLINE} {
  533. SCNG(lineno)++;
  534. return END_OF_LINE;
  535. }
  536. <INITIAL,ST_VALUE,ST_RAW>{TABS_AND_SPACES}*[;][^\r\n]*{NEWLINE} { /* Comment */
  537. BEGIN(INITIAL);
  538. SCNG(lineno)++;
  539. return END_OF_LINE;
  540. }
  541. <INITIAL>{TABS_AND_SPACES}*[#][^\r\n]*{NEWLINE} { /* #Comment */
  542. zend_error(E_DEPRECATED, "Comments starting with '#' are deprecated in %s on line %d", zend_ini_scanner_get_filename(TSRMLS_C), SCNG(lineno));
  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. }