1 | /* |
2 | +----------------------------------------------------------------------+ |
3 | | PHP Version 5 | |
4 | +----------------------------------------------------------------------+ |
5 | | Copyright (c) 1997-2015 The PHP Group | |
6 | +----------------------------------------------------------------------+ |
7 | | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt | |
11 | | If you did not receive a copy of the PHP license and are unable to | |
12 | | obtain it through the world-wide-web, please send a note to | |
13 | | license@php.net so we can mail you a copy immediately. | |
14 | +----------------------------------------------------------------------+ |
15 | | Author: Thies C. Arntzen <thies@thieso.net> | |
16 | +----------------------------------------------------------------------+ |
17 | */ |
18 | |
19 | /* $Id$ */ |
20 | |
21 | /* {{{ includes */ |
22 | #include "php.h" |
23 | #include "php_assert.h" |
24 | #include "php_ini.h" |
25 | /* }}} */ |
26 | |
27 | ZEND_BEGIN_MODULE_GLOBALS(assert) |
28 | long active; |
29 | long bail; |
30 | long warning; |
31 | long quiet_eval; |
32 | zval *callback; |
33 | char *cb; |
34 | ZEND_END_MODULE_GLOBALS(assert) |
35 | |
36 | ZEND_DECLARE_MODULE_GLOBALS(assert) |
37 | |
38 | #ifdef ZTS |
39 | #define ASSERTG(v) TSRMG(assert_globals_id, zend_assert_globals *, v) |
40 | #else |
41 | #define ASSERTG(v) (assert_globals.v) |
42 | #endif |
43 | |
44 | #define SAFE_STRING(s) ((s)?(s):"") |
45 | |
46 | enum { |
47 | ASSERT_ACTIVE=1, |
48 | ASSERT_CALLBACK, |
49 | ASSERT_BAIL, |
50 | ASSERT_WARNING, |
51 | ASSERT_QUIET_EVAL |
52 | }; |
53 | |
54 | static PHP_INI_MH(OnChangeCallback) /* {{{ */ |
55 | { |
56 | if (EG(in_execution)) { |
57 | if (ASSERTG(callback)) { |
58 | zval_ptr_dtor(&ASSERTG(callback)); |
59 | ASSERTG(callback) = NULL; |
60 | } |
61 | if (new_value && (ASSERTG(callback) || new_value_length)) { |
62 | MAKE_STD_ZVAL(ASSERTG(callback)); |
63 | ZVAL_STRINGL(ASSERTG(callback), new_value, new_value_length, 1); |
64 | } |
65 | } else { |
66 | if (ASSERTG(cb)) { |
67 | pefree(ASSERTG(cb), 1); |
68 | } |
69 | if (new_value && new_value_length) { |
70 | ASSERTG(cb) = pemalloc(new_value_length + 1, 1); |
71 | memcpy(ASSERTG(cb), new_value, new_value_length); |
72 | ASSERTG(cb)[new_value_length] = '\0'; |
73 | } else { |
74 | ASSERTG(cb) = NULL; |
75 | } |
76 | } |
77 | return SUCCESS; |
78 | } |
79 | /* }}} */ |
80 | |
81 | PHP_INI_BEGIN() |
82 | STD_PHP_INI_ENTRY("assert.active" , "1" , PHP_INI_ALL, OnUpdateLong, active, zend_assert_globals, assert_globals) |
83 | STD_PHP_INI_ENTRY("assert.bail" , "0" , PHP_INI_ALL, OnUpdateLong, bail, zend_assert_globals, assert_globals) |
84 | STD_PHP_INI_ENTRY("assert.warning" , "1" , PHP_INI_ALL, OnUpdateLong, warning, zend_assert_globals, assert_globals) |
85 | PHP_INI_ENTRY("assert.callback" , NULL, PHP_INI_ALL, OnChangeCallback) |
86 | STD_PHP_INI_ENTRY("assert.quiet_eval" , "0" , PHP_INI_ALL, OnUpdateLong, quiet_eval, zend_assert_globals, assert_globals) |
87 | PHP_INI_END() |
88 | |
89 | static void php_assert_init_globals(zend_assert_globals *assert_globals_p TSRMLS_DC) /* {{{ */ |
90 | { |
91 | assert_globals_p->callback = NULL; |
92 | assert_globals_p->cb = NULL; |
93 | } |
94 | /* }}} */ |
95 | |
96 | PHP_MINIT_FUNCTION(assert) /* {{{ */ |
97 | { |
98 | ZEND_INIT_MODULE_GLOBALS(assert, php_assert_init_globals, NULL); |
99 | |
100 | REGISTER_INI_ENTRIES(); |
101 | |
102 | REGISTER_LONG_CONSTANT("ASSERT_ACTIVE" , ASSERT_ACTIVE, CONST_CS|CONST_PERSISTENT); |
103 | REGISTER_LONG_CONSTANT("ASSERT_CALLBACK" , ASSERT_CALLBACK, CONST_CS|CONST_PERSISTENT); |
104 | REGISTER_LONG_CONSTANT("ASSERT_BAIL" , ASSERT_BAIL, CONST_CS|CONST_PERSISTENT); |
105 | REGISTER_LONG_CONSTANT("ASSERT_WARNING" , ASSERT_WARNING, CONST_CS|CONST_PERSISTENT); |
106 | REGISTER_LONG_CONSTANT("ASSERT_QUIET_EVAL" , ASSERT_QUIET_EVAL, CONST_CS|CONST_PERSISTENT); |
107 | |
108 | return SUCCESS; |
109 | } |
110 | /* }}} */ |
111 | |
112 | PHP_MSHUTDOWN_FUNCTION(assert) /* {{{ */ |
113 | { |
114 | if (ASSERTG(cb)) { |
115 | pefree(ASSERTG(cb), 1); |
116 | ASSERTG(cb) = NULL; |
117 | } |
118 | return SUCCESS; |
119 | } |
120 | /* }}} */ |
121 | |
122 | PHP_RSHUTDOWN_FUNCTION(assert) /* {{{ */ |
123 | { |
124 | if (ASSERTG(callback)) { |
125 | zval_ptr_dtor(&ASSERTG(callback)); |
126 | ASSERTG(callback) = NULL; |
127 | } |
128 | |
129 | return SUCCESS; |
130 | } |
131 | /* }}} */ |
132 | |
133 | PHP_MINFO_FUNCTION(assert) /* {{{ */ |
134 | { |
135 | DISPLAY_INI_ENTRIES(); |
136 | } |
137 | /* }}} */ |
138 | |
139 | /* {{{ proto int assert(string|bool assertion[, string description]) |
140 | Checks if assertion is false */ |
141 | PHP_FUNCTION(assert) |
142 | { |
143 | zval **assertion; |
144 | int val, description_len = 0; |
145 | char *myeval = NULL; |
146 | char *compiled_string_description, *description = NULL; |
147 | |
148 | if (! ASSERTG(active)) { |
149 | RETURN_TRUE; |
150 | } |
151 | |
152 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|s" , &assertion, &description, &description_len) == FAILURE) { |
153 | return; |
154 | } |
155 | |
156 | if (Z_TYPE_PP(assertion) == IS_STRING) { |
157 | zval retval; |
158 | int old_error_reporting = 0; /* shut up gcc! */ |
159 | |
160 | myeval = Z_STRVAL_PP(assertion); |
161 | |
162 | if (ASSERTG(quiet_eval)) { |
163 | old_error_reporting = EG(error_reporting); |
164 | EG(error_reporting) = 0; |
165 | } |
166 | |
167 | compiled_string_description = zend_make_compiled_string_description("assert code" TSRMLS_CC); |
168 | if (zend_eval_stringl(myeval, Z_STRLEN_PP(assertion), &retval, compiled_string_description TSRMLS_CC) == FAILURE) { |
169 | efree(compiled_string_description); |
170 | if (description_len == 0) { |
171 | php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Failure evaluating code: %s%s" , PHP_EOL, myeval); |
172 | } else { |
173 | php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Failure evaluating code: %s%s:\"%s\"" , PHP_EOL, description, myeval); |
174 | } |
175 | if (ASSERTG(bail)) { |
176 | zend_bailout(); |
177 | } |
178 | RETURN_FALSE; |
179 | } |
180 | efree(compiled_string_description); |
181 | |
182 | if (ASSERTG(quiet_eval)) { |
183 | EG(error_reporting) = old_error_reporting; |
184 | } |
185 | |
186 | convert_to_boolean(&retval); |
187 | val = Z_LVAL(retval); |
188 | } else { |
189 | convert_to_boolean_ex(assertion); |
190 | val = Z_LVAL_PP(assertion); |
191 | } |
192 | |
193 | if (val) { |
194 | RETURN_TRUE; |
195 | } |
196 | |
197 | if (!ASSERTG(callback) && ASSERTG(cb)) { |
198 | MAKE_STD_ZVAL(ASSERTG(callback)); |
199 | ZVAL_STRING(ASSERTG(callback), ASSERTG(cb), 1); |
200 | } |
201 | |
202 | if (ASSERTG(callback)) { |
203 | zval **args = safe_emalloc(description_len == 0 ? 3 : 4, sizeof(zval *), 0); |
204 | zval *retval; |
205 | int i; |
206 | uint lineno = zend_get_executed_lineno(TSRMLS_C); |
207 | const char *filename = zend_get_executed_filename(TSRMLS_C); |
208 | |
209 | MAKE_STD_ZVAL(args[0]); |
210 | MAKE_STD_ZVAL(args[1]); |
211 | MAKE_STD_ZVAL(args[2]); |
212 | |
213 | ZVAL_STRING(args[0], SAFE_STRING(filename), 1); |
214 | ZVAL_LONG (args[1], lineno); |
215 | ZVAL_STRING(args[2], SAFE_STRING(myeval), 1); |
216 | |
217 | MAKE_STD_ZVAL(retval); |
218 | ZVAL_FALSE(retval); |
219 | |
220 | /* XXX do we want to check for error here? */ |
221 | if (description_len == 0) { |
222 | call_user_function(CG(function_table), NULL, ASSERTG(callback), retval, 3, args TSRMLS_CC); |
223 | for (i = 0; i <= 2; i++) { |
224 | zval_ptr_dtor(&(args[i])); |
225 | } |
226 | } else { |
227 | MAKE_STD_ZVAL(args[3]); |
228 | ZVAL_STRINGL(args[3], SAFE_STRING(description), description_len, 1); |
229 | |
230 | call_user_function(CG(function_table), NULL, ASSERTG(callback), retval, 4, args TSRMLS_CC); |
231 | for (i = 0; i <= 3; i++) { |
232 | zval_ptr_dtor(&(args[i])); |
233 | } |
234 | } |
235 | |
236 | efree(args); |
237 | zval_ptr_dtor(&retval); |
238 | } |
239 | |
240 | if (ASSERTG(warning)) { |
241 | if (description_len == 0) { |
242 | if (myeval) { |
243 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Assertion \"%s\" failed" , myeval); |
244 | } else { |
245 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Assertion failed" ); |
246 | } |
247 | } else { |
248 | if (myeval) { |
249 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: \"%s\" failed" , description, myeval); |
250 | } else { |
251 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s failed" , description); |
252 | } |
253 | } |
254 | } |
255 | |
256 | if (ASSERTG(bail)) { |
257 | zend_bailout(); |
258 | } |
259 | } |
260 | /* }}} */ |
261 | |
262 | /* {{{ proto mixed assert_options(int what [, mixed value]) |
263 | Set/get the various assert flags */ |
264 | PHP_FUNCTION(assert_options) |
265 | { |
266 | zval **value = NULL; |
267 | long what; |
268 | int oldint; |
269 | int ac = ZEND_NUM_ARGS(); |
270 | |
271 | if (zend_parse_parameters(ac TSRMLS_CC, "l|Z" , &what, &value) == FAILURE) { |
272 | return; |
273 | } |
274 | |
275 | switch (what) { |
276 | case ASSERT_ACTIVE: |
277 | oldint = ASSERTG(active); |
278 | if (ac == 2) { |
279 | convert_to_string_ex(value); |
280 | zend_alter_ini_entry_ex("assert.active" , sizeof("assert.active" ), Z_STRVAL_PP(value), Z_STRLEN_PP(value), PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC); |
281 | } |
282 | RETURN_LONG(oldint); |
283 | break; |
284 | |
285 | case ASSERT_BAIL: |
286 | oldint = ASSERTG(bail); |
287 | if (ac == 2) { |
288 | convert_to_string_ex(value); |
289 | zend_alter_ini_entry_ex("assert.bail" , sizeof("assert.bail" ), Z_STRVAL_PP(value), Z_STRLEN_PP(value), PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC); |
290 | } |
291 | RETURN_LONG(oldint); |
292 | break; |
293 | |
294 | case ASSERT_QUIET_EVAL: |
295 | oldint = ASSERTG(quiet_eval); |
296 | if (ac == 2) { |
297 | convert_to_string_ex(value); |
298 | zend_alter_ini_entry_ex("assert.quiet_eval" , sizeof("assert.quiet_eval" ), Z_STRVAL_PP(value), Z_STRLEN_PP(value), PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC); |
299 | } |
300 | RETURN_LONG(oldint); |
301 | break; |
302 | |
303 | case ASSERT_WARNING: |
304 | oldint = ASSERTG(warning); |
305 | if (ac == 2) { |
306 | convert_to_string_ex(value); |
307 | zend_alter_ini_entry_ex("assert.warning" , sizeof("assert.warning" ), Z_STRVAL_PP(value), Z_STRLEN_PP(value), PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC); |
308 | } |
309 | RETURN_LONG(oldint); |
310 | break; |
311 | |
312 | case ASSERT_CALLBACK: |
313 | if (ASSERTG(callback) != NULL) { |
314 | RETVAL_ZVAL(ASSERTG(callback), 1, 0); |
315 | } else if (ASSERTG(cb)) { |
316 | RETVAL_STRING(ASSERTG(cb), 1); |
317 | } else { |
318 | RETVAL_NULL(); |
319 | } |
320 | if (ac == 2) { |
321 | if (ASSERTG(callback)) { |
322 | zval_ptr_dtor(&ASSERTG(callback)); |
323 | } |
324 | ASSERTG(callback) = *value; |
325 | zval_add_ref(value); |
326 | } |
327 | return; |
328 | break; |
329 | |
330 | default: |
331 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown value %ld" , what); |
332 | break; |
333 | } |
334 | |
335 | RETURN_FALSE; |
336 | } |
337 | /* }}} */ |
338 | |
339 | /* |
340 | * Local variables: |
341 | * tab-width: 4 |
342 | * c-basic-offset: 4 |
343 | * End: |
344 | * vim600: sw=4 ts=4 fdm=marker |
345 | * vim<600: sw=4 ts=4 |
346 | */ |
347 | |
348 | |