xref: /PHP-8.1/Zend/zend_ini.c (revision 0217be4d)
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    | Author: Zeev Suraski <zeev@php.net>                                  |
16    +----------------------------------------------------------------------+
17 */
18 
19 #include "zend.h"
20 #include "zend_sort.h"
21 #include "zend_API.h"
22 #include "zend_ini.h"
23 #include "zend_alloc.h"
24 #include "zend_operators.h"
25 #include "zend_strtod.h"
26 #include "zend_modules.h"
27 
28 static HashTable *registered_zend_ini_directives;
29 
30 #define NO_VALUE_PLAINTEXT		"no value"
31 #define NO_VALUE_HTML			"<i>no value</i>"
32 
33 /*
34  * hash_apply functions
35  */
zend_remove_ini_entries(zval * el,void * arg)36 static int zend_remove_ini_entries(zval *el, void *arg) /* {{{ */
37 {
38 	zend_ini_entry *ini_entry = (zend_ini_entry *)Z_PTR_P(el);
39 	int module_number = *(int *)arg;
40 
41 	return ini_entry->module_number == module_number;
42 }
43 /* }}} */
44 
zend_restore_ini_entry_cb(zend_ini_entry * ini_entry,int stage)45 static zend_result zend_restore_ini_entry_cb(zend_ini_entry *ini_entry, int stage) /* {{{ */
46 {
47 	zend_result result = FAILURE;
48 
49 	if (ini_entry->modified) {
50 		if (ini_entry->on_modify) {
51 			zend_try {
52 			/* even if on_modify bails out, we have to continue on with restoring,
53 				since there can be allocated variables that would be freed on MM shutdown
54 				and would lead to memory corruption later ini entry is modified again */
55 				result = ini_entry->on_modify(ini_entry, ini_entry->orig_value, ini_entry->mh_arg1, ini_entry->mh_arg2, ini_entry->mh_arg3, stage);
56 			} zend_end_try();
57 		}
58 		if (stage == ZEND_INI_STAGE_RUNTIME && result == FAILURE) {
59 			/* runtime failure is OK */
60 			return FAILURE;
61 		}
62 		if (ini_entry->value != ini_entry->orig_value) {
63 			zend_string_release(ini_entry->value);
64 		}
65 		ini_entry->value = ini_entry->orig_value;
66 		ini_entry->modifiable = ini_entry->orig_modifiable;
67 		ini_entry->modified = 0;
68 		ini_entry->orig_value = NULL;
69 		ini_entry->orig_modifiable = 0;
70 	}
71 	return SUCCESS;
72 }
73 /* }}} */
74 
free_ini_entry(zval * zv)75 static void free_ini_entry(zval *zv) /* {{{ */
76 {
77 	zend_ini_entry *entry = (zend_ini_entry*)Z_PTR_P(zv);
78 
79 	zend_string_release_ex(entry->name, 1);
80 	if (entry->value) {
81 		zend_string_release(entry->value);
82 	}
83 	if (entry->orig_value) {
84 		zend_string_release_ex(entry->orig_value, 1);
85 	}
86 	free(entry);
87 }
88 /* }}} */
89 
90 /*
91  * Startup / shutdown
92  */
zend_ini_startup(void)93 ZEND_API void zend_ini_startup(void) /* {{{ */
94 {
95 	registered_zend_ini_directives = (HashTable *) malloc(sizeof(HashTable));
96 
97 	EG(ini_directives) = registered_zend_ini_directives;
98 	EG(modified_ini_directives) = NULL;
99 	EG(error_reporting_ini_entry) = NULL;
100 	zend_hash_init(registered_zend_ini_directives, 128, NULL, free_ini_entry, 1);
101 }
102 /* }}} */
103 
zend_ini_shutdown(void)104 ZEND_API void zend_ini_shutdown(void) /* {{{ */
105 {
106 	zend_ini_dtor(EG(ini_directives));
107 }
108 /* }}} */
109 
zend_ini_dtor(HashTable * ini_directives)110 ZEND_API void zend_ini_dtor(HashTable *ini_directives) /* {{{ */
111 {
112 	zend_hash_destroy(ini_directives);
113 	free(ini_directives);
114 }
115 /* }}} */
116 
zend_ini_global_shutdown(void)117 ZEND_API void zend_ini_global_shutdown(void) /* {{{ */
118 {
119 	zend_hash_destroy(registered_zend_ini_directives);
120 	free(registered_zend_ini_directives);
121 }
122 /* }}} */
123 
zend_ini_deactivate(void)124 ZEND_API void zend_ini_deactivate(void) /* {{{ */
125 {
126 	if (EG(modified_ini_directives)) {
127 		zend_ini_entry *ini_entry;
128 
129 		ZEND_HASH_FOREACH_PTR(EG(modified_ini_directives), ini_entry) {
130 			zend_restore_ini_entry_cb(ini_entry, ZEND_INI_STAGE_DEACTIVATE);
131 		} ZEND_HASH_FOREACH_END();
132 		zend_hash_destroy(EG(modified_ini_directives));
133 		FREE_HASHTABLE(EG(modified_ini_directives));
134 		EG(modified_ini_directives) = NULL;
135 	}
136 }
137 /* }}} */
138 
139 #ifdef ZTS
copy_ini_entry(zval * zv)140 static void copy_ini_entry(zval *zv) /* {{{ */
141 {
142 	zend_ini_entry *old_entry = (zend_ini_entry*)Z_PTR_P(zv);
143 	zend_ini_entry *new_entry = pemalloc(sizeof(zend_ini_entry), 1);
144 
145 	Z_PTR_P(zv) = new_entry;
146 	memcpy(new_entry, old_entry, sizeof(zend_ini_entry));
147 	if (old_entry->name) {
148 		new_entry->name = zend_string_dup(old_entry->name, 1);
149 	}
150 	if (old_entry->value) {
151 		new_entry->value = zend_string_dup(old_entry->value, 1);
152 	}
153 	if (old_entry->orig_value) {
154 		new_entry->orig_value = zend_string_dup(old_entry->orig_value, 1);
155 	}
156 }
157 /* }}} */
158 
zend_copy_ini_directives(void)159 ZEND_API void zend_copy_ini_directives(void) /* {{{ */
160 {
161 	EG(modified_ini_directives) = NULL;
162 	EG(error_reporting_ini_entry) = NULL;
163 	EG(ini_directives) = (HashTable *) malloc(sizeof(HashTable));
164 	zend_hash_init(EG(ini_directives), registered_zend_ini_directives->nNumOfElements, NULL, free_ini_entry, 1);
165 	zend_hash_copy(EG(ini_directives), registered_zend_ini_directives, copy_ini_entry);
166 }
167 /* }}} */
168 #endif
169 
ini_key_compare(Bucket * f,Bucket * s)170 static int ini_key_compare(Bucket *f, Bucket *s) /* {{{ */
171 {
172 	if (!f->key && !s->key) { /* both numeric */
173 		if (f->h > s->h) {
174 			return -1;
175 		} else if (f->h < s->h) {
176 			return 1;
177 		}
178 		return 0;
179 	} else if (!f->key) { /* f is numeric, s is not */
180 		return -1;
181 	} else if (!s->key) { /* s is numeric, f is not */
182 		return 1;
183 	} else { /* both strings */
184 		return zend_binary_strcasecmp(ZSTR_VAL(f->key), ZSTR_LEN(f->key), ZSTR_VAL(s->key), ZSTR_LEN(s->key));
185 	}
186 }
187 /* }}} */
188 
zend_ini_sort_entries(void)189 ZEND_API void zend_ini_sort_entries(void) /* {{{ */
190 {
191 	zend_hash_sort(EG(ini_directives), ini_key_compare, 0);
192 }
193 /* }}} */
194 
195 /*
196  * Registration / unregistration
197  */
zend_register_ini_entries_ex(const zend_ini_entry_def * ini_entry,int module_number,int module_type)198 ZEND_API zend_result zend_register_ini_entries_ex(const zend_ini_entry_def *ini_entry, int module_number, int module_type) /* {{{ */
199 {
200 	zend_ini_entry *p;
201 	zval *default_value;
202 	HashTable *directives = registered_zend_ini_directives;
203 
204 #ifdef ZTS
205 	/* if we are called during the request, eg: from dl(),
206 	 * then we should not touch the global directives table,
207 	 * and should update the per-(request|thread) version instead.
208 	 * This solves two problems: one is that ini entries for dl()'d
209 	 * extensions will now work, and the second is that updating the
210 	 * global hash here from dl() is not mutex protected and can
211 	 * lead to death.
212 	 */
213 	if (directives != EG(ini_directives)) {
214 		directives = EG(ini_directives);
215 	} else {
216 		ZEND_ASSERT(module_type == MODULE_PERSISTENT);
217 	}
218 #endif
219 
220 	while (ini_entry->name) {
221 		p = pemalloc(sizeof(zend_ini_entry), 1);
222 		p->name = zend_string_init_interned(ini_entry->name, ini_entry->name_length, 1);
223 		p->on_modify = ini_entry->on_modify;
224 		p->mh_arg1 = ini_entry->mh_arg1;
225 		p->mh_arg2 = ini_entry->mh_arg2;
226 		p->mh_arg3 = ini_entry->mh_arg3;
227 		p->value = NULL;
228 		p->orig_value = NULL;
229 		p->displayer = ini_entry->displayer;
230 		p->modifiable = ini_entry->modifiable;
231 
232 		p->orig_modifiable = 0;
233 		p->modified = 0;
234 		p->module_number = module_number;
235 
236 		if (zend_hash_add_ptr(directives, p->name, (void*)p) == NULL) {
237 			if (p->name) {
238 				zend_string_release_ex(p->name, 1);
239 			}
240 			zend_unregister_ini_entries_ex(module_number, module_type);
241 			return FAILURE;
242 		}
243 		if (((default_value = zend_get_configuration_directive(p->name)) != NULL) &&
244 		    (!p->on_modify || p->on_modify(p, Z_STR_P(default_value), p->mh_arg1, p->mh_arg2, p->mh_arg3, ZEND_INI_STAGE_STARTUP) == SUCCESS)) {
245 
246 			p->value = zend_new_interned_string(zend_string_copy(Z_STR_P(default_value)));
247 		} else {
248 			p->value = ini_entry->value ?
249 				zend_string_init_interned(ini_entry->value, ini_entry->value_length, 1) : NULL;
250 
251 			if (p->on_modify) {
252 				p->on_modify(p, p->value, p->mh_arg1, p->mh_arg2, p->mh_arg3, ZEND_INI_STAGE_STARTUP);
253 			}
254 		}
255 		ini_entry++;
256 	}
257 	return SUCCESS;
258 }
259 /* }}} */
260 
zend_register_ini_entries(const zend_ini_entry_def * ini_entry,int module_number)261 ZEND_API zend_result zend_register_ini_entries(const zend_ini_entry_def *ini_entry, int module_number) /* {{{ */
262 {
263 	zend_module_entry *module;
264 
265 	/* Module is likely to be the last one in the list */
266 	ZEND_HASH_REVERSE_FOREACH_PTR(&module_registry, module) {
267 		if (module->module_number == module_number) {
268 			return zend_register_ini_entries_ex(ini_entry, module_number, module->type);
269 		}
270 	} ZEND_HASH_FOREACH_END();
271 
272 	return FAILURE;
273 }
274 /* }}} */
275 
zend_unregister_ini_entries_ex(int module_number,int module_type)276 ZEND_API void zend_unregister_ini_entries_ex(int module_number, int module_type) /* {{{ */
277 {
278 	static HashTable *ini_directives;
279 
280 	if (module_type == MODULE_TEMPORARY) {
281 		ini_directives = EG(ini_directives);
282 	} else {
283 		ini_directives = registered_zend_ini_directives;
284 	}
285 
286 	zend_hash_apply_with_argument(ini_directives, zend_remove_ini_entries, (void *) &module_number);
287 }
288 /* }}} */
289 
zend_unregister_ini_entries(int module_number)290 ZEND_API void zend_unregister_ini_entries(int module_number) /* {{{ */
291 {
292 	zend_module_entry *module;
293 
294 	/* Module is likely to be the last one in the list */
295 	ZEND_HASH_REVERSE_FOREACH_PTR(&module_registry, module) {
296 		if (module->module_number == module_number) {
297 			zend_unregister_ini_entries_ex(module_number, module->type);
298 			return;
299 		}
300 	} ZEND_HASH_FOREACH_END();
301 }
302 /* }}} */
303 
304 #ifdef ZTS
zend_ini_refresh_caches(int stage)305 ZEND_API void zend_ini_refresh_caches(int stage) /* {{{ */
306 {
307 	zend_ini_entry *p;
308 
309 	ZEND_HASH_FOREACH_PTR(EG(ini_directives), p) {
310 		if (p->on_modify) {
311 			p->on_modify(p, p->value, p->mh_arg1, p->mh_arg2, p->mh_arg3, stage);
312 		}
313 	} ZEND_HASH_FOREACH_END();
314 }
315 /* }}} */
316 #endif
317 
zend_alter_ini_entry(zend_string * name,zend_string * new_value,int modify_type,int stage)318 ZEND_API zend_result zend_alter_ini_entry(zend_string *name, zend_string *new_value, int modify_type, int stage) /* {{{ */
319 {
320 
321 	return zend_alter_ini_entry_ex(name, new_value, modify_type, stage, 0);
322 }
323 /* }}} */
324 
zend_alter_ini_entry_chars(zend_string * name,const char * value,size_t value_length,int modify_type,int stage)325 ZEND_API zend_result zend_alter_ini_entry_chars(zend_string *name, const char *value, size_t value_length, int modify_type, int stage) /* {{{ */
326 {
327 	zend_result ret;
328 	zend_string *new_value;
329 
330 	new_value = zend_string_init(value, value_length, !(stage & ZEND_INI_STAGE_IN_REQUEST));
331 	ret = zend_alter_ini_entry_ex(name, new_value, modify_type, stage, 0);
332 	zend_string_release(new_value);
333 	return ret;
334 }
335 /* }}} */
336 
zend_alter_ini_entry_chars_ex(zend_string * name,const char * value,size_t value_length,int modify_type,int stage,int force_change)337 ZEND_API zend_result zend_alter_ini_entry_chars_ex(zend_string *name, const char *value, size_t value_length, int modify_type, int stage, int force_change) /* {{{ */
338 {
339 	zend_result ret;
340 	zend_string *new_value;
341 
342 	new_value = zend_string_init(value, value_length, !(stage & ZEND_INI_STAGE_IN_REQUEST));
343 	ret = zend_alter_ini_entry_ex(name, new_value, modify_type, stage, force_change);
344 	zend_string_release(new_value);
345 	return ret;
346 }
347 /* }}} */
348 
zend_alter_ini_entry_ex(zend_string * name,zend_string * new_value,int modify_type,int stage,bool force_change)349 ZEND_API zend_result zend_alter_ini_entry_ex(zend_string *name, zend_string *new_value, int modify_type, int stage, bool force_change) /* {{{ */
350 {
351 	zend_ini_entry *ini_entry;
352 	zend_string *duplicate;
353 	uint8_t modifiable;
354 	bool modified;
355 
356 	if ((ini_entry = zend_hash_find_ptr(EG(ini_directives), name)) == NULL) {
357 		return FAILURE;
358 	}
359 
360 	modifiable = ini_entry->modifiable;
361 	modified = ini_entry->modified;
362 
363 	if (stage == ZEND_INI_STAGE_ACTIVATE && modify_type == ZEND_INI_SYSTEM) {
364 		ini_entry->modifiable = ZEND_INI_SYSTEM;
365 	}
366 
367 	if (!force_change) {
368 		if (!(ini_entry->modifiable & modify_type)) {
369 			return FAILURE;
370 		}
371 	}
372 
373 	if (!EG(modified_ini_directives)) {
374 		ALLOC_HASHTABLE(EG(modified_ini_directives));
375 		zend_hash_init(EG(modified_ini_directives), 8, NULL, NULL, 0);
376 	}
377 	if (!modified) {
378 		ini_entry->orig_value = ini_entry->value;
379 		ini_entry->orig_modifiable = modifiable;
380 		ini_entry->modified = 1;
381 		zend_hash_add_ptr(EG(modified_ini_directives), ini_entry->name, ini_entry);
382 	}
383 
384 	duplicate = zend_string_copy(new_value);
385 
386 	if (!ini_entry->on_modify
387 		|| ini_entry->on_modify(ini_entry, duplicate, ini_entry->mh_arg1, ini_entry->mh_arg2, ini_entry->mh_arg3, stage) == SUCCESS) {
388 		if (modified && ini_entry->orig_value != ini_entry->value) { /* we already changed the value, free the changed value */
389 			zend_string_release(ini_entry->value);
390 		}
391 		ini_entry->value = duplicate;
392 	} else {
393 		zend_string_release(duplicate);
394 		return FAILURE;
395 	}
396 
397 	return SUCCESS;
398 }
399 /* }}} */
400 
zend_restore_ini_entry(zend_string * name,int stage)401 ZEND_API zend_result zend_restore_ini_entry(zend_string *name, int stage) /* {{{ */
402 {
403 	zend_ini_entry *ini_entry;
404 
405 	if ((ini_entry = zend_hash_find_ptr(EG(ini_directives), name)) == NULL ||
406 		(stage == ZEND_INI_STAGE_RUNTIME && (ini_entry->modifiable & ZEND_INI_USER) == 0)) {
407 		return FAILURE;
408 	}
409 
410 	if (EG(modified_ini_directives)) {
411 		if (zend_restore_ini_entry_cb(ini_entry, stage) == 0) {
412 			zend_hash_del(EG(modified_ini_directives), name);
413 		} else {
414 			return FAILURE;
415 		}
416 	}
417 
418 	return SUCCESS;
419 }
420 /* }}} */
421 
zend_ini_register_displayer(const char * name,uint32_t name_length,void (* displayer)(zend_ini_entry * ini_entry,int type))422 ZEND_API zend_result zend_ini_register_displayer(const char *name, uint32_t name_length, void (*displayer)(zend_ini_entry *ini_entry, int type)) /* {{{ */
423 {
424 	zend_ini_entry *ini_entry;
425 
426 	ini_entry = zend_hash_str_find_ptr(registered_zend_ini_directives, name, name_length);
427 	if (ini_entry == NULL) {
428 		return FAILURE;
429 	}
430 
431 	ini_entry->displayer = displayer;
432 	return SUCCESS;
433 }
434 /* }}} */
435 
436 /*
437  * Data retrieval
438  */
439 
zend_ini_long(const char * name,size_t name_length,int orig)440 ZEND_API zend_long zend_ini_long(const char *name, size_t name_length, int orig) /* {{{ */
441 {
442 	zend_ini_entry *ini_entry;
443 
444 	ini_entry = zend_hash_str_find_ptr(EG(ini_directives), name, name_length);
445 	if (ini_entry) {
446 		if (orig && ini_entry->modified) {
447 			return (ini_entry->orig_value ? ZEND_STRTOL(ZSTR_VAL(ini_entry->orig_value), NULL, 0) : 0);
448 		} else {
449 			return (ini_entry->value      ? ZEND_STRTOL(ZSTR_VAL(ini_entry->value), NULL, 0)      : 0);
450 		}
451 	}
452 
453 	return 0;
454 }
455 /* }}} */
456 
zend_ini_double(const char * name,size_t name_length,int orig)457 ZEND_API double zend_ini_double(const char *name, size_t name_length, int orig) /* {{{ */
458 {
459 	zend_ini_entry *ini_entry;
460 
461 	ini_entry = zend_hash_str_find_ptr(EG(ini_directives), name, name_length);
462 	if (ini_entry) {
463 		if (orig && ini_entry->modified) {
464 			return (double) (ini_entry->orig_value ? zend_strtod(ZSTR_VAL(ini_entry->orig_value), NULL) : 0.0);
465 		} else {
466 			return (double) (ini_entry->value      ? zend_strtod(ZSTR_VAL(ini_entry->value), NULL)      : 0.0);
467 		}
468 	}
469 
470 	return 0.0;
471 }
472 /* }}} */
473 
zend_ini_string_ex(const char * name,size_t name_length,int orig,bool * exists)474 ZEND_API char *zend_ini_string_ex(const char *name, size_t name_length, int orig, bool *exists) /* {{{ */
475 {
476 	zend_ini_entry *ini_entry;
477 
478 	ini_entry = zend_hash_str_find_ptr(EG(ini_directives), name, name_length);
479 	if (ini_entry) {
480 		if (exists) {
481 			*exists = 1;
482 		}
483 
484 		if (orig && ini_entry->modified) {
485 			return ini_entry->orig_value ? ZSTR_VAL(ini_entry->orig_value) : NULL;
486 		} else {
487 			return ini_entry->value ? ZSTR_VAL(ini_entry->value) : NULL;
488 		}
489 	} else {
490 		if (exists) {
491 			*exists = 0;
492 		}
493 		return NULL;
494 	}
495 }
496 /* }}} */
497 
zend_ini_string(const char * name,size_t name_length,int orig)498 ZEND_API char *zend_ini_string(const char *name, size_t name_length, int orig) /* {{{ */
499 {
500 	bool exists = 1;
501 	char *return_value;
502 
503 	return_value = zend_ini_string_ex(name, name_length, orig, &exists);
504 	if (!exists) {
505 		return NULL;
506 	} else if (!return_value) {
507 		return_value = "";
508 	}
509 	return return_value;
510 }
511 /* }}} */
512 
zend_ini_get_value(zend_string * name)513 ZEND_API zend_string *zend_ini_get_value(zend_string *name) /* {{{ */
514 {
515 	zend_ini_entry *ini_entry;
516 
517 	ini_entry = zend_hash_find_ptr(EG(ini_directives), name);
518 	if (ini_entry) {
519 		return ini_entry->value ? ini_entry->value : ZSTR_EMPTY_ALLOC();
520 	} else {
521 		return NULL;
522 	}
523 }
524 /* }}} */
525 
zend_ini_parse_bool(zend_string * str)526 ZEND_API bool zend_ini_parse_bool(zend_string *str)
527 {
528 	if (zend_string_equals_literal_ci(str, "true")
529 			|| zend_string_equals_literal_ci(str, "yes")
530 			|| zend_string_equals_literal_ci(str, "on")
531 	) {
532 		return 1;
533 	} else {
534 		return atoi(ZSTR_VAL(str)) != 0;
535 	}
536 }
537 
ZEND_INI_DISP(zend_ini_boolean_displayer_cb)538 ZEND_INI_DISP(zend_ini_boolean_displayer_cb) /* {{{ */
539 {
540 	int value;
541 	zend_string *tmp_value;
542 
543 	if (type == ZEND_INI_DISPLAY_ORIG && ini_entry->modified) {
544 		tmp_value = (ini_entry->orig_value ? ini_entry->orig_value : NULL );
545 	} else if (ini_entry->value) {
546 		tmp_value = ini_entry->value;
547 	} else {
548 		tmp_value = NULL;
549 	}
550 
551 	if (tmp_value) {
552 		value = zend_ini_parse_bool(tmp_value);
553 	} else {
554 		value = 0;
555 	}
556 
557 	if (value) {
558 		ZEND_PUTS("On");
559 	} else {
560 		ZEND_PUTS("Off");
561 	}
562 }
563 /* }}} */
564 
ZEND_INI_DISP(zend_ini_color_displayer_cb)565 ZEND_INI_DISP(zend_ini_color_displayer_cb) /* {{{ */
566 {
567 	char *value;
568 
569 	if (type == ZEND_INI_DISPLAY_ORIG && ini_entry->modified) {
570 		value = ZSTR_VAL(ini_entry->orig_value);
571 	} else if (ini_entry->value) {
572 		value = ZSTR_VAL(ini_entry->value);
573 	} else {
574 		value = NULL;
575 	}
576 	if (value) {
577 		if (zend_uv.html_errors) {
578 			zend_printf("<font style=\"color: %s\">%s</font>", value, value);
579 		} else {
580 			ZEND_PUTS(value);
581 		}
582 	} else {
583 		if (zend_uv.html_errors) {
584 			ZEND_PUTS(NO_VALUE_HTML);
585 		} else {
586 			ZEND_PUTS(NO_VALUE_PLAINTEXT);
587 		}
588 	}
589 }
590 /* }}} */
591 
ZEND_INI_DISP(display_link_numbers)592 ZEND_INI_DISP(display_link_numbers) /* {{{ */
593 {
594 	char *value;
595 
596 	if (type == ZEND_INI_DISPLAY_ORIG && ini_entry->modified) {
597 		value = ZSTR_VAL(ini_entry->orig_value);
598 	} else if (ini_entry->value) {
599 		value = ZSTR_VAL(ini_entry->value);
600 	} else {
601 		value = NULL;
602 	}
603 
604 	if (value) {
605 		if (atoi(value) == -1) {
606 			ZEND_PUTS("Unlimited");
607 		} else {
608 			zend_printf("%s", value);
609 		}
610 	}
611 }
612 /* }}} */
613 
614 /* Standard message handlers */
ZEND_INI_MH(OnUpdateBool)615 ZEND_API ZEND_INI_MH(OnUpdateBool) /* {{{ */
616 {
617 	bool *p = (bool *) ZEND_INI_GET_ADDR();
618 	*p = zend_ini_parse_bool(new_value);
619 	return SUCCESS;
620 }
621 /* }}} */
622 
ZEND_INI_MH(OnUpdateLong)623 ZEND_API ZEND_INI_MH(OnUpdateLong) /* {{{ */
624 {
625 	zend_long *p = (zend_long *) ZEND_INI_GET_ADDR();
626 	*p = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
627 	return SUCCESS;
628 }
629 /* }}} */
630 
ZEND_INI_MH(OnUpdateLongGEZero)631 ZEND_API ZEND_INI_MH(OnUpdateLongGEZero) /* {{{ */
632 {
633 	zend_long tmp = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
634 	if (tmp < 0) {
635 		return FAILURE;
636 	}
637 
638 	zend_long *p = (zend_long *) ZEND_INI_GET_ADDR();
639 	*p = tmp;
640 
641 	return SUCCESS;
642 }
643 /* }}} */
644 
ZEND_INI_MH(OnUpdateReal)645 ZEND_API ZEND_INI_MH(OnUpdateReal) /* {{{ */
646 {
647 	double *p = (double *) ZEND_INI_GET_ADDR();
648 	*p = zend_strtod(ZSTR_VAL(new_value), NULL);
649 	return SUCCESS;
650 }
651 /* }}} */
652 
ZEND_INI_MH(OnUpdateString)653 ZEND_API ZEND_INI_MH(OnUpdateString) /* {{{ */
654 {
655 	char **p = (char **) ZEND_INI_GET_ADDR();
656 	*p = new_value ? ZSTR_VAL(new_value) : NULL;
657 	return SUCCESS;
658 }
659 /* }}} */
660 
ZEND_INI_MH(OnUpdateStringUnempty)661 ZEND_API ZEND_INI_MH(OnUpdateStringUnempty) /* {{{ */
662 {
663 	if (new_value && !ZSTR_VAL(new_value)[0]) {
664 		return FAILURE;
665 	}
666 
667 	char **p = (char **) ZEND_INI_GET_ADDR();
668 	*p = new_value ? ZSTR_VAL(new_value) : NULL;
669 	return SUCCESS;
670 }
671 /* }}} */
672