| PHP Cross Reference |
|
/repository/ ZendEngine2/ zend_API.c |
|
|
1 /*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1998-2008 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 | Authors: Andi Gutmans <andi@zend.com> |
16 | Zeev Suraski <zeev@zend.com> |
17 | Andrei Zmievski <andrei@php.net> |
18 +----------------------------------------------------------------------+
19 */
20
21 /* $Id: zend_API.c,v 1.489 2008/08/22 14:51:19 tony2001 Exp $ */
22
23 #include "zend.h"
24 #include "zend_execute.h"
25 #include "zend_API.h"
26 #include "zend_modules.h"
27 #include "zend_constants.h"
28 #include "zend_exceptions.h"
29 #include "zend_closures.h"
30
31 #ifdef HAVE_STDARG_H
32 #include <stdarg.h>
33 #endif
34
35 /* these variables are true statics/globals, and have to be mutex'ed on every access */
36 static int module_count=0;
37 ZEND_API HashTable module_registry;
38
39 /* this function doesn't check for too many parameters */
40 ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */
41 {
42 void **p;
43 int arg_count;
44 va_list ptr;
45 zval **param, *param_ptr;
46 TSRMLS_FETCH();
47
48 p = zend_vm_stack_top(TSRMLS_C) - 1;
49 arg_count = (int)(zend_uintptr_t) *p;
50
51 if (param_count>arg_count) {
52 return FAILURE;
53 }
54
55 va_start(ptr, param_count);
56
57 while (param_count-->0) {
58 param = va_arg(ptr, zval **);
59 param_ptr = *(p-arg_count);
60 if (!PZVAL_IS_REF(param_ptr) && Z_REFCOUNT_P(param_ptr) > 1) {
61 zval *new_tmp;
62
63 ALLOC_ZVAL(new_tmp);
64 *new_tmp = *param_ptr;
65 zval_copy_ctor(new_tmp);
66 INIT_PZVAL(new_tmp);
67 param_ptr = new_tmp;
68 Z_DELREF_P((zval *) *(p-arg_count));
69 *(p-arg_count) = param_ptr;
70 }
71 *param = param_ptr;
72 arg_count--;
73 }
74 va_end(ptr);
75
76 return SUCCESS;
77 }
78 /* }}} */
79
80 ZEND_API int _zend_get_parameters_array(int ht, int param_count, zval **argument_array TSRMLS_DC) /* {{{ */
81 {
82 void **p;
83 int arg_count;
84 zval *param_ptr;
85
86 p = zend_vm_stack_top(TSRMLS_C) - 1;
87 arg_count = (int)(zend_uintptr_t) *p;
88
89 if (param_count>arg_count) {
90 return FAILURE;
91 }
92
93 while (param_count-->0) {
94 param_ptr = *(p-arg_count);
95 if (!PZVAL_IS_REF(param_ptr) && Z_REFCOUNT_P(param_ptr) > 1) {
96 zval *new_tmp;
97
98 ALLOC_ZVAL(new_tmp);
99 *new_tmp = *param_ptr;
100 zval_copy_ctor(new_tmp);
101 INIT_PZVAL(new_tmp);
102 param_ptr = new_tmp;
103 Z_DELREF_P((zval *) *(p-arg_count));
104 *(p-arg_count) = param_ptr;
105 }
106 *(argument_array++) = param_ptr;
107 arg_count--;
108 }
109
110 return SUCCESS;
111 }
112 /* }}} */
113
114 /* Zend-optimized Extended functions */
115 /* this function doesn't check for too many parameters */
116 ZEND_API int zend_get_parameters_ex(int param_count, ...) /* {{{ */
117 {
118 void **p;
119 int arg_count;
120 va_list ptr;
121 zval ***param;
122 TSRMLS_FETCH();
123
124 p = zend_vm_stack_top(TSRMLS_C) - 1;
125 arg_count = (int)(zend_uintptr_t) *p;
126
127 if (param_count>arg_count) {
128 return FAILURE;
129 }
130
131 va_start(ptr, param_count);
132 while (param_count-->0) {
133 param = va_arg(ptr, zval ***);
134 *param = (zval **) p-(arg_count--);
135 }
136 va_end(ptr);
137
138 return SUCCESS;
139 }
140 /* }}} */
141
142 ZEND_API int _zend_get_parameters_array_ex(int param_count, zval ***argument_array TSRMLS_DC) /* {{{ */
143 {
144 void **p;
145 int arg_count;
146
147 p = zend_vm_stack_top(TSRMLS_C) - 1;
148 arg_count = (int)(zend_uintptr_t) *p;
149
150 if (param_count>arg_count) {
151 return FAILURE;
152 }
153
154 while (param_count-->0) {
155 zval **value = (zval**)(p-arg_count);
156
157 *(argument_array++) = value;
158 arg_count--;
159 }
160
161 return SUCCESS;
162 }
163 /* }}} */
164
165 ZEND_API int zend_copy_parameters_array(int param_count, zval *argument_array TSRMLS_DC) /* {{{ */
166 {
167 void **p;
168 int arg_count;
169
170 p = zend_vm_stack_top(TSRMLS_C) - 1;
171 arg_count = (int)(zend_uintptr_t) *p;
172
173 if (param_count>arg_count) {
174 return FAILURE;
175 }
176
177 while (param_count-->0) {
178 zval **param = (zval **) p-(arg_count--);
179 zval_add_ref(param);
180 add_next_index_zval(argument_array, *param);
181 }
182
183 return SUCCESS;
184 }
185 /* }}} */
186
187 ZEND_API void zend_wrong_param_count(TSRMLS_D) /* {{{ */
188 {
189 char *space;
190 zstr class_name = get_active_class_name(&space TSRMLS_CC);
191
192 zend_error(E_WARNING, "Wrong parameter count for %v%s%v()", class_name, space, get_active_function_name(TSRMLS_C));
193 }
194 /* }}} */
195
196 /* Argument parsing API -- andrei */
197 ZEND_API char *zend_get_type_by_const(int type) /* {{{ */
198 {
199 switch(type) {
200 case IS_BOOL:
201 return "boolean";
202 case IS_LONG:
203 return "integer";
204 case IS_DOUBLE:
205 return "double";
206 case IS_STRING:
207 {
208 TSRMLS_FETCH();
209
210 if (UG(unicode)) {
211 return "binary string";
212 } else {
213 return "string";
214 }
215 }
216 case IS_OBJECT:
217 return "object";
218 case IS_RESOURCE:
219 return "resource";
220 case IS_NULL:
221 return "null";
222 case IS_ARRAY:
223 return "array";
224 case IS_UNICODE:
225 return "Unicode string";
226 default:
227 return "unknown";
228 }
229 }
230 /* }}} */
231
232 ZEND_API char *zend_zval_type_name(const zval *arg) /* {{{ */
233 {
234 return zend_get_type_by_const(Z_TYPE_P(arg));
235 }
236 /* }}} */
237
238 ZEND_API zend_class_entry *zend_get_class_entry(const zval *zobject TSRMLS_DC) /* {{{ */
239 {
240 if (Z_OBJ_HT_P(zobject)->get_class_entry) {
241 return Z_OBJ_HT_P(zobject)->get_class_entry(zobject TSRMLS_CC);
242 } else {
243 zend_error(E_ERROR, "Class entry requested for an object without PHP class");
244 return NULL;
245 }
246 }
247 /* }}} */
248
249 /* returns 1 if you need to copy result, 0 if it's already a copy */
250 ZEND_API int zend_get_object_classname(const zval *object, zstr *class_name, zend_uint *class_name_len TSRMLS_DC) /* {{{ */
251 {
252 if (Z_OBJ_HT_P(object)->get_class_name == NULL ||
253 Z_OBJ_HT_P(object)->get_class_name(object, class_name, class_name_len, 0 TSRMLS_CC) != SUCCESS) {
254 zend_class_entry *ce = Z_OBJCE_P(object);
255
256 *class_name = ce->name;
257 *class_name_len = ce->name_length;
258 return 1;
259 }
260 return 0;
261 }
262 /* }}} */
263
264 #define RETURN_AS_STRING(arg, p, pl, type) \
265 (*p).s = Z_STRVAL_PP(arg); \
266 *pl = Z_STRLEN_PP(arg); \
267 *type = IS_STRING;
268
269 #define RETURN_AS_UNICODE(arg, p, pl, type) \
270 (*p).u = Z_USTRVAL_PP(arg); \
271 *pl = Z_USTRLEN_PP(arg); \
272 *type = IS_UNICODE;
273
274 static int parse_arg_object_to_string(zval **arg, char **p, int *pl, int type TSRMLS_DC) /* {{{ */
275 {
276 if (Z_OBJ_HANDLER_PP(arg, cast_object)) {
277 SEPARATE_ZVAL_IF_NOT_REF(arg);
278 if (Z_OBJ_HANDLER_PP(arg, cast_object)(*arg, *arg, type, NULL TSRMLS_CC) == SUCCESS) {
279 *pl = Z_STRLEN_PP(arg);
280 *p = Z_STRVAL_PP(arg);
281 return SUCCESS;
282 }
283 }
284 /* Standard PHP objects */
285 if (Z_OBJ_HT_PP(arg) == &std_object_handlers || !Z_OBJ_HANDLER_PP(arg, cast_object)) {
286 SEPARATE_ZVAL_IF_NOT_REF(arg);
287 if (zend_std_cast_object_tostring(*arg, *arg, type, NULL TSRMLS_CC) == SUCCESS) {
288 *pl = Z_STRLEN_PP(arg);
289 *p = Z_STRVAL_PP(arg);
290 return SUCCESS;
291 }
292 }
293 if (!Z_OBJ_HANDLER_PP(arg, cast_object) && Z_OBJ_HANDLER_PP(arg, get)) {
294 int use_copy;
295 zval *z = Z_OBJ_HANDLER_PP(arg, get)(*arg TSRMLS_CC);
296 Z_ADDREF_P(z);
297 if(Z_TYPE_P(z) != IS_OBJECT) {
298 zval_dtor(*arg);
299 Z_TYPE_P(*arg) = IS_NULL;
300 if (type == IS_STRING) {
301 zend_make_string_zval(z, *arg, &use_copy);
302 } else {
303 zend_make_unicode_zval(z, *arg, &use_copy);
304 }
305 if (!use_copy) {
306 ZVAL_ZVAL(*arg, z, 1, 1);
307 }
308 *pl = Z_STRLEN_PP(arg);
309 *p = Z_STRVAL_PP(arg);
310 return SUCCESS;
311 }
312 zval_ptr_dtor(&z);
313 }
314 return FAILURE;
315 }
316 /* }}} */
317
318 static char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, char **spec, char T_arg_type, int* ret_type, char **error, int *severity TSRMLS_DC) /* {{{ */
319 {
320 char *spec_walk = *spec;
321 char c = *spec_walk++;
322 int return_null = 0;
323 int alternate_form = 0;
324 int return_orig_type = 0;
325 zend_uchar orig_type;
326
327 /* scan through modifiers */
328 while (1) {
329 if (*spec_walk == '/') {
330 SEPARATE_ZVAL_IF_NOT_REF(arg);
331 } else if (*spec_walk == '&') {
332 alternate_form = 1;
333 } else if (*spec_walk == '!') {
334 if (Z_TYPE_PP(arg) == IS_NULL) {
335 return_null = 1;
336 }
337 } else if (*spec_walk == '^') {
338 return_orig_type = 1;
339 orig_type = Z_TYPE_PP(arg);
340 } else {
341 break;
342 }
343 spec_walk++;
344 }
345
346 if (c == 'x') {
347 c = UG(unicode) ? 'u' : 's';
348 }
349
350 switch (c) {
351 case 'l':
352 {
353 long *p = va_arg(*va, long *);
354 switch (Z_TYPE_PP(arg)) {
355 case IS_STRING:
356 {
357 double d;
358 int type;
359
360 if ((type = is_numeric_string(Z_STRVAL_PP(arg), Z_STRLEN_PP(arg), p, &d, -1)) == 0) {
361 return "long";
362 } else if (type == IS_DOUBLE) {
363 *p = (long) d;
364 }
365 }
366 break;
367
368 case IS_UNICODE:
369 {
370 double d;
371 int type;
372
373 if ((type = is_numeric_unicode(Z_USTRVAL_PP(arg), Z_USTRLEN_PP(arg), p, &d, -1)) == 0) {
374 return "long";
375 } else if (type == IS_DOUBLE) {
376 *p = (long) d;
377 }
378 }
379 break;
380
381 case IS_NULL:
382 case IS_LONG:
383 case IS_DOUBLE:
384 case IS_BOOL:
385 convert_to_long_ex(arg);
386 *p = Z_LVAL_PP(arg);
387 break;
388
389 case IS_ARRAY:
390 case IS_OBJECT:
391 case IS_RESOURCE:
392 default:
393 return "long";
394 }
395 }
396 break;
397
398 case 'd':
399 {
400 double *p = va_arg(*va, double *);
401 switch (Z_TYPE_PP(arg)) {
402 case IS_STRING:
403 {
404 long l;
405 int type;
406
407 if ((type = is_numeric_string(Z_STRVAL_PP(arg), Z_STRLEN_PP(arg), &l, p, -1)) == 0) {
408 return "double";
409 } else if (type == IS_LONG) {
410 *p = (double) l;
411 }
412 }
413 break;
414
415 case IS_UNICODE:
416 {
417 long l;
418 int type;
419
420 if ((type = is_numeric_unicode(Z_USTRVAL_PP(arg), Z_USTRLEN_PP(arg), &l, p, -1)) == 0) {
421 return "double";
422 } else if (type == IS_LONG) {
423 *p = (double) l;
424 }
425 }
426 break;
427
428 case IS_NULL:
429 case IS_LONG:
430 case IS_DOUBLE:
431 case IS_BOOL:
432 convert_to_double_ex(arg);
433 *p = Z_DVAL_PP(arg);
434 break;
435
436 case IS_ARRAY:
437 case IS_OBJECT:
438 case IS_RESOURCE:
439 default:
440 return "double";
441 }
442 }
443 break;
444
445 case 's':
446 case 'S':
447 {
448 char **p = va_arg(*va, char **);
449 int *pl = va_arg(*va, int *);
450 UConverter *conv = NULL;
451
452 if (c == 's' && alternate_form) {
453 conv = va_arg(*va, UConverter *);
454 }
455
456 if (return_orig_type) {
457 zend_uchar *type = va_arg(*va, zend_uchar *);
458 *type = orig_type;
459 }
460
461 switch (Z_TYPE_PP(arg)) {
462 case IS_NULL:
463 if (return_null) {
464 *p = NULL;
465 *pl = 0;
466 break;
467 }
468 /* break omitted intentionally */
469
470 case IS_UNICODE:
471 /* handle conversion of Unicode to binary with a specific converter */
472 if (conv != NULL) {
473 SEPARATE_ZVAL_IF_NOT_REF(arg);
474 if (convert_to_string_with_converter(*arg, conv) == FAILURE) {
475 return "";
476 }
477 *p = Z_STRVAL_PP(arg);
478 *pl = Z_STRLEN_PP(arg);
479 break;
480 } else if (c == 'S' && Z_TYPE_PP(arg) != IS_NULL /* NULL is ok */) {
481 return "strictly a binary string";
482 }
483 /* fall through */
484 case IS_STRING:
485 case IS_LONG:
486 case IS_DOUBLE:
487 case IS_BOOL:
488 convert_to_string_ex(arg);
489 *p = Z_STRVAL_PP(arg);
490 *pl = Z_STRLEN_PP(arg);
491 break;
492
493 case IS_OBJECT:
494 if (parse_arg_object_to_string(arg, p, pl, IS_STRING TSRMLS_CC) == SUCCESS) {
495 break;
496 }
497
498 case IS_ARRAY:
499 case IS_RESOURCE:
500 default:
501 if (UG(unicode)) {
502 return "binary string";
503 } else {
504 return "string";
505 }
506 }
507 }
508 break;
509
510 case 'u':
511 case 'U':
512 {
513 UChar **p = va_arg(*va, UChar **);
514 int *pl = va_arg(*va, int *);
515
516 if (return_orig_type) {
517 zend_uchar *type = va_arg(*va, zend_uchar *);
518 *type = orig_type;
519 }
520
521 switch (Z_TYPE_PP(arg)) {
522 case IS_NULL:
523 if (return_null) {
524 *p = NULL;
525 *pl = 0;
526 break;
527 }
528 /* break omitted intentionally */
529
530 case IS_STRING:
531 if (c == 'U') {
532 return "strictly a Unicode string";
533 }
534 /* fall through */
535 case IS_LONG:
536 case IS_DOUBLE:
537 case IS_BOOL:
538 case IS_UNICODE:
539 convert_to_unicode_ex(arg);
540 *p = Z_USTRVAL_PP(arg);
541 *pl = Z_USTRLEN_PP(arg);
542 break;
543
544 case IS_OBJECT:
545 if (parse_arg_object_to_string(arg, (char**)p, pl, IS_UNICODE TSRMLS_CC) == SUCCESS) {
546 break;
547 }
548
549 case IS_ARRAY:
550 case IS_RESOURCE:
551 default:
552 return "Unicode string";
553 }
554 }
555 break;
556
557 case 'T':
558 if (T_arg_type != -1)
559 {
560 zstr *p = va_arg(*va, zstr *);
561 int *pl = va_arg(*va, int *);
562 zend_uchar *type = va_arg(*va, zend_uchar *);
563 switch (Z_TYPE_PP(arg)) {
564 case IS_NULL:
565 if (return_null) {
566 *p = NULL_ZSTR;
567 *pl = 0;
568 *type = T_arg_type;
569 break;
570 }
571 /* break omitted intentionally */
572
573 case IS_LONG:
574 case IS_DOUBLE:
575 case IS_BOOL:
576 case IS_STRING:
577 case IS_UNICODE:
578 if (T_arg_type == IS_UNICODE) {
579 convert_to_unicode_ex(arg);
580 RETURN_AS_UNICODE(arg, p, pl, type);
581 } else if (T_arg_type == IS_STRING) {
582 convert_to_string_ex(arg);
583 RETURN_AS_STRING(arg, p, pl, type);
584 }
585 break;
586
587 case IS_OBJECT:
588 if (parse_arg_object_to_string(arg, (char**)p, pl, T_arg_type TSRMLS_CC) == SUCCESS) {
589 *type = Z_TYPE_PP(arg);
590 break;
591 }
592
593 case IS_ARRAY:
594 case IS_RESOURCE:
595 default:
596 return "string (Unicode or binary)";
597 }
598
599 break;
600 }
601 /* break omitted intentionally */
602
603 case 't':
604 {
605 zstr *p = va_arg(*va, zstr *);
606 int *pl = va_arg(*va, int *);
607 zend_uchar *type = va_arg(*va, zend_uchar *);
608 switch (Z_TYPE_PP(arg)) {
609 case IS_NULL:
610 if (return_null) {
611 *p = NULL_ZSTR;
612 *pl = 0;
613 *type = UG(unicode)?IS_UNICODE:IS_STRING;
614 break;
615 }
616 /* break omitted intentionally */
617
618 case IS_LONG:
619 case IS_DOUBLE:
620 case IS_BOOL:
621 if (UG(unicode)) {
622 convert_to_unicode_ex(arg);
623 RETURN_AS_UNICODE(arg, p, pl, type);
624 } else {
625 convert_to_string_ex(arg);
626 RETURN_AS_STRING(arg, p, pl, type);
627 }
628 break;
629
630 case IS_STRING:
631 RETURN_AS_STRING(arg, p, pl, type);
632 break;
633
634 case IS_UNICODE:
635 RETURN_AS_UNICODE(arg, p, pl, type);
636 break;
637
638 case IS_OBJECT:
639 if (parse_arg_object_to_string(arg, (char**)p, pl, UG(unicode) ? IS_UNICODE : IS_STRING TSRMLS_CC) == SUCCESS) {
640 *type = UG(unicode)?IS_UNICODE:IS_STRING;
641 break;
642 }
643
644 case IS_ARRAY:
645 case IS_RESOURCE:
646 default:
647 return "string (Unicode or binary)";
648 }
649 }
650 break;
651
652 case 'b':
653 {
654 zend_bool *p = va_arg(*va, zend_bool *);
655 switch (Z_TYPE_PP(arg)) {
656 case IS_NULL:
657 case IS_STRING:
658 case IS_UNICODE:
659 case IS_LONG:
660 case IS_DOUBLE:
661 case IS_BOOL:
662 convert_to_boolean_ex(arg);
663 *p = Z_BVAL_PP(arg);
664 break;
665
666 case IS_ARRAY:
667 case IS_OBJECT:
668 case IS_RESOURCE:
669 default:
670 return "boolean";
671 }
672 }
673 break;
674
675 case 'r':
676 {
677 zval **p = va_arg(*va, zval **);
678 if (return_null) {
679 *p = NULL;
680 break;
681 }
682 if (Z_TYPE_PP(arg) == IS_RESOURCE) {
683 *p = *arg;
684 } else {
685 return "resource";
686 }
687 }
688 break;
689
690 case 'a':
691 {
692 zval **p = va_arg(*va, zval **);
693 if (return_null) {
694 *p = NULL;
695 break;
696 }
697 if (Z_TYPE_PP(arg) == IS_ARRAY) {
698 *p = *arg;
699 } else {
700 return "array";
701 }
702 }
703 break;
704
705 case 'h':
706 {
707 HashTable **p = va_arg(*va, HashTable **);
708 if (return_null) {
709 *p = NULL;
710 break;
711 }
712 if (Z_TYPE_PP(arg) == IS_ARRAY) {
713 *p = Z_ARRVAL_PP(arg);
714 } else {
715 return "array";
716 }
717 }
718 break;
719
720 case 'o':
721 {
722 zval **p = va_arg(*va, zval **);
723 if (return_null) {
724 *p = NULL;
725 break;
726 }
727 if (Z_TYPE_PP(arg) == IS_OBJECT) {
728 *p = *arg;
729 } else {
730 return "object";
731 }
732 }
733 break;
734
735 case 'O':
736 {
737 zval **p = va_arg(*va, zval **);
738 zend_class_entry *ce = va_arg(*va, zend_class_entry *);
739
740 if (return_null) {
741 *p = NULL;
742 break;
743 }
744 if (Z_TYPE_PP(arg) == IS_OBJECT &&
745 (!ce || instanceof_function(Z_OBJCE_PP(arg), ce TSRMLS_CC))) {
746 *p = *arg;
747 } else {
748 if (ce) {
749 *ret_type = UG(unicode)?IS_UNICODE:IS_STRING;
750 return ce->name.v;
751 } else {
752 return "object";
753 }
754 }
755 }
756 break;
757
758 case 'C':
759 {
760 zend_class_entry **lookup, **pce = va_arg(*va, zend_class_entry **);
761 zend_class_entry *ce_base = *pce;
762
763 if (return_null) {
764 *pce = NULL;
765 break;
766 }
767 convert_to_text_ex(arg);
768 if (zend_u_lookup_class(Z_TYPE_PP(arg), Z_UNIVAL_PP(arg), Z_UNILEN_PP(arg), &lookup TSRMLS_CC) == FAILURE) {
769 *pce = NULL;
770 } else {
771 *pce = *lookup;
772 }
773 if (ce_base) {
774 if ((!*pce || !instanceof_function(*pce, ce_base TSRMLS_CC))) {
775 zend_spprintf(error, 0, "to be a class name derived from %v, '%v' given",
776 ce_base->name, Z_UNIVAL_PP(arg));
777 *pce = NULL;
778 return "";
779 }
780 }
781 if (!*pce) {
782 zend_spprintf(error, 0, "to be a valid class name, '%v' given",
783 Z_UNIVAL_PP(arg));
784 return "";
785 }
786 break;
787
788 }
789 break;
790
791 case 'f':
792 {
793 zend_fcall_info *fci = va_arg(*va, zend_fcall_info *);
794 zend_fcall_info_cache *fcc = va_arg(*va, zend_fcall_info_cache *);
795 char *is_callable_error = NULL;
796
797 if (return_null) {
798 fci->size = 0;
799 fcc->initialized = 0;
800 break;
801 }
802
803 if (zend_fcall_info_init(*arg, 0, fci, fcc, NULL, &is_callable_error TSRMLS_CC) == SUCCESS) {
804 if (is_callable_error) {
805 *severity = E_STRICT;
806 zend_spprintf(error, 0, "to be a valid callback, %s", is_callable_error);
807 efree(is_callable_error);
808 *spec = spec_walk;
809 return "";
810 }
811 break;
812 } else {
813 if (is_callable_error) {
814 *severity = E_WARNING;
815 zend_spprintf(error, 0, "to be a valid callback, %s", is_callable_error);
816 efree(is_callable_error);
817 return "";
818 } else {
819 return "valid callback";
820 }
821 }
822 }
823
824 case 'z':
825 {
826 zval **p = va_arg(*va, zval **);
827 if (return_null) {
828 *p = NULL;
829 } else {
830 *p = *arg;
831 }
832 }
833 break;
834
835 case 'Z':
836 {
837 zval ***p = va_arg(*va, zval ***);
838 if (return_null) {
839 *p = NULL;
840 } else {
841 *p = arg;
842 }
843 }
844 break;
845
846 default:
847 return "unknown";
848 }
849
850 *spec = spec_walk;
851
852 return NULL;
853 }
854 /* }}} */
855
856 static int zend_parse_arg(int arg_num, zval **arg, va_list *va, char **spec, int quiet, char T_arg_type TSRMLS_DC) /* {{{ */
857 {
858 char *expected_type = NULL, *error = NULL;
859 int ret_type = IS_STRING;
860 int severity = E_WARNING;
861
862 expected_type = zend_parse_arg_impl(arg_num, arg, va, spec, T_arg_type, &ret_type, &error, &severity TSRMLS_CC);
863 if (expected_type) {
864 if (!quiet && (*expected_type || error)) {
865 char *space;
866 zstr class_name = get_active_class_name(&space TSRMLS_CC);
867
868 if (error) {
869 zend_error(severity, "%v%s%v() expects parameter %d %s",
870 class_name, space, get_active_function_name(TSRMLS_C), arg_num, error);
871 efree(error);
872 } else {
873 zend_error(severity, "%v%s%v() expects parameter %d to be %R, %s given",
874 class_name, space, get_active_function_name(TSRMLS_C), arg_num, ret_type, expected_type,
875 zend_zval_type_name(*arg));
876 }
877 }
878 if (severity != E_STRICT) {
879 return FAILURE;
880 }
881 }
882
883 return SUCCESS;
884 }
885 /* }}} */
886
887 static int zend_parse_va_args(int num_args, char *type_spec, va_list *va, int flags TSRMLS_DC) /* {{{ */
888 {
889 char *spec_walk;
890 int c, i;
891 int min_num_args = -1;
892 int max_num_args = 0;
893 int post_varargs = 0;
894 zval **arg;
895 int arg_count;
896 int quiet = flags & ZEND_PARSE_PARAMS_QUIET;
897 zend_bool have_varargs = 0;
898 zend_bool T_present = 0;
899 char T_arg_type = -1;
900 zval ****varargs = NULL;
901 int *n_varargs = NULL;
902
903 for (spec_walk = type_spec; *spec_walk; spec_walk++) {
904 c = *spec_walk;
905 switch (c) {
906 case 'T':
907 T_present++;
908 /* break omitted intentionally */
909 case 'l': case 'd':
910 case 's': case 'b':
911 case 'r': case 'a':
912 case 'o': case 'O':
913 case 'z': case 'Z':
914 case 't': case 'u':
915 case 'C': case 'h':
916 case 'U': case 'S':
917 case 'f': case 'x':
918 max_num_args++;
919 break;
920
921 case '|':
922 min_num_args = max_num_args;
923 break;
924
925 case '/': case '!':
926 case '&': case '^':
927 /* Pass */
928 break;
929
930 case '*':
931 case '+':
932 if (have_varargs) {
933 if (!quiet) {
934 char *space;
935 zstr class_name = get_active_class_name(&space TSRMLS_CC);
936 zend_error(E_WARNING, "%v%s%v(): only one varargs specifier (* or +) is permitted",
937 class_name, space, get_active_function_name(TSRMLS_C));
938 }
939 return FAILURE;
940 }
941 have_varargs = 1;
942 /* we expect at least one parameter in varargs */
943 if (c == '+') {
944 max_num_args++;
945 }
946 /* mark the beginning of varargs */
947 post_varargs = max_num_args;