zend_ini_scanner.l 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  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. #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. ZEND_API size_t ini_scanner_globals_offset;
  94. #else
  95. ZEND_API zend_ini_scanner_globals ini_scanner_globals;
  96. #endif
  97. #define ZEND_SYSTEM_INI CG(ini_parser_unbuffered_errors)
  98. /* Eat leading whitespace */
  99. #define EAT_LEADING_WHITESPACE() \
  100. while (yyleng) { \
  101. if (yytext[0] == ' ' || yytext[0] == '\t') { \
  102. SCNG(yy_text)++; \
  103. yyleng--; \
  104. } else { \
  105. break; \
  106. } \
  107. }
  108. /* Eat trailing whitespace + extra char */
  109. #define EAT_TRAILING_WHITESPACE_EX(ch) \
  110. while (yyleng && ( \
  111. (ch != 'X' && yytext[yyleng - 1] == ch) || \
  112. yytext[yyleng - 1] == '\n' || \
  113. yytext[yyleng - 1] == '\r' || \
  114. yytext[yyleng - 1] == '\t' || \
  115. yytext[yyleng - 1] == ' ') \
  116. ) { \
  117. yyleng--; \
  118. }
  119. /* Eat trailing whitespace */
  120. #define EAT_TRAILING_WHITESPACE() EAT_TRAILING_WHITESPACE_EX('X')
  121. #define zend_ini_copy_value(retval, str, len) \
  122. ZVAL_NEW_STR(retval, zend_string_init(str, len, ZEND_SYSTEM_INI))
  123. #define RETURN_TOKEN(type, str, len) { \
  124. if (SCNG(scanner_mode) == ZEND_INI_SCANNER_TYPED && \
  125. (YYSTATE == STATE(ST_VALUE) || YYSTATE == STATE(ST_RAW))) {\
  126. zend_ini_copy_typed_value(ini_lval, type, str, len); \
  127. } else { \
  128. zend_ini_copy_value(ini_lval, str, len); \
  129. } \
  130. return type; \
  131. }
  132. static inline zend_result convert_to_number(zval *retval, const char *str, const int str_len)
  133. {
  134. zend_uchar type;
  135. int overflow;
  136. zend_long lval;
  137. double dval;
  138. if ((type = is_numeric_string_ex(str, str_len, &lval, &dval, 0, &overflow, NULL)) != 0) {
  139. if (type == IS_LONG) {
  140. ZVAL_LONG(retval, lval);
  141. return SUCCESS;
  142. } else if (type == IS_DOUBLE && !overflow) {
  143. ZVAL_DOUBLE(retval, dval);
  144. return SUCCESS;
  145. }
  146. }
  147. return FAILURE;
  148. }
  149. static void zend_ini_copy_typed_value(zval *retval, const int type, const char *str, int len)
  150. {
  151. switch (type) {
  152. case BOOL_FALSE:
  153. case BOOL_TRUE:
  154. ZVAL_BOOL(retval, type == BOOL_TRUE);
  155. break;
  156. case NULL_NULL:
  157. ZVAL_NULL(retval);
  158. break;
  159. case TC_NUMBER:
  160. if (convert_to_number(retval, str, len) == SUCCESS) {
  161. break;
  162. }
  163. ZEND_FALLTHROUGH;
  164. default:
  165. zend_ini_copy_value(retval, str, len);
  166. }
  167. }
  168. static void _yy_push_state(int new_state)
  169. {
  170. zend_stack_push(&SCNG(state_stack), (void *) &YYGETCONDITION());
  171. YYSETCONDITION(new_state);
  172. }
  173. #define yy_push_state(state_and_tsrm) _yy_push_state(yyc##state_and_tsrm)
  174. static void yy_pop_state(void)
  175. {
  176. int *stack_state = zend_stack_top(&SCNG(state_stack));
  177. YYSETCONDITION(*stack_state);
  178. zend_stack_del_top(&SCNG(state_stack));
  179. }
  180. static void yy_scan_buffer(char *str, unsigned int len)
  181. {
  182. YYCURSOR = (YYCTYPE*)str;
  183. SCNG(yy_start) = YYCURSOR;
  184. YYLIMIT = YYCURSOR + len;
  185. }
  186. #define ini_filename SCNG(filename)
  187. /* {{{ init_ini_scanner() */
  188. static zend_result 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_string_copy(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. void shutdown_ini_scanner(void)
  210. {
  211. zend_stack_destroy(&SCNG(state_stack));
  212. if (ini_filename) {
  213. zend_string_release(ini_filename);
  214. }
  215. }
  216. /* }}} */
  217. /* {{{ zend_ini_scanner_get_lineno() */
  218. ZEND_COLD int zend_ini_scanner_get_lineno(void)
  219. {
  220. return SCNG(lineno);
  221. }
  222. /* }}} */
  223. /* {{{ zend_ini_scanner_get_filename() */
  224. ZEND_COLD char *zend_ini_scanner_get_filename(void)
  225. {
  226. return ini_filename ? ZSTR_VAL(ini_filename) : "Unknown";
  227. }
  228. /* }}} */
  229. /* {{{ zend_ini_open_file_for_scanning() */
  230. zend_result zend_ini_open_file_for_scanning(zend_file_handle *fh, int scanner_mode)
  231. {
  232. char *buf;
  233. size_t size;
  234. if (zend_stream_fixup(fh, &buf, &size) == FAILURE) {
  235. return FAILURE;
  236. }
  237. if (init_ini_scanner(scanner_mode, fh) == FAILURE) {
  238. return FAILURE;
  239. }
  240. yy_scan_buffer(buf, (unsigned int)size);
  241. return SUCCESS;
  242. }
  243. /* }}} */
  244. /* {{{ zend_ini_prepare_string_for_scanning() */
  245. zend_result zend_ini_prepare_string_for_scanning(char *str, int scanner_mode)
  246. {
  247. int len = (int)strlen(str);
  248. if (init_ini_scanner(scanner_mode, NULL) == FAILURE) {
  249. return FAILURE;
  250. }
  251. yy_scan_buffer(str, len);
  252. return SUCCESS;
  253. }
  254. /* }}} */
  255. /* {{{ zend_ini_escape_string() */
  256. static void zend_ini_escape_string(zval *lval, char *str, int len, char quote_type)
  257. {
  258. char *s, *t;
  259. char *end;
  260. zend_ini_copy_value(lval, str, len);
  261. /* convert escape sequences */
  262. s = t = Z_STRVAL_P(lval);
  263. end = s + Z_STRLEN_P(lval);
  264. while (s < end) {
  265. if (*s == '\\') {
  266. s++;
  267. if (s >= end) {
  268. *t++ = '\\';
  269. continue;
  270. }
  271. switch (*s) {
  272. case '"':
  273. if (*s != quote_type) {
  274. *t++ = '\\';
  275. *t++ = *s;
  276. break;
  277. }
  278. ZEND_FALLTHROUGH;
  279. case '\\':
  280. case '$':
  281. *t++ = *s;
  282. Z_STRLEN_P(lval)--;
  283. break;
  284. default:
  285. *t++ = '\\';
  286. *t++ = *s;
  287. break;
  288. }
  289. } else {
  290. *t++ = *s;
  291. }
  292. if (*s == '\n' || (*s == '\r' && (*(s+1) != '\n'))) {
  293. SCNG(lineno)++;
  294. }
  295. s++;
  296. }
  297. *t = 0;
  298. }
  299. /* }}} */
  300. int ini_lex(zval *ini_lval)
  301. {
  302. restart:
  303. SCNG(yy_text) = YYCURSOR;
  304. /* yymore_restart: */
  305. /* detect EOF */
  306. if (YYCURSOR >= YYLIMIT) {
  307. if (YYSTATE == STATE(ST_VALUE) || YYSTATE == STATE(ST_RAW)) {
  308. BEGIN(INITIAL);
  309. return END_OF_LINE;
  310. }
  311. return 0;
  312. }
  313. /* Eat any UTF-8 BOM we find in the first 3 bytes */
  314. if (YYCURSOR == SCNG(yy_start) && YYCURSOR + 3 < YYLIMIT) {
  315. if (memcmp(YYCURSOR, "\xef\xbb\xbf", 3) == 0) {
  316. YYCURSOR += 3;
  317. goto restart;
  318. }
  319. }
  320. /*!re2c
  321. re2c:yyfill:check = 0;
  322. LNUM [0-9]+
  323. DNUM ([0-9]*[\.][0-9]+)|([0-9]+[\.][0-9]*)
  324. NUMBER [-]?{LNUM}|{DNUM}
  325. ANY_CHAR (.|[\n\t])
  326. NEWLINE ("\r"|"\n"|"\r\n")
  327. TABS_AND_SPACES [ \t]
  328. WHITESPACE [ \t]+
  329. CONSTANT [a-zA-Z_][a-zA-Z0-9_]*
  330. LABEL [^=\n\r\t;&|^$~(){}!"\[]+
  331. TOKENS [:,.\[\]"'()&|^+-/*=%$!~<>?@{}]
  332. OPERATORS [&|^~()!]
  333. DOLLAR_CURLY "${"
  334. SECTION_RAW_CHARS [^\]\n\r]
  335. SINGLE_QUOTED_CHARS [^']
  336. RAW_VALUE_CHARS [^\n\r;\000]
  337. LITERAL_DOLLAR ("$"([^{\000]|("\\"{ANY_CHAR})))
  338. VALUE_CHARS ([^$= \t\n\r;&|^~()!"'\000]|{LITERAL_DOLLAR})
  339. SECTION_VALUE_CHARS ([^$\n\r;"'\]\\]|("\\"{ANY_CHAR})|{LITERAL_DOLLAR})
  340. <!*> := yyleng = YYCURSOR - SCNG(yy_text);
  341. <INITIAL>"[" { /* Section start */
  342. /* Enter section data lookup state */
  343. if (SCNG(scanner_mode) == ZEND_INI_SCANNER_RAW) {
  344. BEGIN(ST_SECTION_RAW);
  345. } else {
  346. BEGIN(ST_SECTION_VALUE);
  347. }
  348. return TC_SECTION;
  349. }
  350. <ST_VALUE,ST_SECTION_VALUE,ST_OFFSET>"'"{SINGLE_QUOTED_CHARS}+"'" { /* Raw string */
  351. /* Eat leading and trailing single quotes */
  352. if (yytext[0] == '\'' && yytext[yyleng - 1] == '\'') {
  353. SCNG(yy_text)++;
  354. yyleng = yyleng - 2;
  355. }
  356. RETURN_TOKEN(TC_RAW, yytext, yyleng);
  357. }
  358. <ST_SECTION_RAW,ST_SECTION_VALUE>"]"{TABS_AND_SPACES}*{NEWLINE}? { /* End of section */
  359. BEGIN(INITIAL);
  360. SCNG(lineno)++;
  361. return ']';
  362. }
  363. <INITIAL>{LABEL}"["{TABS_AND_SPACES}* { /* Start of option with offset */
  364. /* Eat leading whitespace */
  365. EAT_LEADING_WHITESPACE();
  366. /* Eat trailing whitespace and [ */
  367. EAT_TRAILING_WHITESPACE_EX('[');
  368. /* Enter offset lookup state */
  369. BEGIN(ST_OFFSET);
  370. RETURN_TOKEN(TC_OFFSET, yytext, yyleng);
  371. }
  372. <ST_OFFSET>{TABS_AND_SPACES}*"]" { /* End of section or an option offset */
  373. BEGIN(INITIAL);
  374. return ']';
  375. }
  376. <ST_DOUBLE_QUOTES,ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{DOLLAR_CURLY} { /* Variable start */
  377. yy_push_state(ST_VARNAME);
  378. return TC_DOLLAR_CURLY;
  379. }
  380. <ST_VARNAME>{LABEL} { /* Variable name */
  381. /* Eat leading whitespace */
  382. EAT_LEADING_WHITESPACE();
  383. /* Eat trailing whitespace */
  384. EAT_TRAILING_WHITESPACE();
  385. RETURN_TOKEN(TC_VARNAME, yytext, yyleng);
  386. }
  387. <ST_VARNAME>"}" { /* Variable end */
  388. yy_pop_state();
  389. return '}';
  390. }
  391. <INITIAL,ST_VALUE>("true"|"on"|"yes"){TABS_AND_SPACES}* { /* TRUE value (when used outside option value/offset this causes parse error!) */
  392. RETURN_TOKEN(BOOL_TRUE, "1", 1);
  393. }
  394. <INITIAL,ST_VALUE>("false"|"off"|"no"|"none"){TABS_AND_SPACES}* { /* FALSE value (when used outside option value/offset this causes parse error!)*/
  395. RETURN_TOKEN(BOOL_FALSE, "", 0);
  396. }
  397. <INITIAL,ST_VALUE>("null"){TABS_AND_SPACES}* {
  398. RETURN_TOKEN(NULL_NULL, "", 0);
  399. }
  400. <INITIAL>{LABEL} { /* Get option name */
  401. /* Eat leading whitespace */
  402. EAT_LEADING_WHITESPACE();
  403. /* Eat trailing whitespace */
  404. EAT_TRAILING_WHITESPACE();
  405. RETURN_TOKEN(TC_LABEL, yytext, yyleng);
  406. }
  407. <INITIAL>{TABS_AND_SPACES}*[=]{TABS_AND_SPACES}* { /* Start option value */
  408. if (SCNG(scanner_mode) == ZEND_INI_SCANNER_RAW) {
  409. BEGIN(ST_RAW);
  410. } else {
  411. BEGIN(ST_VALUE);
  412. }
  413. return '=';
  414. }
  415. <ST_RAW>{RAW_VALUE_CHARS} { /* Raw value, only used when SCNG(scanner_mode) == ZEND_INI_SCANNER_RAW. */
  416. unsigned char *sc = NULL;
  417. EAT_LEADING_WHITESPACE();
  418. while (YYCURSOR < YYLIMIT) {
  419. switch (*YYCURSOR) {
  420. case '\n':
  421. case '\r':
  422. goto end_raw_value_chars;
  423. break;
  424. case ';':
  425. if (sc == NULL) {
  426. sc = YYCURSOR;
  427. }
  428. YYCURSOR++;
  429. break;
  430. case '"':
  431. if (yytext[0] == '"') {
  432. sc = NULL;
  433. }
  434. YYCURSOR++;
  435. break;
  436. default:
  437. YYCURSOR++;
  438. break;
  439. }
  440. }
  441. end_raw_value_chars:
  442. if (sc) {
  443. yyleng = sc - SCNG(yy_text);
  444. } else {
  445. yyleng = YYCURSOR - SCNG(yy_text);
  446. }
  447. EAT_TRAILING_WHITESPACE();
  448. /* Eat leading and trailing double quotes */
  449. if (yyleng > 1 && yytext[0] == '"' && yytext[yyleng - 1] == '"') {
  450. SCNG(yy_text)++;
  451. yyleng = yyleng - 2;
  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);
  488. return '"';
  489. }
  490. <ST_DOUBLE_QUOTES>["]{TABS_AND_SPACES}* { /* Double quoted '"' string ends */
  491. yy_pop_state();
  492. return '"';
  493. }
  494. <ST_DOUBLE_QUOTES>[^] { /* Escape double quoted string contents */
  495. if (YYCURSOR > YYLIMIT) {
  496. return 0;
  497. }
  498. unsigned char *s = SCNG(yy_text);
  499. while (s < YYLIMIT) {
  500. switch (*s++) {
  501. case '"':
  502. break;
  503. case '$':
  504. if (s < YYLIMIT && *s == '{') {
  505. break;
  506. }
  507. continue;
  508. case '\\':
  509. if (s < YYLIMIT) {
  510. unsigned char escaped = *s++;
  511. /* A special case for Windows paths, e.g. key="C:\path\" */
  512. if (escaped == '"' && (s >= YYLIMIT || *s == '\n' || *s == '\r')) {
  513. break;
  514. }
  515. }
  516. ZEND_FALLTHROUGH;
  517. default:
  518. continue;
  519. }
  520. s--;
  521. break;
  522. }
  523. YYCURSOR = s;
  524. yyleng = YYCURSOR - SCNG(yy_text);
  525. zend_ini_escape_string(ini_lval, yytext, yyleng, '"');
  526. return TC_QUOTED_STRING;
  527. }
  528. <ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{WHITESPACE} {
  529. RETURN_TOKEN(TC_WHITESPACE, yytext, yyleng);
  530. }
  531. <INITIAL,ST_RAW>{TABS_AND_SPACES}+ {
  532. /* eat whitespace */
  533. goto restart;
  534. }
  535. <INITIAL>{TABS_AND_SPACES}*{NEWLINE} {
  536. SCNG(lineno)++;
  537. return END_OF_LINE;
  538. }
  539. <INITIAL,ST_VALUE,ST_RAW>{TABS_AND_SPACES}*[;][^\r\n]*{NEWLINE} { /* Comment */
  540. BEGIN(INITIAL);
  541. SCNG(lineno)++;
  542. return END_OF_LINE;
  543. }
  544. <ST_VALUE,ST_RAW>[^] { /* End of option value (if EOF is reached before EOL */
  545. BEGIN(INITIAL);
  546. return END_OF_LINE;
  547. }
  548. <*>[^] {
  549. return 0;
  550. }
  551. */
  552. }