1 %{
2 /*
3 +----------------------------------------------------------------------+
4 | Zend Engine |
5 +----------------------------------------------------------------------+
6 | Copyright (c) 1998-2014 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
21 /* $Id$ */
22
23 #define DEBUG_CFG_PARSER 0
24
25 #include "zend.h"
26 #include "zend_API.h"
27 #include "zend_ini.h"
28 #include "zend_constants.h"
29 #include "zend_ini_scanner.h"
30 #include "zend_extensions.h"
31
32 #define YYERROR_VERBOSE
33 #define YYSTYPE zval
34
35 #ifdef ZTS
36 #define YYPARSE_PARAM tsrm_ls
37 #define YYLEX_PARAM tsrm_ls
38 int ini_parse(void *arg);
39 #else
40 int ini_parse(void);
41 #endif
42
43 #define ZEND_INI_PARSER_CB (CG(ini_parser_param))->ini_parser_cb
44 #define ZEND_INI_PARSER_ARG (CG(ini_parser_param))->arg
45
46 /* {{{ zend_ini_do_op()
47 */
zend_ini_do_op(char type,zval * result,zval * op1,zval * op2)48 static void zend_ini_do_op(char type, zval *result, zval *op1, zval *op2)
49 {
50 int i_result;
51 int i_op1, i_op2;
52 char str_result[MAX_LENGTH_OF_LONG];
53
54 i_op1 = atoi(Z_STRVAL_P(op1));
55 free(Z_STRVAL_P(op1));
56 if (op2) {
57 i_op2 = atoi(Z_STRVAL_P(op2));
58 free(Z_STRVAL_P(op2));
59 } else {
60 i_op2 = 0;
61 }
62
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;
72 break;
73 case '!':
74 i_result = !i_op1;
75 break;
76 default:
77 i_result = 0;
78 break;
79 }
80
81 Z_STRLEN_P(result) = zend_sprintf(str_result, "%d", i_result);
82 Z_STRVAL_P(result) = (char *) malloc(Z_STRLEN_P(result)+1);
83 memcpy(Z_STRVAL_P(result), str_result, Z_STRLEN_P(result));
84 Z_STRVAL_P(result)[Z_STRLEN_P(result)] = 0;
85 Z_TYPE_P(result) = IS_STRING;
86 }
87 /* }}} */
88
89 /* {{{ zend_ini_init_string()
90 */
zend_ini_init_string(zval * result)91 static void zend_ini_init_string(zval *result)
92 {
93 Z_STRVAL_P(result) = malloc(1);
94 Z_STRVAL_P(result)[0] = 0;
95 Z_STRLEN_P(result) = 0;
96 Z_TYPE_P(result) = IS_STRING;
97 }
98 /* }}} */
99
100 /* {{{ zend_ini_add_string()
101 */
zend_ini_add_string(zval * result,zval * op1,zval * op2)102 static void zend_ini_add_string(zval *result, zval *op1, zval *op2)
103 {
104 int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
105
106 Z_STRVAL_P(result) = (char *) realloc(Z_STRVAL_P(op1), length+1);
107 memcpy(Z_STRVAL_P(result)+Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
108 Z_STRVAL_P(result)[length] = 0;
109 Z_STRLEN_P(result) = length;
110 Z_TYPE_P(result) = IS_STRING;
111 }
112 /* }}} */
113
114 /* {{{ zend_ini_get_constant()
115 */
zend_ini_get_constant(zval * result,zval * name TSRMLS_DC)116 static void zend_ini_get_constant(zval *result, zval *name TSRMLS_DC)
117 {
118 zval z_constant;
119
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
136 /* {{{ zend_ini_get_var()
137 */
zend_ini_get_var(zval * result,zval * name TSRMLS_DC)138 static void zend_ini_get_var(zval *result, zval *name TSRMLS_DC)
139 {
140 zval curval;
141 char *envvar;
142
143 /* Fetch configuration option value */
144 if (zend_get_configuration_directive(Z_STRVAL_P(name), Z_STRLEN_P(name)+1, &curval) == SUCCESS) {
145 Z_STRVAL_P(result) = zend_strndup(Z_STRVAL(curval), Z_STRLEN(curval));
146 Z_STRLEN_P(result) = Z_STRLEN(curval);
147 /* ..or if not found, try ENV */
148 } else if ((envvar = zend_getenv(Z_STRVAL_P(name), Z_STRLEN_P(name) TSRMLS_CC)) != NULL ||
149 (envvar = getenv(Z_STRVAL_P(name))) != NULL) {
150 Z_STRVAL_P(result) = strdup(envvar);
151 Z_STRLEN_P(result) = strlen(envvar);
152 } else {
153 zend_ini_init_string(result);
154 }
155 }
156 /* }}} */
157
158 /* {{{ ini_error()
159 */
ini_error(char * msg)160 static void ini_error(char *msg)
161 {
162 char *error_buf;
163 int error_buf_len;
164 char *currently_parsed_filename;
165 TSRMLS_FETCH();
166
167 currently_parsed_filename = zend_ini_scanner_get_filename(TSRMLS_C);
168 if (currently_parsed_filename) {
169 error_buf_len = 128 + strlen(msg) + strlen(currently_parsed_filename); /* should be more than enough */
170 error_buf = (char *) emalloc(error_buf_len);
171
172 sprintf(error_buf, "%s in %s on line %d\n", msg, currently_parsed_filename, zend_ini_scanner_get_lineno(TSRMLS_C));
173 } else {
174 error_buf = estrdup("Invalid configuration directive\n");
175 }
176
177 if (CG(ini_parser_unbuffered_errors)) {
178 #ifdef PHP_WIN32
179 MessageBox(NULL, error_buf, "PHP Error", MB_OK|MB_TOPMOST|0x00200000L);
180 #else
181 fprintf(stderr, "PHP: %s", error_buf);
182 #endif
183 } else {
184 zend_error(E_WARNING, "%s", error_buf);
185 }
186 efree(error_buf);
187 }
188 /* }}} */
189
190 /* {{{ zend_parse_ini_file()
191 */
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)192 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)
193 {
194 int retval;
195 zend_ini_parser_param ini_parser_param;
196
197 ini_parser_param.ini_parser_cb = ini_parser_cb;
198 ini_parser_param.arg = arg;
199 CG(ini_parser_param) = &ini_parser_param;
200
201 if (zend_ini_open_file_for_scanning(fh, scanner_mode TSRMLS_CC) == FAILURE) {
202 return FAILURE;
203 }
204
205 CG(ini_parser_unbuffered_errors) = unbuffered_errors;
206 retval = ini_parse(TSRMLS_C);
207 zend_file_handle_dtor(fh TSRMLS_CC);
208
209 shutdown_ini_scanner(TSRMLS_C);
210
211 if (retval == 0) {
212 return SUCCESS;
213 } else {
214 return FAILURE;
215 }
216 }
217 /* }}} */
218
219 /* {{{ zend_parse_ini_string()
220 */
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)221 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)
222 {
223 int retval;
224 zend_ini_parser_param ini_parser_param;
225
226 ini_parser_param.ini_parser_cb = ini_parser_cb;
227 ini_parser_param.arg = arg;
228 CG(ini_parser_param) = &ini_parser_param;
229
230 if (zend_ini_prepare_string_for_scanning(str, scanner_mode TSRMLS_CC) == FAILURE) {
231 return FAILURE;
232 }
233
234 CG(ini_parser_unbuffered_errors) = unbuffered_errors;
235 retval = ini_parse(TSRMLS_C);
236
237 shutdown_ini_scanner(TSRMLS_C);
238
239 if (retval == 0) {
240 return SUCCESS;
241 } else {
242 return FAILURE;
243 }
244 }
245 /* }}} */
246
247 %}
248
249 %expect 0
250 %pure_parser
251
252 %token TC_SECTION
253 %token TC_RAW
254 %token TC_CONSTANT
255 %token TC_NUMBER
256 %token TC_STRING
257 %token TC_WHITESPACE
258 %token TC_LABEL
259 %token TC_OFFSET
260 %token TC_DOLLAR_CURLY
261 %token TC_VARNAME
262 %token TC_QUOTED_STRING
263 %token BOOL_TRUE
264 %token BOOL_FALSE
265 %token END_OF_LINE
266 %token '=' ':' ',' '.' '"' '\'' '^' '+' '-' '/' '*' '%' '$' '~' '<' '>' '?' '@' '{' '}'
267 %left '|' '&'
268 %right '~' '!'
269
270 %%
271
272 statement_list:
273 statement_list statement
274 | /* empty */
275 ;
276
277 statement:
278 TC_SECTION section_string_or_value ']' {
279 #if DEBUG_CFG_PARSER
280 printf("SECTION: [%s]\n", Z_STRVAL($2));
281 #endif
282 ZEND_INI_PARSER_CB(&$2, NULL, NULL, ZEND_INI_PARSER_SECTION, ZEND_INI_PARSER_ARG TSRMLS_CC);
283 free(Z_STRVAL($2));
284 }
285 | TC_LABEL '=' string_or_value {
286 #if DEBUG_CFG_PARSER
287 printf("NORMAL: '%s' = '%s'\n", Z_STRVAL($1), Z_STRVAL($3));
288 #endif
289 ZEND_INI_PARSER_CB(&$1, &$3, NULL, ZEND_INI_PARSER_ENTRY, ZEND_INI_PARSER_ARG TSRMLS_CC);
290 free(Z_STRVAL($1));
291 free(Z_STRVAL($3));
292 }
293 | TC_OFFSET option_offset ']' '=' string_or_value {
294 #if DEBUG_CFG_PARSER
295 printf("OFFSET: '%s'[%s] = '%s'\n", Z_STRVAL($1), Z_STRVAL($2), Z_STRVAL($5));
296 #endif
297 ZEND_INI_PARSER_CB(&$1, &$5, &$2, ZEND_INI_PARSER_POP_ENTRY, ZEND_INI_PARSER_ARG TSRMLS_CC);
298 free(Z_STRVAL($1));
299 free(Z_STRVAL($2));
300 free(Z_STRVAL($5));
301 }
302 | TC_LABEL { ZEND_INI_PARSER_CB(&$1, NULL, NULL, ZEND_INI_PARSER_ENTRY, ZEND_INI_PARSER_ARG TSRMLS_CC); free(Z_STRVAL($1)); }
303 | END_OF_LINE
304 ;
305
306 section_string_or_value:
307 var_string_list_section { $$ = $1; }
308 | /* empty */ { zend_ini_init_string(&$$); }
309 ;
310
311 string_or_value:
312 expr { $$ = $1; }
313 | BOOL_TRUE { $$ = $1; }
314 | BOOL_FALSE { $$ = $1; }
315 | END_OF_LINE { zend_ini_init_string(&$$); }
316 ;
317
318 option_offset:
319 var_string_list { $$ = $1; }
320 | /* empty */ { zend_ini_init_string(&$$); }
321 ;
322
323 encapsed_list:
324 encapsed_list cfg_var_ref { zend_ini_add_string(&$$, &$1, &$2); free(Z_STRVAL($2)); }
325 | encapsed_list TC_QUOTED_STRING { zend_ini_add_string(&$$, &$1, &$2); free(Z_STRVAL($2)); }
326 | /* empty */ { zend_ini_init_string(&$$); }
327 ;
328
329 var_string_list_section:
330 cfg_var_ref { $$ = $1; }
331 | constant_literal { $$ = $1; }
332 | '"' encapsed_list '"' { $$ = $2; }
333 | var_string_list_section cfg_var_ref { zend_ini_add_string(&$$, &$1, &$2); free(Z_STRVAL($2)); }
334 | var_string_list_section constant_literal { zend_ini_add_string(&$$, &$1, &$2); free(Z_STRVAL($2)); }
335 | var_string_list_section '"' encapsed_list '"' { zend_ini_add_string(&$$, &$1, &$3); free(Z_STRVAL($3)); }
336 ;
337
338 var_string_list:
339 cfg_var_ref { $$ = $1; }
340 | constant_string { $$ = $1; }
341 | '"' encapsed_list '"' { $$ = $2; }
342 | var_string_list cfg_var_ref { zend_ini_add_string(&$$, &$1, &$2); free(Z_STRVAL($2)); }
343 | var_string_list constant_string { zend_ini_add_string(&$$, &$1, &$2); free(Z_STRVAL($2)); }
344 | var_string_list '"' encapsed_list '"' { zend_ini_add_string(&$$, &$1, &$3); free(Z_STRVAL($3)); }
345 ;
346
347 expr:
348 var_string_list { $$ = $1; }
349 | expr '|' expr { zend_ini_do_op('|', &$$, &$1, &$3); }
350 | expr '&' expr { zend_ini_do_op('&', &$$, &$1, &$3); }
351 | '~' expr { zend_ini_do_op('~', &$$, &$2, NULL); }
352 | '!' expr { zend_ini_do_op('!', &$$, &$2, NULL); }
353 | '(' expr ')' { $$ = $2; }
354 ;
355
356 cfg_var_ref:
357 TC_DOLLAR_CURLY TC_VARNAME '}' { zend_ini_get_var(&$$, &$2 TSRMLS_CC); free(Z_STRVAL($2)); }
358 ;
359
360 constant_literal:
361 TC_CONSTANT { $$ = $1; }
362 | TC_RAW { $$ = $1; /*printf("TC_RAW: '%s'\n", Z_STRVAL($1));*/ }
363 | TC_NUMBER { $$ = $1; /*printf("TC_NUMBER: '%s'\n", Z_STRVAL($1));*/ }
364 | TC_STRING { $$ = $1; /*printf("TC_STRING: '%s'\n", Z_STRVAL($1));*/ }
365 | TC_WHITESPACE { $$ = $1; /*printf("TC_WHITESPACE: '%s'\n", Z_STRVAL($1));*/ }
366 ;
367
368 constant_string:
369 TC_CONSTANT { zend_ini_get_constant(&$$, &$1 TSRMLS_CC); }
370 | TC_RAW { $$ = $1; /*printf("TC_RAW: '%s'\n", Z_STRVAL($1));*/ }
371 | TC_NUMBER { $$ = $1; /*printf("TC_NUMBER: '%s'\n", Z_STRVAL($1));*/ }
372 | TC_STRING { $$ = $1; /*printf("TC_STRING: '%s'\n", Z_STRVAL($1));*/ }
373 | TC_WHITESPACE { $$ = $1; /*printf("TC_WHITESPACE: '%s'\n", Z_STRVAL($1));*/ }
374 ;
375
376 /*
377 * Local variables:
378 * tab-width: 4
379 * c-basic-offset: 4
380 * indent-tabs-mode: t
381 * End:
382 */
383