zend_ini_parser.y 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. %{
  2. /*
  3. +----------------------------------------------------------------------+
  4. | Zend Engine |
  5. +----------------------------------------------------------------------+
  6. | Copyright (c) 1998-2016 Zend Technologies Ltd. (http://www.zend.com) |
  7. +----------------------------------------------------------------------+
  8. | This source file is subject to version 2.00 of the Zend license, |
  9. | that is bundled with this package in the file LICENSE, and is |
  10. | available through the world-wide-web at the following url: |
  11. | http://www.zend.com/license/2_00.txt. |
  12. | If you did not receive a copy of the Zend license and are unable to |
  13. | obtain it through the world-wide-web, please send a note to |
  14. | license@zend.com so we can mail you a copy immediately. |
  15. +----------------------------------------------------------------------+
  16. | Authors: Zeev Suraski <zeev@zend.com> |
  17. | Jani Taskinen <jani@php.net> |
  18. +----------------------------------------------------------------------+
  19. */
  20. /* $Id$ */
  21. #define DEBUG_CFG_PARSER 0
  22. #include "zend.h"
  23. #include "zend_API.h"
  24. #include "zend_ini.h"
  25. #include "zend_constants.h"
  26. #include "zend_ini_scanner.h"
  27. #include "zend_extensions.h"
  28. #ifdef PHP_WIN32
  29. #include "win32/syslog.h"
  30. #endif
  31. #define YYERROR_VERBOSE
  32. #define YYSTYPE zval
  33. #ifdef ZTS
  34. #define YYPARSE_PARAM tsrm_ls
  35. #define YYLEX_PARAM tsrm_ls
  36. int ini_parse(void *arg);
  37. #else
  38. int ini_parse(void);
  39. #endif
  40. #define ZEND_INI_PARSER_CB (CG(ini_parser_param))->ini_parser_cb
  41. #define ZEND_INI_PARSER_ARG (CG(ini_parser_param))->arg
  42. /* {{{ zend_ini_do_op()
  43. */
  44. static void zend_ini_do_op(char type, zval *result, zval *op1, zval *op2)
  45. {
  46. int i_result;
  47. int i_op1, i_op2;
  48. char str_result[MAX_LENGTH_OF_LONG+1];
  49. i_op1 = atoi(Z_STRVAL_P(op1));
  50. free(Z_STRVAL_P(op1));
  51. if (op2) {
  52. i_op2 = atoi(Z_STRVAL_P(op2));
  53. free(Z_STRVAL_P(op2));
  54. } else {
  55. i_op2 = 0;
  56. }
  57. switch (type) {
  58. case '|':
  59. i_result = i_op1 | i_op2;
  60. break;
  61. case '&':
  62. i_result = i_op1 & i_op2;
  63. break;
  64. case '^':
  65. i_result = i_op1 ^ i_op2;
  66. break;
  67. case '~':
  68. i_result = ~i_op1;
  69. break;
  70. case '!':
  71. i_result = !i_op1;
  72. break;
  73. default:
  74. i_result = 0;
  75. break;
  76. }
  77. Z_STRLEN_P(result) = zend_sprintf(str_result, "%d", i_result);
  78. Z_STRVAL_P(result) = (char *) malloc(Z_STRLEN_P(result)+1);
  79. memcpy(Z_STRVAL_P(result), str_result, Z_STRLEN_P(result));
  80. Z_STRVAL_P(result)[Z_STRLEN_P(result)] = 0;
  81. Z_TYPE_P(result) = IS_STRING;
  82. }
  83. /* }}} */
  84. /* {{{ zend_ini_init_string()
  85. */
  86. static void zend_ini_init_string(zval *result)
  87. {
  88. Z_STRVAL_P(result) = malloc(1);
  89. Z_STRVAL_P(result)[0] = 0;
  90. Z_STRLEN_P(result) = 0;
  91. Z_TYPE_P(result) = IS_STRING;
  92. }
  93. /* }}} */
  94. /* {{{ zend_ini_add_string()
  95. */
  96. static void zend_ini_add_string(zval *result, zval *op1, zval *op2)
  97. {
  98. int length;
  99. if (Z_TYPE_P(op1) != IS_STRING) {
  100. zval copy;
  101. MAKE_COPY_ZVAL(&op1, &copy);
  102. convert_to_string(&copy);
  103. Z_STRVAL_P(op1) = zend_strndup(Z_STRVAL(copy), Z_STRLEN(copy));
  104. Z_STRLEN_P(op1) = Z_STRLEN(copy);
  105. zval_dtor(&copy);
  106. }
  107. length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
  108. Z_STRVAL_P(result) = (char *) realloc(Z_STRVAL_P(op1), length+1);
  109. memcpy(Z_STRVAL_P(result)+Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
  110. Z_STRVAL_P(result)[length] = 0;
  111. Z_STRLEN_P(result) = length;
  112. Z_TYPE_P(result) = IS_STRING;
  113. }
  114. /* }}} */
  115. /* {{{ zend_ini_get_constant()
  116. */
  117. static void zend_ini_get_constant(zval *result, zval *name TSRMLS_DC)
  118. {
  119. zval z_constant;
  120. /* If name contains ':' it is not a constant. Bug #26893. */
  121. if (!memchr(Z_STRVAL_P(name), ':', Z_STRLEN_P(name))
  122. && zend_get_constant(Z_STRVAL_P(name), Z_STRLEN_P(name), &z_constant TSRMLS_CC)) {
  123. /* z_constant is emalloc()'d */
  124. convert_to_string(&z_constant);
  125. Z_STRVAL_P(result) = zend_strndup(Z_STRVAL(z_constant), Z_STRLEN(z_constant));
  126. Z_STRLEN_P(result) = Z_STRLEN(z_constant);
  127. Z_TYPE_P(result) = Z_TYPE(z_constant);
  128. zval_dtor(&z_constant);
  129. free(Z_STRVAL_P(name));
  130. } else {
  131. *result = *name;
  132. }
  133. }
  134. /* }}} */
  135. /* {{{ zend_ini_get_var()
  136. */
  137. static void zend_ini_get_var(zval *result, zval *name TSRMLS_DC)
  138. {
  139. zval curval;
  140. char *envvar;
  141. /* Fetch configuration option value */
  142. if (zend_get_configuration_directive(Z_STRVAL_P(name), Z_STRLEN_P(name)+1, &curval) == SUCCESS) {
  143. Z_STRVAL_P(result) = zend_strndup(Z_STRVAL(curval), Z_STRLEN(curval));
  144. Z_STRLEN_P(result) = Z_STRLEN(curval);
  145. /* ..or if not found, try ENV */
  146. } else if ((envvar = zend_getenv(Z_STRVAL_P(name), Z_STRLEN_P(name) TSRMLS_CC)) != NULL ||
  147. (envvar = getenv(Z_STRVAL_P(name))) != NULL) {
  148. Z_STRVAL_P(result) = strdup(envvar);
  149. Z_STRLEN_P(result) = strlen(envvar);
  150. } else {
  151. zend_ini_init_string(result);
  152. }
  153. }
  154. /* }}} */
  155. /* {{{ ini_error()
  156. */
  157. static void ini_error(char *msg)
  158. {
  159. char *error_buf;
  160. int error_buf_len;
  161. char *currently_parsed_filename;
  162. TSRMLS_FETCH();
  163. currently_parsed_filename = zend_ini_scanner_get_filename(TSRMLS_C);
  164. if (currently_parsed_filename) {
  165. error_buf_len = 128 + strlen(msg) + strlen(currently_parsed_filename); /* should be more than enough */
  166. error_buf = (char *) emalloc(error_buf_len);
  167. sprintf(error_buf, "%s in %s on line %d\n", msg, currently_parsed_filename, zend_ini_scanner_get_lineno(TSRMLS_C));
  168. } else {
  169. error_buf = estrdup("Invalid configuration directive\n");
  170. }
  171. if (CG(ini_parser_unbuffered_errors)) {
  172. #ifdef PHP_WIN32
  173. syslog(LOG_ALERT, "PHP: %s (%s)", error_buf, GetCommandLine());
  174. #endif
  175. fprintf(stderr, "PHP: %s", error_buf);
  176. } else {
  177. zend_error(E_WARNING, "%s", error_buf);
  178. }
  179. efree(error_buf);
  180. }
  181. /* }}} */
  182. /* {{{ zend_parse_ini_file()
  183. */
  184. ZEND_API int zend_parse_ini_file(zend_file_handle *fh, zend_bool unbuffered_errors, int scanner_mode, zend_ini_parser_cb_t ini_parser_cb, void *arg TSRMLS_DC)
  185. {
  186. int retval;
  187. zend_ini_parser_param ini_parser_param;
  188. ini_parser_param.ini_parser_cb = ini_parser_cb;
  189. ini_parser_param.arg = arg;
  190. CG(ini_parser_param) = &ini_parser_param;
  191. if (zend_ini_open_file_for_scanning(fh, scanner_mode TSRMLS_CC) == FAILURE) {
  192. return FAILURE;
  193. }
  194. CG(ini_parser_unbuffered_errors) = unbuffered_errors;
  195. retval = ini_parse(TSRMLS_C);
  196. zend_file_handle_dtor(fh TSRMLS_CC);
  197. shutdown_ini_scanner(TSRMLS_C);
  198. if (retval == 0) {
  199. return SUCCESS;
  200. } else {
  201. return FAILURE;
  202. }
  203. }
  204. /* }}} */
  205. /* {{{ zend_parse_ini_string()
  206. */
  207. ZEND_API int zend_parse_ini_string(char *str, zend_bool unbuffered_errors, int scanner_mode, zend_ini_parser_cb_t ini_parser_cb, void *arg TSRMLS_DC)
  208. {
  209. int retval;
  210. zend_ini_parser_param ini_parser_param;
  211. ini_parser_param.ini_parser_cb = ini_parser_cb;
  212. ini_parser_param.arg = arg;
  213. CG(ini_parser_param) = &ini_parser_param;
  214. if (zend_ini_prepare_string_for_scanning(str, scanner_mode TSRMLS_CC) == FAILURE) {
  215. return FAILURE;
  216. }
  217. CG(ini_parser_unbuffered_errors) = unbuffered_errors;
  218. retval = ini_parse(TSRMLS_C);
  219. shutdown_ini_scanner(TSRMLS_C);
  220. if (retval == 0) {
  221. return SUCCESS;
  222. } else {
  223. return FAILURE;
  224. }
  225. }
  226. /* }}} */
  227. %}
  228. %expect 0
  229. %pure_parser
  230. %token TC_SECTION
  231. %token TC_RAW
  232. %token TC_CONSTANT
  233. %token TC_NUMBER
  234. %token TC_STRING
  235. %token TC_WHITESPACE
  236. %token TC_LABEL
  237. %token TC_OFFSET
  238. %token TC_DOLLAR_CURLY
  239. %token TC_VARNAME
  240. %token TC_QUOTED_STRING
  241. %token BOOL_TRUE
  242. %token BOOL_FALSE
  243. %token NULL_NULL
  244. %token END_OF_LINE
  245. %token '=' ':' ',' '.' '"' '\'' '^' '+' '-' '/' '*' '%' '$' '~' '<' '>' '?' '@' '{' '}'
  246. %left '|' '&' '^'
  247. %right '~' '!'
  248. %%
  249. statement_list:
  250. statement_list statement
  251. | /* empty */
  252. ;
  253. statement:
  254. TC_SECTION section_string_or_value ']' {
  255. #if DEBUG_CFG_PARSER
  256. printf("SECTION: [%s]\n", Z_STRVAL($2));
  257. #endif
  258. ZEND_INI_PARSER_CB(&$2, NULL, NULL, ZEND_INI_PARSER_SECTION, ZEND_INI_PARSER_ARG TSRMLS_CC);
  259. free(Z_STRVAL($2));
  260. }
  261. | TC_LABEL '=' string_or_value {
  262. #if DEBUG_CFG_PARSER
  263. printf("NORMAL: '%s' = '%s'\n", Z_STRVAL($1), Z_STRVAL($3));
  264. #endif
  265. ZEND_INI_PARSER_CB(&$1, &$3, NULL, ZEND_INI_PARSER_ENTRY, ZEND_INI_PARSER_ARG TSRMLS_CC);
  266. free(Z_STRVAL($1));
  267. zval_internal_dtor(&$3);
  268. }
  269. | TC_OFFSET option_offset ']' '=' string_or_value {
  270. #if DEBUG_CFG_PARSER
  271. printf("OFFSET: '%s'[%s] = '%s'\n", Z_STRVAL($1), Z_STRVAL($2), Z_STRVAL($5));
  272. #endif
  273. ZEND_INI_PARSER_CB(&$1, &$5, &$2, ZEND_INI_PARSER_POP_ENTRY, ZEND_INI_PARSER_ARG TSRMLS_CC);
  274. free(Z_STRVAL($1));
  275. if (Z_TYPE($2) == IS_STRING) {
  276. free(Z_STRVAL($2));
  277. } else {
  278. zval_dtor(&$2);
  279. }
  280. zval_internal_dtor(&$5);
  281. }
  282. | TC_LABEL { ZEND_INI_PARSER_CB(&$1, NULL, NULL, ZEND_INI_PARSER_ENTRY, ZEND_INI_PARSER_ARG TSRMLS_CC); free(Z_STRVAL($1)); }
  283. | END_OF_LINE
  284. ;
  285. section_string_or_value:
  286. var_string_list_section { $$ = $1; }
  287. | /* empty */ { zend_ini_init_string(&$$); }
  288. ;
  289. string_or_value:
  290. expr { $$ = $1; }
  291. | BOOL_TRUE { $$ = $1; }
  292. | BOOL_FALSE { $$ = $1; }
  293. | NULL_NULL { $$ = $1; }
  294. | END_OF_LINE { zend_ini_init_string(&$$); }
  295. ;
  296. option_offset:
  297. var_string_list { $$ = $1; }
  298. | /* empty */ { zend_ini_init_string(&$$); }
  299. ;
  300. encapsed_list:
  301. encapsed_list cfg_var_ref { zend_ini_add_string(&$$, &$1, &$2); free(Z_STRVAL($2)); }
  302. | encapsed_list TC_QUOTED_STRING { zend_ini_add_string(&$$, &$1, &$2); free(Z_STRVAL($2)); }
  303. | /* empty */ { zend_ini_init_string(&$$); }
  304. ;
  305. var_string_list_section:
  306. cfg_var_ref { $$ = $1; }
  307. | constant_literal { $$ = $1; }
  308. | '"' encapsed_list '"' { $$ = $2; }
  309. | var_string_list_section cfg_var_ref { zend_ini_add_string(&$$, &$1, &$2); free(Z_STRVAL($2)); }
  310. | var_string_list_section constant_literal { zend_ini_add_string(&$$, &$1, &$2); free(Z_STRVAL($2)); }
  311. | var_string_list_section '"' encapsed_list '"' { zend_ini_add_string(&$$, &$1, &$3); free(Z_STRVAL($3)); }
  312. ;
  313. var_string_list:
  314. cfg_var_ref { $$ = $1; }
  315. | constant_string { $$ = $1; }
  316. | '"' encapsed_list '"' { $$ = $2; }
  317. | var_string_list cfg_var_ref { zend_ini_add_string(&$$, &$1, &$2); free(Z_STRVAL($2)); }
  318. | var_string_list constant_string { zend_ini_add_string(&$$, &$1, &$2); free(Z_STRVAL($2)); }
  319. | var_string_list '"' encapsed_list '"' { zend_ini_add_string(&$$, &$1, &$3); free(Z_STRVAL($3)); }
  320. ;
  321. expr:
  322. var_string_list { $$ = $1; }
  323. | expr '|' expr { zend_ini_do_op('|', &$$, &$1, &$3); }
  324. | expr '&' expr { zend_ini_do_op('&', &$$, &$1, &$3); }
  325. | expr '^' expr { zend_ini_do_op('^', &$$, &$1, &$3); }
  326. | '~' expr { zend_ini_do_op('~', &$$, &$2, NULL); }
  327. | '!' expr { zend_ini_do_op('!', &$$, &$2, NULL); }
  328. | '(' expr ')' { $$ = $2; }
  329. ;
  330. cfg_var_ref:
  331. TC_DOLLAR_CURLY TC_VARNAME '}' { zend_ini_get_var(&$$, &$2 TSRMLS_CC); free(Z_STRVAL($2)); }
  332. ;
  333. constant_literal:
  334. TC_CONSTANT { $$ = $1; }
  335. | TC_RAW { $$ = $1; /*printf("TC_RAW: '%s'\n", Z_STRVAL($1));*/ }
  336. | TC_NUMBER { $$ = $1; /*printf("TC_NUMBER: '%s'\n", Z_STRVAL($1));*/ }
  337. | TC_STRING { $$ = $1; /*printf("TC_STRING: '%s'\n", Z_STRVAL($1));*/ }
  338. | TC_WHITESPACE { $$ = $1; /*printf("TC_WHITESPACE: '%s'\n", Z_STRVAL($1));*/ }
  339. ;
  340. constant_string:
  341. TC_CONSTANT { zend_ini_get_constant(&$$, &$1 TSRMLS_CC); }
  342. | TC_RAW { $$ = $1; /*printf("TC_RAW: '%s'\n", Z_STRVAL($1));*/ }
  343. | TC_NUMBER { $$ = $1; /*printf("TC_NUMBER: '%s'\n", Z_STRVAL($1));*/ }
  344. | TC_STRING { $$ = $1; /*printf("TC_STRING: '%s'\n", Z_STRVAL($1));*/ }
  345. | TC_WHITESPACE { $$ = $1; /*printf("TC_WHITESPACE: '%s'\n", Z_STRVAL($1));*/ }
  346. ;
  347. /*
  348. * Local variables:
  349. * tab-width: 4
  350. * c-basic-offset: 4
  351. * indent-tabs-mode: t
  352. * End:
  353. */