PHP Cross Reference
Main Menu
/repository/ ZendEngine2/ zend_API.c
CVS Log
CVS Blame

changes to
this file in
the last:
day
week
month
  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;