zend_ini_parser.y 12 KB

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