PageRenderTime 43ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/Zend/zend_ini_scanner.l

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