1/*
2   +----------------------------------------------------------------------+
3   | Zend Engine                                                          |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1998-2014 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$ */
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 */
36ZEND_API HashTable module_registry;
37
38static zend_module_entry **module_request_startup_handlers;
39static zend_module_entry **module_request_shutdown_handlers;
40static zend_module_entry **module_post_deactivate_handlers;
41
42static zend_class_entry  **class_cleanup_handlers;
43
44/* this function doesn't check for too many parameters */
45ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */
46{
47    int arg_count;
48    va_list ptr;
49    zval **param, *param_ptr;
50    TSRMLS_FETCH();
51
52    param_ptr = ZEND_CALL_ARG(EG(current_execute_data), 1);
53    arg_count = EG(current_execute_data)->num_args;
54
55    if (param_count>arg_count) {
56        return FAILURE;
57    }
58
59    va_start(ptr, param_count);
60
61    while (param_count-->0) {
62        param = va_arg(ptr, zval **);
63        if (!Z_ISREF_P(param_ptr) && Z_REFCOUNT_P(param_ptr) > 1) {
64            zval new_tmp;
65
66            ZVAL_DUP(&new_tmp, param_ptr);
67            Z_DELREF_P(param_ptr);
68            ZVAL_COPY_VALUE(param_ptr, &new_tmp);
69        }
70        *param = param_ptr;
71        param_ptr++;
72    }
73    va_end(ptr);
74
75    return SUCCESS;
76}
77/* }}} */
78
79/* Zend-optimized Extended functions */
80/* this function doesn't check for too many parameters */
81ZEND_API int zend_get_parameters_ex(int param_count, ...) /* {{{ */
82{
83    int arg_count;
84    va_list ptr;
85    zval **param, *param_ptr;
86    TSRMLS_FETCH();
87
88    param_ptr = ZEND_CALL_ARG(EG(current_execute_data), 1);
89    arg_count = EG(current_execute_data)->num_args;
90
91    if (param_count>arg_count) {
92        return FAILURE;
93    }
94
95    va_start(ptr, param_count);
96    while (param_count-->0) {
97        param = va_arg(ptr, zval **);
98        *param = param_ptr;
99        param_ptr++;
100    }
101    va_end(ptr);
102
103    return SUCCESS;
104}
105/* }}} */
106
107ZEND_API int _zend_get_parameters_array_ex(int param_count, zval *argument_array TSRMLS_DC) /* {{{ */
108{
109    zval *param_ptr;
110    int arg_count;
111
112    param_ptr = ZEND_CALL_ARG(EG(current_execute_data), 1);
113    arg_count = EG(current_execute_data)->num_args;
114
115    if (param_count>arg_count) {
116        return FAILURE;
117    }
118
119    while (param_count-->0) {
120        ZVAL_COPY_VALUE(argument_array, param_ptr);
121        argument_array++;
122        param_ptr++;
123    }
124
125    return SUCCESS;
126}
127/* }}} */
128
129ZEND_API int zend_copy_parameters_array(int param_count, zval *argument_array TSRMLS_DC) /* {{{ */
130{
131    zval *param_ptr;
132    int arg_count;
133
134    param_ptr = ZEND_CALL_ARG(EG(current_execute_data), 1);
135    arg_count = EG(current_execute_data)->num_args;
136
137    if (param_count>arg_count) {
138        return FAILURE;
139    }
140
141    while (param_count-->0) {
142        if (Z_REFCOUNTED_P(param_ptr)) {
143            Z_ADDREF_P(param_ptr);
144        }
145        zend_hash_next_index_insert_new(Z_ARRVAL_P(argument_array), param_ptr);
146        param_ptr++;
147    }
148
149    return SUCCESS;
150}
151/* }}} */
152
153ZEND_API void zend_wrong_param_count(TSRMLS_D) /* {{{ */
154{
155    const char *space;
156    const char *class_name = get_active_class_name(&space TSRMLS_CC);
157
158    zend_error(E_WARNING, "Wrong parameter count for %s%s%s()", class_name, space, get_active_function_name(TSRMLS_C));
159}
160/* }}} */
161
162/* Argument parsing API -- andrei */
163ZEND_API char *zend_get_type_by_const(int type) /* {{{ */
164{
165    switch(type) {
166        case IS_FALSE:
167        case IS_TRUE:
168            return "boolean";
169        case IS_LONG:
170            return "integer";
171        case IS_DOUBLE:
172            return "double";
173        case IS_STRING:
174            return "string";
175        case IS_OBJECT:
176            return "object";
177        case IS_RESOURCE:
178            return "resource";
179        case IS_NULL:
180            return "null";
181        case IS_CALLABLE:
182            return "callable";
183        case IS_ARRAY:
184            return "array";
185        default:
186            return "unknown";
187    }
188}
189/* }}} */
190
191ZEND_API char *zend_zval_type_name(const zval *arg) /* {{{ */
192{
193    ZVAL_DEREF(arg);
194    return zend_get_type_by_const(Z_TYPE_P(arg));
195}
196/* }}} */
197
198ZEND_API zend_class_entry *zend_get_class_entry(const zend_object *zobject TSRMLS_DC) /* {{{ */
199{
200    if (zobject->handlers->get_class_entry) {
201        return zobject->handlers->get_class_entry(zobject TSRMLS_CC);
202    } else {
203        zend_error(E_ERROR, "Class entry requested for an object without PHP class");
204        return NULL;
205    }
206}
207/* }}} */
208
209/* returns 1 if you need to copy result, 0 if it's already a copy */
210ZEND_API zend_string *zend_get_object_classname(const zend_object *object TSRMLS_DC) /* {{{ */
211{
212    zend_string *ret;
213
214    if (object->handlers->get_class_name != NULL) {
215        ret = object->handlers->get_class_name(object, 0 TSRMLS_CC);
216        if (ret) {
217            return ret;
218        }
219    }
220    return zend_get_class_entry(object TSRMLS_CC)->name;
221}
222/* }}} */
223
224static int parse_arg_object_to_string(zval *arg, char **p, size_t *pl, int type TSRMLS_DC) /* {{{ */
225{
226    if (Z_OBJ_HANDLER_P(arg, cast_object)) {
227        zval obj;
228        if (Z_OBJ_HANDLER_P(arg, cast_object)(arg, &obj, type TSRMLS_CC) == SUCCESS) {
229            zval_ptr_dtor(arg);
230            ZVAL_COPY_VALUE(arg, &obj);
231            *pl = Z_STRLEN_P(arg);
232            *p = Z_STRVAL_P(arg);
233            return SUCCESS;
234        }
235    }
236    /* Standard PHP objects */
237    if (Z_OBJ_HT_P(arg) == &std_object_handlers || !Z_OBJ_HANDLER_P(arg, cast_object)) {
238        SEPARATE_ZVAL_NOREF(arg);
239        if (zend_std_cast_object_tostring(arg, arg, type TSRMLS_CC) == SUCCESS) {
240            *pl = Z_STRLEN_P(arg);
241            *p = Z_STRVAL_P(arg);
242            return SUCCESS;
243        }
244    }
245    if (!Z_OBJ_HANDLER_P(arg, cast_object) && Z_OBJ_HANDLER_P(arg, get)) {
246        zval rv;
247        zval *z = Z_OBJ_HANDLER_P(arg, get)(arg, &rv TSRMLS_CC);
248        Z_ADDREF_P(z);
249        if(Z_TYPE_P(z) != IS_OBJECT) {
250            zval_dtor(arg);
251            ZVAL_NULL(arg);
252            if (!zend_make_printable_zval(z, arg TSRMLS_CC)) {
253                ZVAL_ZVAL(arg, z, 1, 1);
254            }
255            *pl = Z_STRLEN_P(arg);
256            *p = Z_STRVAL_P(arg);
257            return SUCCESS;
258        }
259        zval_ptr_dtor(z);
260    }
261    return FAILURE;
262}
263/* }}} */
264
265ZEND_API int parse_arg_object_to_str(zval *arg, zend_string **str, int type TSRMLS_DC) /* {{{ */
266{
267    if (Z_OBJ_HANDLER_P(arg, cast_object)) {
268        zval obj;
269        if (Z_OBJ_HANDLER_P(arg, cast_object)(arg, &obj, type TSRMLS_CC) == SUCCESS) {
270            zval_ptr_dtor(arg);
271            ZVAL_COPY_VALUE(arg, &obj);
272            *str = Z_STR_P(arg);
273            return SUCCESS;
274        }
275    }
276    /* Standard PHP objects */
277    if (Z_OBJ_HT_P(arg) == &std_object_handlers || !Z_OBJ_HANDLER_P(arg, cast_object)) {
278        SEPARATE_ZVAL_NOREF(arg);
279        if (zend_std_cast_object_tostring(arg, arg, type TSRMLS_CC) == SUCCESS) {
280            *str = Z_STR_P(arg);
281            return SUCCESS;
282        }
283    }
284    if (!Z_OBJ_HANDLER_P(arg, cast_object) && Z_OBJ_HANDLER_P(arg, get)) {
285        zval rv;
286        zval *z = Z_OBJ_HANDLER_P(arg, get)(arg, &rv TSRMLS_CC);
287        Z_ADDREF_P(z);
288        if(Z_TYPE_P(z) != IS_OBJECT) {
289            zval_dtor(arg);
290            ZVAL_NULL(arg);
291            if (!zend_make_printable_zval(z, arg TSRMLS_CC)) {
292                ZVAL_ZVAL(arg, z, 1, 1);
293            }
294            *str = Z_STR_P(arg);
295            return SUCCESS;
296        }
297        zval_ptr_dtor(z);
298    }
299    return FAILURE;
300}
301/* }}} */
302
303#ifdef FAST_ZPP
304ZEND_API void zend_wrong_paramers_count_error(int num_args, int min_num_args, int max_num_args TSRMLS_DC) /* {{{ */
305{
306    zend_function *active_function = EG(current_execute_data)->func;
307    const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : "";
308
309    zend_error(E_WARNING, "%s%s%s() expects %s %d parameter%s, %d given",
310        class_name, \
311        class_name[0] ? "::" : "", \
312        active_function->common.function_name->val,
313        min_num_args == max_num_args ? "exactly" : num_args < min_num_args ? "at least" : "at most",
314        num_args < min_num_args ? min_num_args : max_num_args,
315        (num_args < min_num_args ? min_num_args : max_num_args) == 1 ? "" : "s",
316        num_args);
317}
318/* }}} */
319
320ZEND_API void zend_wrong_paramer_type_error(int num, zend_expected_type expected_type, zval *arg TSRMLS_DC) /* {{{ */
321{
322    const char *space;
323    const char *class_name = get_active_class_name(&space TSRMLS_CC);
324    static const char * const expected_error[] = {
325        Z_EXPECTED_TYPES(Z_EXPECTED_TYPE_STR)
326        NULL
327    };
328
329    zend_error(E_WARNING, "%s%s%s() expects parameter %d to be %s, %s given",
330        class_name, space, get_active_function_name(TSRMLS_C), num, expected_error[expected_type], zend_zval_type_name(arg));
331}
332/* }}} */
333
334ZEND_API void zend_wrong_paramer_class_error(int num, char *name, zval *arg TSRMLS_DC) /* {{{ */
335{
336    const char *space;
337    const char *class_name = get_active_class_name(&space TSRMLS_CC);
338
339    zend_error(E_WARNING, "%s%s%s() expects parameter %d to be %s, %s given",
340        class_name, space, get_active_function_name(TSRMLS_C), num, name, zend_zval_type_name(arg));
341}
342/* }}} */
343
344ZEND_API void zend_wrong_callback_error(int severity, int num, char *error TSRMLS_DC) /* {{{ */
345{
346    const char *space;
347    const char *class_name = get_active_class_name(&space TSRMLS_CC);
348
349    zend_error(severity, "%s%s%s() expects parameter %d to be a valid callback, %s",
350        class_name, space, get_active_function_name(TSRMLS_C), num, error);
351    efree(error);
352}
353/* }}} */
354
355ZEND_API int _z_param_class(zval *arg, zend_class_entry **pce, int num, int check_null TSRMLS_DC) /* {{{ */
356{
357    zend_class_entry *ce_base = *pce;
358
359    if (check_null && Z_TYPE_P(arg) == IS_NULL) {
360        *pce = NULL;
361        return 1;
362    }
363    convert_to_string_ex(arg);
364    *pce = zend_lookup_class(Z_STR_P(arg) TSRMLS_CC);
365    if (ce_base) {
366        if ((!*pce || !instanceof_function(*pce, ce_base TSRMLS_CC))) {
367            const char *space;
368            const char *class_name = get_active_class_name(&space TSRMLS_CC);
369
370            zend_error(E_WARNING, "%s%s%s() expects parameter %d to be a class name derived from %s, '%s' given",
371                class_name, space, get_active_function_name(TSRMLS_C), num,
372                ce_base->name->val, Z_STRVAL_P(arg));
373            *pce = NULL;
374            return 0;
375        }
376    }
377    if (!*pce) {
378        const char *space;
379        const char *class_name = get_active_class_name(&space TSRMLS_CC);
380
381        zend_error(E_WARNING, "%s%s%s() expects parameter %d to be a valid class name, '%s' given",
382            class_name, space, get_active_function_name(TSRMLS_C), num,
383            Z_STRVAL_P(arg));
384        return 0;
385    }
386    return 1;
387}
388/* }}} */
389#endif
390
391static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, const char **spec, char **error, int *severity TSRMLS_DC) /* {{{ */
392{
393    const char *spec_walk = *spec;
394    char c = *spec_walk++;
395    int check_null = 0;
396    zval *real_arg = arg;
397
398    /* scan through modifiers */
399    ZVAL_DEREF(arg);
400    while (1) {
401        if (*spec_walk == '/') {
402            SEPARATE_ZVAL(arg);
403            real_arg = arg;
404        } else if (*spec_walk == '!') {
405            check_null = 1;
406        } else {
407            break;
408        }
409        spec_walk++;
410    }
411
412    switch (c) {
413        case 'l':
414        case 'L':
415            {
416                zend_long *p = va_arg(*va, zend_long *);
417
418                if (check_null) {
419                    zend_bool *p = va_arg(*va, zend_bool *);
420                    *p = (Z_TYPE_P(arg) == IS_NULL);
421                }
422
423                switch (Z_TYPE_P(arg)) {
424                    case IS_STRING:
425                        {
426                            double d;
427                            int type;
428
429                            if ((type = is_numeric_string(Z_STRVAL_P(arg), Z_STRLEN_P(arg), p, &d, -1)) == 0) {
430                                return "long";
431                            } else if (type == IS_DOUBLE) {
432                                if (c == 'L') {
433                                    if (d > ZEND_LONG_MAX) {
434                                        *p = ZEND_LONG_MAX;
435                                        break;
436                                    } else if (d < ZEND_LONG_MIN) {
437                                        *p = ZEND_LONG_MIN;
438                                        break;
439                                    }
440                                }
441
442                                *p = zend_dval_to_lval(d);
443                            }
444                        }
445                        break;
446
447                    case IS_DOUBLE:
448                        if (c == 'L') {
449                            if (Z_DVAL_P(arg) > ZEND_LONG_MAX) {
450                                *p = ZEND_LONG_MAX;
451                                break;
452                            } else if (Z_DVAL_P(arg) < ZEND_LONG_MIN) {
453                                *p = ZEND_LONG_MIN;
454                                break;
455                            }
456                        }
457                    case IS_NULL:
458                    case IS_FALSE:
459                    case IS_TRUE:
460                    case IS_LONG:
461                        convert_to_long_ex(arg);
462                        *p = Z_LVAL_P(arg);
463                        break;
464
465                    case IS_ARRAY:
466                    case IS_OBJECT:
467                    case IS_RESOURCE:
468                    default:
469                        return "long";
470                }
471            }
472            break;
473
474        case 'd':
475            {
476                double *p = va_arg(*va, double *);
477
478                if (check_null) {
479                    zend_bool *p = va_arg(*va, zend_bool *);
480                    *p = (Z_TYPE_P(arg) == IS_NULL);
481                }
482
483                switch (Z_TYPE_P(arg)) {
484                    case IS_STRING:
485                        {
486                            zend_long l;
487                            int type;
488
489                            if ((type = is_numeric_string(Z_STRVAL_P(arg), Z_STRLEN_P(arg), &l, p, -1)) == 0) {
490                                return "double";
491                            } else if (type == IS_LONG) {
492                                *p = (double) l;
493                            }
494                        }
495                        break;
496
497                    case IS_NULL:
498                    case IS_FALSE:
499                    case IS_TRUE:
500                    case IS_LONG:
501                    case IS_DOUBLE:
502                        convert_to_double_ex(arg);
503                        *p = Z_DVAL_P(arg);
504                        break;
505
506                    case IS_ARRAY:
507                    case IS_OBJECT:
508                    case IS_RESOURCE:
509                    default:
510                        return "double";
511                }
512            }
513            break;
514
515        case 'p':
516        case 's':
517            {
518                char **p = va_arg(*va, char **);
519                size_t *pl = va_arg(*va, size_t *);
520                switch (Z_TYPE_P(arg)) {
521                    case IS_NULL:
522                        if (check_null) {
523                            *p = NULL;
524                            *pl = 0;
525                            break;
526                        }
527                        /* break omitted intentionally */
528
529                    case IS_LONG:
530                    case IS_DOUBLE:
531                    case IS_FALSE:
532                    case IS_TRUE:
533                        convert_to_string_ex(arg);
534                    case IS_STRING:
535                        *p = Z_STRVAL_P(arg);
536                        *pl = Z_STRLEN_P(arg);
537                        if (c == 'p' && CHECK_ZVAL_NULL_PATH(arg)) {
538                            return "a valid path";
539                        }
540                        break;
541
542                    case IS_OBJECT:
543                        if (parse_arg_object_to_string(arg, p, pl, IS_STRING TSRMLS_CC) == SUCCESS) {
544                            if (c == 'p' && CHECK_ZVAL_NULL_PATH(arg)) {
545                                return "a valid path";
546                            }
547                            break;
548                        }
549
550                    case IS_ARRAY:
551                    case IS_RESOURCE:
552                    default:
553                        return c == 's' ? "string" : "a valid path";
554                }
555            }
556            break;
557
558        case 'P':
559        case 'S':
560            {
561                zend_string **str = va_arg(*va, zend_string **);
562                switch (Z_TYPE_P(arg)) {
563                    case IS_NULL:
564                        if (check_null) {
565                            *str = NULL;
566                            break;
567                        }
568                        /* break omitted intentionally */
569
570                    case IS_LONG:
571                    case IS_DOUBLE:
572                    case IS_FALSE:
573                    case IS_TRUE:
574                        convert_to_string_ex(arg);
575                    case IS_STRING:
576                        *str = Z_STR_P(arg);
577                        if (c == 'P' && CHECK_ZVAL_NULL_PATH(arg)) {
578                            return "a valid path";
579                        }
580                        break;
581
582                    case IS_OBJECT: {
583                        if (parse_arg_object_to_str(arg, str, IS_STRING TSRMLS_CC) == SUCCESS) {
584                            if (c == 'P' && CHECK_ZVAL_NULL_PATH(arg)) {
585                                return "a valid path";
586                            }
587                            break;
588                        }
589                    }
590                    case IS_ARRAY:
591                    case IS_RESOURCE:
592                    default:
593                        return c == 'S' ? "string" : "a valid path";
594                }
595            }
596            break;
597
598        case 'b':
599            {
600                zend_bool *p = va_arg(*va, zend_bool *);
601
602                if (check_null) {
603                    zend_bool *p = va_arg(*va, zend_bool *);
604                    *p = (Z_TYPE_P(arg) == IS_NULL);
605                }
606
607                switch (Z_TYPE_P(arg)) {
608                    case IS_NULL:
609                    case IS_STRING:
610                    case IS_LONG:
611                    case IS_DOUBLE:
612                    case IS_FALSE:
613                    case IS_TRUE:
614                        convert_to_boolean_ex(arg);
615                        *p = Z_TYPE_P(arg) == IS_TRUE;
616                        break;
617
618                    case IS_ARRAY:
619                    case IS_OBJECT:
620                    case IS_RESOURCE:
621                    default:
622                        return "boolean";
623                }
624            }
625            break;
626
627        case 'r':
628            {
629                zval **p = va_arg(*va, zval **);
630                if (check_null && Z_TYPE_P(arg) == IS_NULL) {
631                    *p = NULL;
632                    break;
633                }
634                if (Z_TYPE_P(arg) == IS_RESOURCE) {
635                    *p = arg;
636                } else {
637                    return "resource";
638                }
639            }
640            break;
641        case 'A':
642        case 'a':
643            {
644                zval **p = va_arg(*va, zval **);
645                if (check_null && Z_TYPE_P(arg) == IS_NULL) {
646                    *p = NULL;
647                    break;
648                }
649                if (Z_TYPE_P(arg) == IS_ARRAY || (c == 'A' && Z_TYPE_P(arg) == IS_OBJECT)) {
650                    *p = arg;
651                } else {
652                    return "array";
653                }
654            }
655            break;
656        case 'H':
657        case 'h':
658            {
659                HashTable **p = va_arg(*va, HashTable **);
660                if (check_null && Z_TYPE_P(arg) == IS_NULL) {
661                    *p = NULL;
662                    break;
663                }
664                if (Z_TYPE_P(arg) == IS_ARRAY) {
665                    *p = Z_ARRVAL_P(arg);
666                } else if(c == 'H' && Z_TYPE_P(arg) == IS_OBJECT) {
667                    *p = HASH_OF(arg);
668                    if(*p == NULL) {
669                        return "array";
670                    }
671                } else {
672                    return "array";
673                }
674            }
675            break;
676
677        case 'o':
678            {
679                zval **p = va_arg(*va, zval **);
680                if (check_null && Z_TYPE_P(arg) == IS_NULL) {
681                    *p = NULL;
682                    break;
683                }
684                if (Z_TYPE_P(arg) == IS_OBJECT) {
685                    *p = arg;
686                } else {
687                    return "object";
688                }
689            }
690            break;
691
692        case 'O':
693            {
694                zval **p = va_arg(*va, zval **);
695                zend_class_entry *ce = va_arg(*va, zend_class_entry *);
696
697                if (check_null && Z_TYPE_P(arg) == IS_NULL) {
698                    *p = NULL;
699                    break;
700                }
701                if (Z_TYPE_P(arg) == IS_OBJECT &&
702                        (!ce || instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC))) {
703                    *p = arg;
704                } else {
705                    if (ce) {
706                        return ce->name->val;
707                    } else {
708                        return "object";
709                    }
710                }
711            }
712            break;
713
714        case 'C':
715            {
716                zend_class_entry *lookup, **pce = va_arg(*va, zend_class_entry **);
717                zend_class_entry *ce_base = *pce;
718
719                if (check_null && Z_TYPE_P(arg) == IS_NULL) {
720                    *pce = NULL;
721                    break;
722                }
723                convert_to_string_ex(arg);
724                if ((lookup = zend_lookup_class(Z_STR_P(arg) TSRMLS_CC)) == NULL) {
725                    *pce = NULL;
726                } else {
727                    *pce = lookup;
728                }
729                if (ce_base) {
730                    if ((!*pce || !instanceof_function(*pce, ce_base TSRMLS_CC))) {
731                        zend_spprintf(error, 0, "to be a class name derived from %s, '%s' given",
732                            ce_base->name->val, Z_STRVAL_P(arg));
733                        *pce = NULL;
734                        return "";
735                    }
736                }
737                if (!*pce) {
738                    zend_spprintf(error, 0, "to be a valid class name, '%s' given",
739                        Z_STRVAL_P(arg));
740                    return "";
741                }
742                break;
743
744            }
745            break;
746
747        case 'f':
748            {
749                zend_fcall_info *fci = va_arg(*va, zend_fcall_info *);
750                zend_fcall_info_cache *fcc = va_arg(*va, zend_fcall_info_cache *);
751                char *is_callable_error = NULL;
752
753                if (check_null && Z_TYPE_P(arg) == IS_NULL) {
754                    fci->size = 0;
755                    fcc->initialized = 0;
756                    break;
757                }
758
759                if (zend_fcall_info_init(arg, 0, fci, fcc, NULL, &is_callable_error TSRMLS_CC) == SUCCESS) {
760                    if (is_callable_error) {
761                        *severity = E_STRICT;
762                        zend_spprintf(error, 0, "to be a valid callback, %s", is_callable_error);
763                        efree(is_callable_error);
764                        *spec = spec_walk;
765                        return "";
766                    }
767                    break;
768                } else {
769                    if (is_callable_error) {
770                        *severity = E_WARNING;
771                        zend_spprintf(error, 0, "to be a valid callback, %s", is_callable_error);
772                        efree(is_callable_error);
773                        return "";
774                    } else {
775                        return "valid callback";
776                    }
777                }
778            }
779
780        case 'z':
781            {
782                zval **p = va_arg(*va, zval **);
783                if (check_null && Z_TYPE_P(arg) == IS_NULL) {
784                    *p = NULL;
785                } else {
786                    *p = real_arg;
787                }
788            }
789            break;
790
791        case 'Z':
792            /* 'Z' iz not supported anymore and should be replaced with 'z' */
793            ZEND_ASSERT(c != 'Z');
794        default:
795            return "unknown";
796    }
797
798    *spec = spec_walk;
799
800    return NULL;
801}
802/* }}} */
803
804static int zend_parse_arg(int arg_num, zval *arg, va_list *va, const char **spec, int quiet TSRMLS_DC) /* {{{ */
805{
806    const char *expected_type = NULL;
807    char *error = NULL;
808    int severity = E_WARNING;
809
810    expected_type = zend_parse_arg_impl(arg_num, arg, va, spec, &error, &severity TSRMLS_CC);
811    if (expected_type) {
812        if (!quiet && (*expected_type || error)) {
813            const char *space;
814            const char *class_name = get_active_class_name(&space TSRMLS_CC);
815
816            if (error) {
817                zend_error(severity, "%s%s%s() expects parameter %d %s",
818                        class_name, space, get_active_function_name(TSRMLS_C), arg_num, error);
819                efree(error);
820            } else {
821                zend_error(severity, "%s%s%s() expects parameter %d to be %s, %s given",
822                        class_name, space, get_active_function_name(TSRMLS_C), arg_num, expected_type,
823                        zend_zval_type_name(arg));
824            }
825        }
826        if (severity != E_STRICT) {
827            return FAILURE;
828        }
829    }
830
831    return SUCCESS;
832}
833/* }}} */
834
835ZEND_API int zend_parse_parameter(int flags, int arg_num TSRMLS_DC, zval *arg, const char *spec, ...)
836{
837    va_list va;
838    int ret;
839    int quiet = flags & ZEND_PARSE_PARAMS_QUIET;
840
841    va_start(va, spec);
842    ret = zend_parse_arg(arg_num, arg, &va, &spec, quiet TSRMLS_CC);
843    va_end(va);
844
845    return ret;
846}
847
848static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, int flags TSRMLS_DC) /* {{{ */
849{
850    const  char *spec_walk;
851    int c, i;
852    int min_num_args = -1;
853    int max_num_args = 0;
854    int post_varargs = 0;
855    zval *arg;
856    int arg_count;
857    int quiet = flags & ZEND_PARSE_PARAMS_QUIET;
858    zend_bool have_varargs = 0;
859    zval **varargs = NULL;
860    int *n_varargs = NULL;
861
862    for (spec_walk = type_spec; *spec_walk; spec_walk++) {
863        c = *spec_walk;
864        switch (c) {
865            case 'l': case 'd':
866            case 's': case 'b':
867            case 'r': case 'a':
868            case 'o': case 'O':
869            case 'z': case 'Z':
870            case 'C': case 'h':
871            case 'f': case 'A':
872            case 'H': case 'p':
873            case 'S': case 'P':
874            case 'L':
875                max_num_args++;
876                break;
877
878            case '|':
879                min_num_args = max_num_args;
880                break;
881
882            case '/':
883            case '!':
884                /* Pass */
885                break;
886
887            case '*':
888            case '+':
889                if (have_varargs) {
890                    if (!quiet) {
891                        zend_function *active_function = EG(current_execute_data)->func;
892                        const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : "";
893                        zend_error(E_WARNING, "%s%s%s(): only one varargs specifier (* or +) is permitted",
894                                class_name,
895                                class_name[0] ? "::" : "",
896                                active_function->common.function_name->val);
897                    }
898                    return FAILURE;
899                }
900                have_varargs = 1;
901                /* we expect at least one parameter in varargs */
902                if (c == '+') {
903                    max_num_args++;
904                }
905                /* mark the beginning of varargs */
906                post_varargs = max_num_args;
907                break;
908
909            default:
910                if (!quiet) {
911                    zend_function *active_function = EG(current_execute_data)->func;
912                    const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : "";
913                    zend_error(E_WARNING, "%s%s%s(): bad type specifier while parsing parameters",
914                            class_name,
915                            class_name[0] ? "::" : "",
916                            active_function->common.function_name->val);
917                }
918                return FAILURE;
919        }
920    }
921
922    if (min_num_args < 0) {
923        min_num_args = max_num_args;
924    }
925
926    if (have_varargs) {
927        /* calculate how many required args are at the end of the specifier list */
928        post_varargs = max_num_args - post_varargs;
929        max_num_args = -1;
930    }
931
932    if (num_args < min_num_args || (num_args > max_num_args && max_num_args > 0)) {
933        if (!quiet) {
934            zend_function *active_function = EG(current_execute_data)->func;
935            const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : "";
936            zend_error(E_WARNING, "%s%s%s() expects %s %d parameter%s, %d given",
937                    class_name,
938                    class_name[0] ? "::" : "",
939                    active_function->common.function_name->val,
940                    min_num_args == max_num_args ? "exactly" : num_args < min_num_args ? "at least" : "at most",
941                    num_args < min_num_args ? min_num_args : max_num_args,
942                    (num_args < min_num_args ? min_num_args : max_num_args) == 1 ? "" : "s",
943                    num_args);
944        }
945        return FAILURE;
946    }
947
948    arg_count = EG(current_execute_data)->num_args;
949
950    if (num_args > arg_count) {
951        zend_error(E_WARNING, "%s(): could not obtain parameters for parsing",
952            get_active_function_name(TSRMLS_C));
953        return FAILURE;
954    }
955
956    i = 0;
957    while (num_args-- > 0) {
958        if (*type_spec == '|') {
959            type_spec++;
960        }
961
962        if (*type_spec == '*' || *type_spec == '+') {
963            int num_varargs = num_args + 1 - post_varargs;
964
965            /* eat up the passed in storage even if it won't be filled in with varargs */
966            varargs = va_arg(*va, zval **);
967            n_varargs = va_arg(*va, int *);
968            type_spec++;
969
970            if (num_varargs > 0) {
971                *n_varargs = num_varargs;
972                *varargs = ZEND_CALL_ARG(EG(current_execute_data), i + 1);
973                /* adjust how many args we have left and restart loop */
974                num_args += 1 - num_varargs;
975                i += num_varargs;
976                continue;
977            } else {
978                *varargs = NULL;
979                *n_varargs = 0;
980            }
981        }
982
983        arg = ZEND_CALL_ARG(EG(current_execute_data), i + 1);
984
985        if (zend_parse_arg(i+1, arg, va, &type_spec, quiet TSRMLS_CC) == FAILURE) {
986            /* clean up varargs array if it was used */
987            if (varargs && *varargs) {
988                *varargs = NULL;
989            }
990            return FAILURE;
991        }
992        i++;
993    }
994
995    return SUCCESS;
996}
997/* }}} */
998
999#define RETURN_IF_ZERO_ARGS(num_args, type_spec, quiet) { \
1000    int __num_args = (num_args); \
1001    \
1002    if (0 == (type_spec)[0] && 0 != __num_args && !(quiet)) { \
1003        const char *__space; \
1004        const char * __class_name = get_active_class_name(&__space TSRMLS_CC); \
1005        zend_error(E_WARNING, "%s%s%s() expects exactly 0 parameters, %d given", \
1006            __class_name, __space, \
1007            get_active_function_name(TSRMLS_C), __num_args); \
1008        return FAILURE; \
1009    }\
1010}
1011
1012ZEND_API int zend_parse_parameters_ex(int flags, int num_args TSRMLS_DC, const char *type_spec, ...) /* {{{ */
1013{
1014    va_list va;
1015    int retval;
1016
1017    RETURN_IF_ZERO_ARGS(num_args, type_spec, flags & ZEND_PARSE_PARAMS_QUIET);
1018
1019    va_start(va, type_spec);
1020    retval = zend_parse_va_args(num_args, type_spec, &va, flags TSRMLS_CC);
1021    va_end(va);
1022
1023    return retval;
1024}
1025/* }}} */
1026
1027ZEND_API int zend_parse_parameters(int num_args TSRMLS_DC, const char *type_spec, ...) /* {{{ */
1028{
1029    va_list va;
1030    int retval;
1031
1032    RETURN_IF_ZERO_ARGS(num_args, type_spec, 0);
1033
1034    va_start(va, type_spec);
1035    retval = zend_parse_va_args(num_args, type_spec, &va, 0 TSRMLS_CC);
1036    va_end(va);
1037
1038    return retval;
1039}
1040/* }}} */
1041
1042ZEND_API int zend_parse_method_parameters(int num_args TSRMLS_DC, zval *this_ptr, const char *type_spec, ...) /* {{{ */
1043{
1044    va_list va;
1045    int retval;
1046    const char *p = type_spec;
1047    zval **object;
1048    zend_class_entry *ce;
1049
1050    /* Just checking this_ptr is not enough, because fcall_common_helper does not set
1051     * Z_OBJ(EG(This)) to NULL when calling an internal function with common.scope == NULL.
1052     * In that case EG(This) would still be the $this from the calling code and we'd take the
1053     * wrong branch here. */
1054    zend_bool is_method = EG(current_execute_data)->func->common.scope != NULL;
1055    if (!is_method || !this_ptr || Z_TYPE_P(this_ptr) != IS_OBJECT) {
1056        RETURN_IF_ZERO_ARGS(num_args, p, 0);
1057
1058        va_start(va, type_spec);
1059        retval = zend_parse_va_args(num_args, type_spec, &va, 0 TSRMLS_CC);
1060        va_end(va);
1061    } else {
1062        p++;
1063        RETURN_IF_ZERO_ARGS(num_args, p, 0);
1064
1065        va_start(va, type_spec);
1066
1067        object = va_arg(va, zval **);
1068        ce = va_arg(va, zend_class_entry *);
1069        *object = this_ptr;
1070
1071        if (ce && !instanceof_function(Z_OBJCE_P(this_ptr), ce TSRMLS_CC)) {
1072            zend_error(E_CORE_ERROR, "%s::%s() must be derived from %s::%s",
1073                Z_OBJCE_P(this_ptr)->name->val, get_active_function_name(TSRMLS_C), ce->name->val, get_active_function_name(TSRMLS_C));
1074        }
1075
1076        retval = zend_parse_va_args(num_args, p, &va, 0 TSRMLS_CC);
1077        va_end(va);
1078    }
1079    return retval;
1080}
1081/* }}} */
1082
1083ZEND_API int zend_parse_method_parameters_ex(int flags, int num_args TSRMLS_DC, zval *this_ptr, const char *type_spec, ...) /* {{{ */
1084{
1085    va_list va;
1086    int retval;
1087    const char *p = type_spec;
1088    zval **object;
1089    zend_class_entry *ce;
1090    int quiet = flags & ZEND_PARSE_PARAMS_QUIET;
1091
1092    if (!this_ptr) {
1093        RETURN_IF_ZERO_ARGS(num_args, p, quiet);
1094
1095        va_start(va, type_spec);
1096        retval = zend_parse_va_args(num_args, type_spec, &va, flags TSRMLS_CC);
1097        va_end(va);
1098    } else {
1099        p++;
1100        RETURN_IF_ZERO_ARGS(num_args, p, quiet);
1101
1102        va_start(va, type_spec);
1103
1104        object = va_arg(va, zval **);
1105        ce = va_arg(va, zend_class_entry *);
1106        *object = this_ptr;
1107
1108        if (ce && !instanceof_function(Z_OBJCE_P(this_ptr), ce TSRMLS_CC)) {
1109            if (!quiet) {
1110                zend_error(E_CORE_ERROR, "%s::%s() must be derived from %s::%s",
1111                    ce->name->val, get_active_function_name(TSRMLS_C), Z_OBJCE_P(this_ptr)->name->val, get_active_function_name(TSRMLS_C));
1112            }
1113            va_end(va);
1114            return FAILURE;
1115        }
1116
1117        retval = zend_parse_va_args(num_args, p, &va, flags TSRMLS_CC);
1118        va_end(va);
1119    }
1120    return retval;
1121}
1122/* }}} */
1123
1124/* Argument parsing API -- andrei */
1125ZEND_API int _array_init(zval *arg, uint size ZEND_FILE_LINE_DC) /* {{{ */
1126{
1127    ZVAL_NEW_ARR(arg);
1128    _zend_hash_init(Z_ARRVAL_P(arg), size, ZVAL_PTR_DTOR, 0 ZEND_FILE_LINE_RELAY_CC);
1129    return SUCCESS;
1130}
1131/* }}} */
1132
1133/* This function should be called after the constructor has been called
1134 * because it may call __set from the uninitialized object otherwise. */
1135ZEND_API void zend_merge_properties(zval *obj, HashTable *properties TSRMLS_DC) /* {{{ */
1136{
1137    const zend_object_handlers *obj_ht = Z_OBJ_HT_P(obj);
1138    zend_class_entry *old_scope = EG(scope);
1139    zend_string *key;
1140    zval *value;
1141
1142    EG(scope) = Z_OBJCE_P(obj);
1143    ZEND_HASH_FOREACH_STR_KEY_VAL(properties, key, value) {
1144        if (key) {
1145            zval member;
1146
1147            ZVAL_STR(&member, zend_string_copy(key));
1148            obj_ht->write_property(obj, &member, value, NULL TSRMLS_CC);
1149            zval_ptr_dtor(&member);
1150        }
1151    } ZEND_HASH_FOREACH_END();
1152    EG(scope) = old_scope;
1153}
1154/* }}} */
1155
1156static int zval_update_class_constant(zval *pp, int is_static, int offset TSRMLS_DC) /* {{{ */
1157{
1158    ZVAL_DEREF(pp);
1159    if (Z_CONSTANT_P(pp)) {
1160        zend_class_entry **scope = EG(current_execute_data) ? &EG(scope) : &CG(active_class_entry);
1161
1162        if ((*scope)->parent) {
1163            zend_class_entry *ce = *scope;
1164            zend_property_info *prop_info;
1165
1166            do {
1167                ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) {
1168                    if (is_static == ((prop_info->flags & ZEND_ACC_STATIC) != 0) &&
1169                        offset == prop_info->offset) {
1170                        int ret;
1171                        zend_class_entry *old_scope = *scope;
1172                        *scope = prop_info->ce;
1173                        ret = zval_update_constant(pp, 1 TSRMLS_CC);
1174                        *scope = old_scope;
1175                        return ret;
1176                    }
1177                } ZEND_HASH_FOREACH_END();
1178                ce = ce->parent;
1179            } while (ce);
1180
1181        }
1182        return zval_update_constant(pp, 1 TSRMLS_CC);
1183    }
1184    return 0;
1185}
1186/* }}} */
1187
1188ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
1189{
1190    int i;
1191
1192    /* initialize static members of internal class */
1193    if (!CE_STATIC_MEMBERS(class_type) && class_type->default_static_members_count) {
1194        zval *p;
1195
1196        if (class_type->parent) {
1197            zend_update_class_constants(class_type->parent TSRMLS_CC);
1198        }
1199#if ZTS
1200        CG(static_members_table)[(zend_intptr_t)(class_type->static_members_table)] = emalloc(sizeof(zval*) * class_type->default_static_members_count);
1201#else
1202        class_type->static_members_table = emalloc(sizeof(zval*) * class_type->default_static_members_count);
1203#endif
1204        for (i = 0; i < class_type->default_static_members_count; i++) {
1205            p = &class_type->default_static_members_table[i];
1206            if (Z_ISREF_P(p) &&
1207                class_type->parent &&
1208                i < class_type->parent->default_static_members_count &&
1209                p == &class_type->parent->default_static_members_table[i] &&
1210                Z_TYPE(CE_STATIC_MEMBERS(class_type->parent)[i]) != IS_UNDEF
1211            ) {
1212                zval *q = &CE_STATIC_MEMBERS(class_type->parent)[i];
1213
1214                ZVAL_NEW_REF(q, q);
1215                ZVAL_COPY_VALUE(&CE_STATIC_MEMBERS(class_type)[i], q);
1216                Z_ADDREF_P(q);
1217            } else {
1218                ZVAL_DUP(&CE_STATIC_MEMBERS(class_type)[i], p);
1219            }
1220        }
1221    }
1222
1223    if ((class_type->ce_flags & ZEND_ACC_CONSTANTS_UPDATED) == 0) {
1224        zend_class_entry **scope = EG(current_execute_data) ? &EG(scope) : &CG(active_class_entry);
1225        zend_class_entry *old_scope = *scope;
1226        zval *val;
1227
1228        *scope = class_type;
1229
1230        ZEND_HASH_FOREACH_VAL(&class_type->constants_table, val) {
1231            zval_update_constant(val, 1 TSRMLS_CC);
1232        } ZEND_HASH_FOREACH_END();
1233
1234        for (i = 0; i < class_type->default_properties_count; i++) {
1235            if (Z_TYPE(class_type->default_properties_table[i]) != IS_UNDEF) {
1236                zval_update_class_constant(&class_type->default_properties_table[i], 0, i TSRMLS_CC);
1237            }
1238        }
1239
1240        for (i = 0; i < class_type->default_static_members_count; i++) {
1241            zval_update_class_constant(&CE_STATIC_MEMBERS(class_type)[i], 1, i TSRMLS_CC);
1242        }
1243
1244        *scope = old_scope;
1245        class_type->ce_flags |= ZEND_ACC_CONSTANTS_UPDATED;
1246    }
1247}
1248/* }}} */
1249
1250ZEND_API void object_properties_init(zend_object *object, zend_class_entry *class_type) /* {{{ */
1251{
1252    int i;
1253
1254    if (class_type->default_properties_count) {
1255        for (i = 0; i < class_type->default_properties_count; i++) {
1256#if ZTS
1257            ZVAL_DUP(&object->properties_table[i], &class_type->default_properties_table[i]);
1258#else
1259            ZVAL_COPY(&object->properties_table[i], &class_type->default_properties_table[i]);
1260#endif
1261        }
1262        object->properties = NULL;
1263    }
1264}
1265/* }}} */
1266
1267ZEND_API void object_properties_init_ex(zend_object *object, HashTable *properties TSRMLS_DC) /* {{{ */
1268{
1269    object->properties = properties;
1270    if (object->ce->default_properties_count) {
1271        zval *prop, tmp;
1272        zend_string *key;
1273        zend_property_info *property_info;
1274
1275        ZEND_HASH_FOREACH_STR_KEY_VAL(properties, key, prop) {
1276            ZVAL_STR(&tmp, key);
1277            property_info = zend_get_property_info(object->ce, &tmp, 1 TSRMLS_CC);
1278            if (property_info &&
1279                (property_info->flags & ZEND_ACC_STATIC) == 0 &&
1280                property_info->offset >= 0) {
1281                ZVAL_COPY_VALUE(&object->properties_table[property_info->offset], prop);
1282                ZVAL_INDIRECT(prop, &object->properties_table[property_info->offset]);
1283            }
1284        } ZEND_HASH_FOREACH_END();
1285    }
1286}
1287/* }}} */
1288
1289ZEND_API void object_properties_load(zend_object *object, HashTable *properties TSRMLS_DC) /* {{{ */
1290{
1291    zval *prop, tmp;
1292    zend_string *key;
1293    zend_property_info *property_info;
1294
1295    ZEND_HASH_FOREACH_STR_KEY_VAL(properties, key, prop) {
1296        ZVAL_STR(&tmp, key);
1297        property_info = zend_get_property_info(object->ce, &tmp, 1 TSRMLS_CC);
1298        if (property_info &&
1299            (property_info->flags & ZEND_ACC_STATIC) == 0 &&
1300            property_info->offset >= 0) {
1301            zval_ptr_dtor(&object->properties_table[property_info->offset]);
1302            ZVAL_COPY_VALUE(&object->properties_table[property_info->offset], prop);
1303            zval_add_ref(&object->properties_table[property_info->offset]);
1304            if (object->properties) {
1305                ZVAL_INDIRECT(&tmp, &object->properties_table[property_info->offset]);
1306                prop = zend_hash_update(object->properties, key, &tmp);
1307            }
1308        } else {
1309            if (!object->properties) {
1310                rebuild_object_properties(object);
1311            }
1312            prop = zend_hash_update(object->properties, key, prop);
1313            zval_add_ref(prop);
1314        }
1315    } ZEND_HASH_FOREACH_END();
1316}
1317/* }}} */
1318
1319/* This function requires 'properties' to contain all props declared in the
1320 * class and all props being public. If only a subset is given or the class
1321 * has protected members then you need to merge the properties separately by
1322 * calling zend_merge_properties(). */
1323ZEND_API int _object_and_properties_init(zval *arg, zend_class_entry *class_type, HashTable *properties ZEND_FILE_LINE_DC TSRMLS_DC) /* {{{ */
1324{
1325    if (class_type->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
1326        char *what =   (class_type->ce_flags & ZEND_ACC_INTERFACE)                ? "interface"
1327                     :((class_type->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) ? "trait"
1328                     :                                                              "abstract class";
1329        zend_error(E_ERROR, "Cannot instantiate %s %s", what, class_type->name->val);
1330    }
1331
1332    zend_update_class_constants(class_type TSRMLS_CC);
1333
1334    if (class_type->create_object == NULL) {
1335        ZVAL_OBJ(arg, zend_objects_new(class_type TSRMLS_CC));
1336        if (properties) {
1337            object_properties_init_ex(Z_OBJ_P(arg), properties TSRMLS_CC);
1338        } else {
1339            object_properties_init(Z_OBJ_P(arg), class_type);
1340        }
1341    } else {
1342        ZVAL_OBJ(arg, class_type->create_object(class_type TSRMLS_CC));
1343    }
1344    return SUCCESS;
1345}
1346/* }}} */
1347
1348ZEND_API int _object_init_ex(zval *arg, zend_class_entry *class_type ZEND_FILE_LINE_DC TSRMLS_DC) /* {{{ */
1349{
1350    return _object_and_properties_init(arg, class_type, 0 ZEND_FILE_LINE_RELAY_CC TSRMLS_CC);
1351}
1352/* }}} */
1353
1354ZEND_API int _object_init(zval *arg ZEND_FILE_LINE_DC TSRMLS_DC) /* {{{ */
1355{
1356    return _object_init_ex(arg, zend_standard_class_def ZEND_FILE_LINE_RELAY_CC TSRMLS_CC);
1357}
1358/* }}} */
1359
1360ZEND_API int add_assoc_function(zval *arg, const char *key, void (*function_ptr)(INTERNAL_FUNCTION_PARAMETERS)) /* {{{ */
1361{
1362    zend_error(E_WARNING, "add_assoc_function() is no longer supported");
1363    return FAILURE;
1364}
1365/* }}} */
1366
1367ZEND_API int add_assoc_long_ex(zval *arg, const char *key, uint key_len, zend_long n) /* {{{ */
1368{
1369    zval *ret, tmp;
1370
1371    ZVAL_LONG(&tmp, n);
1372    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1373    return ret ? SUCCESS : FAILURE;
1374}
1375/* }}} */
1376
1377ZEND_API int add_assoc_null_ex(zval *arg, const char *key, uint key_len) /* {{{ */
1378{
1379    zval *ret, tmp;
1380
1381    ZVAL_NULL(&tmp);
1382    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1383    return ret ? SUCCESS : FAILURE;
1384}
1385/* }}} */
1386
1387ZEND_API int add_assoc_bool_ex(zval *arg, const char *key, uint key_len, int b) /* {{{ */
1388{
1389    zval *ret, tmp;
1390
1391    ZVAL_BOOL(&tmp, b);
1392    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1393    return ret ? SUCCESS : FAILURE;
1394}
1395/* }}} */
1396
1397ZEND_API int add_assoc_resource_ex(zval *arg, const char *key, uint key_len, zend_resource *r) /* {{{ */
1398{
1399    zval *ret, tmp;
1400
1401    ZVAL_RES(&tmp, r);
1402    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1403    return ret ? SUCCESS : FAILURE;
1404}
1405/* }}} */
1406
1407ZEND_API int add_assoc_double_ex(zval *arg, const char *key, uint key_len, double d) /* {{{ */
1408{
1409    zval *ret, tmp;
1410
1411    ZVAL_DOUBLE(&tmp, d);
1412    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1413    return ret ? SUCCESS : FAILURE;
1414}
1415/* }}} */
1416
1417ZEND_API int add_assoc_str_ex(zval *arg, const char *key, uint key_len, zend_string *str) /* {{{ */
1418{
1419    zval *ret, tmp;
1420
1421    ZVAL_STR(&tmp, str);
1422    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1423    return ret ? SUCCESS : FAILURE;
1424}
1425/* }}} */
1426
1427ZEND_API int add_assoc_string_ex(zval *arg, const char *key, uint key_len, char *str) /* {{{ */
1428{
1429    zval *ret, tmp;
1430
1431    ZVAL_STRING(&tmp, str);
1432    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1433    return ret ? SUCCESS : FAILURE;
1434}
1435/* }}} */
1436
1437ZEND_API int add_assoc_stringl_ex(zval *arg, const char *key, uint key_len, char *str, size_t length) /* {{{ */
1438{
1439    zval *ret, tmp;
1440
1441    ZVAL_STRINGL(&tmp, str, length);
1442    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1443    return ret ? SUCCESS : FAILURE;
1444}
1445/* }}} */
1446
1447ZEND_API int add_assoc_zval_ex(zval *arg, const char *key, uint key_len, zval *value) /* {{{ */
1448{
1449    zval *ret;
1450
1451    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, value);
1452    return ret ? SUCCESS : FAILURE;
1453}
1454/* }}} */
1455
1456ZEND_API int add_index_long(zval *arg, zend_ulong index, zend_long n) /* {{{ */
1457{
1458    zval tmp;
1459
1460    ZVAL_LONG(&tmp, n);
1461    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp) ? SUCCESS : FAILURE;
1462}
1463/* }}} */
1464
1465ZEND_API int add_index_null(zval *arg, zend_ulong index) /* {{{ */
1466{
1467    zval tmp;
1468
1469    ZVAL_NULL(&tmp);
1470    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp) ? SUCCESS : FAILURE;
1471}
1472/* }}} */
1473
1474ZEND_API int add_index_bool(zval *arg, zend_ulong index, int b) /* {{{ */
1475{
1476    zval tmp;
1477
1478    ZVAL_BOOL(&tmp, b);
1479    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp) ? SUCCESS : FAILURE;
1480}
1481/* }}} */
1482
1483ZEND_API int add_index_resource(zval *arg, zend_ulong index, zend_resource *r) /* {{{ */
1484{
1485    zval tmp;
1486
1487    ZVAL_RES(&tmp, r);
1488    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp) ? SUCCESS : FAILURE;
1489}
1490/* }}} */
1491
1492ZEND_API int add_index_double(zval *arg, zend_ulong index, double d) /* {{{ */
1493{
1494    zval tmp;
1495
1496    ZVAL_DOUBLE(&tmp, d);
1497    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp) ? SUCCESS : FAILURE;
1498}
1499/* }}} */
1500
1501ZEND_API int add_index_str(zval *arg, zend_ulong index, zend_string *str) /* {{{ */
1502{
1503    zval tmp;
1504
1505    ZVAL_STR(&tmp, str);
1506    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp) ? SUCCESS : FAILURE;
1507}
1508/* }}} */
1509
1510ZEND_API int add_index_string(zval *arg, zend_ulong index, const char *str) /* {{{ */
1511{
1512    zval tmp;
1513
1514    ZVAL_STRING(&tmp, str);
1515    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp) ? SUCCESS : FAILURE;
1516}
1517/* }}} */
1518
1519ZEND_API int add_index_stringl(zval *arg, zend_ulong index, const char *str, size_t length) /* {{{ */
1520{
1521    zval tmp;
1522
1523    ZVAL_STRINGL(&tmp, str, length);
1524    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp) ? SUCCESS : FAILURE;
1525}
1526/* }}} */
1527
1528ZEND_API int add_index_zval(zval *arg, zend_ulong index, zval *value) /* {{{ */
1529{
1530    return zend_hash_index_update(Z_ARRVAL_P(arg), index, value) ? SUCCESS : FAILURE;
1531}
1532/* }}} */
1533
1534ZEND_API int add_next_index_long(zval *arg, zend_long n) /* {{{ */
1535{
1536    zval tmp;
1537
1538    ZVAL_LONG(&tmp, n);
1539    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
1540}
1541/* }}} */
1542
1543ZEND_API int add_next_index_null(zval *arg) /* {{{ */
1544{
1545    zval tmp;
1546
1547    ZVAL_NULL(&tmp);
1548    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
1549}
1550/* }}} */
1551
1552ZEND_API int add_next_index_bool(zval *arg, int b) /* {{{ */
1553{
1554    zval tmp;
1555
1556    ZVAL_BOOL(&tmp, b);
1557    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
1558}
1559/* }}} */
1560
1561ZEND_API int add_next_index_resource(zval *arg, zend_resource *r) /* {{{ */
1562{
1563    zval tmp;
1564
1565    ZVAL_RES(&tmp, r);
1566    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
1567}
1568/* }}} */
1569
1570ZEND_API int add_next_index_double(zval *arg, double d) /* {{{ */
1571{
1572    zval tmp;
1573
1574    ZVAL_DOUBLE(&tmp, d);
1575    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
1576}
1577/* }}} */
1578
1579ZEND_API int add_next_index_str(zval *arg, zend_string *str) /* {{{ */
1580{
1581    zval tmp;
1582
1583    ZVAL_STR(&tmp, str);
1584    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
1585}
1586/* }}} */
1587
1588ZEND_API int add_next_index_string(zval *arg, const char *str) /* {{{ */
1589{
1590    zval tmp;
1591
1592    ZVAL_STRING(&tmp, str);
1593    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
1594}
1595/* }}} */
1596
1597ZEND_API int add_next_index_stringl(zval *arg, const char *str, size_t length) /* {{{ */
1598{
1599    zval tmp;
1600
1601    ZVAL_STRINGL(&tmp, str, length);
1602    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
1603}
1604/* }}} */
1605
1606ZEND_API int add_next_index_zval(zval *arg, zval *value) /* {{{ */
1607{
1608    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), value) ? SUCCESS : FAILURE;
1609}
1610/* }}} */
1611
1612ZEND_API zval *add_get_assoc_string_ex(zval *arg, const char *key, uint key_len, const char *str) /* {{{ */
1613{
1614    zval tmp, *ret;
1615
1616    ZVAL_STRING(&tmp, str);
1617    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1618    return ret;
1619}
1620/* }}} */
1621
1622ZEND_API zval *add_get_assoc_stringl_ex(zval *arg, const char *key, uint key_len, const char *str, size_t length) /* {{{ */
1623{
1624    zval tmp, *ret;
1625
1626    ZVAL_STRINGL(&tmp, str, length);
1627    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1628    return ret;
1629}
1630/* }}} */
1631
1632ZEND_API zval *add_get_index_long(zval *arg, zend_ulong index, zend_long l) /* {{{ */
1633{
1634    zval tmp;
1635
1636    ZVAL_LONG(&tmp, l);
1637    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
1638}
1639/* }}} */
1640
1641ZEND_API zval *add_get_index_double(zval *arg, zend_ulong index, double d) /* {{{ */
1642{
1643    zval tmp;
1644
1645    ZVAL_DOUBLE(&tmp, d);
1646    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
1647}
1648/* }}} */
1649
1650ZEND_API zval *add_get_index_str(zval *arg, zend_ulong index, zend_string *str) /* {{{ */
1651{
1652    zval tmp;
1653
1654    ZVAL_STR(&tmp, str);
1655    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
1656}
1657/* }}} */
1658
1659ZEND_API zval *add_get_index_string(zval *arg, zend_ulong index, const char *str) /* {{{ */
1660{
1661    zval tmp;
1662
1663    ZVAL_STRING(&tmp, str);
1664    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
1665}
1666/* }}} */
1667
1668ZEND_API zval *add_get_index_stringl(zval *arg, zend_ulong index, const char *str, size_t length) /* {{{ */
1669{
1670    zval tmp;
1671
1672    ZVAL_STRINGL(&tmp, str, length);
1673    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
1674}
1675/* }}} */
1676
1677ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value TSRMLS_DC) /* {{{ */
1678{
1679    zval *result;
1680
1681    switch (Z_TYPE_P(key)) {
1682        case IS_STRING:
1683            result = zend_symtable_update(ht, Z_STR_P(key), value);
1684            break;
1685        case IS_NULL:
1686            result = zend_symtable_update(ht, STR_EMPTY_ALLOC(), value);
1687            break;
1688        case IS_RESOURCE:
1689            zend_error(E_STRICT, "Resource ID#" ZEND_LONG_FMT " used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(key), Z_RES_HANDLE_P(key));
1690            result = zend_hash_index_update(ht, Z_RES_HANDLE_P(key), value);
1691            break;
1692        case IS_FALSE:
1693            result = zend_hash_index_update(ht, 0, value);
1694            break;
1695        case IS_TRUE:
1696            result = zend_hash_index_update(ht, 1, value);
1697            break;
1698        case IS_LONG:
1699            result = zend_hash_index_update(ht, Z_LVAL_P(key), value);
1700            break;
1701        case IS_DOUBLE:
1702            result = zend_hash_index_update(ht, zend_dval_to_lval(Z_DVAL_P(key)), value);
1703            break;
1704        default:
1705            zend_error(E_WARNING, "Illegal offset type");
1706            result = NULL;
1707    }
1708
1709    if (result) {
1710        if (Z_REFCOUNTED_P(result)) {
1711            Z_ADDREF_P(result);
1712        }
1713        return SUCCESS;
1714    } else {
1715        return FAILURE;
1716    }
1717}
1718/* }}} */
1719
1720ZEND_API int add_property_long_ex(zval *arg, const char *key, uint key_len, zend_long n TSRMLS_DC) /* {{{ */
1721{
1722    zval tmp;
1723    zval z_key;
1724
1725    ZVAL_LONG(&tmp, n);
1726    ZVAL_STRINGL(&z_key, key, key_len);
1727    Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL TSRMLS_CC);
1728    zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1729    zval_ptr_dtor(&z_key);
1730    return SUCCESS;
1731}
1732/* }}} */
1733
1734ZEND_API int add_property_bool_ex(zval *arg, const char *key, uint key_len, zend_long b TSRMLS_DC) /* {{{ */
1735{
1736    zval tmp;
1737    zval z_key;
1738
1739    ZVAL_BOOL(&tmp, b);
1740    ZVAL_STRINGL(&z_key, key, key_len);
1741    Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL TSRMLS_CC);
1742    zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1743    zval_ptr_dtor(&z_key);
1744    return SUCCESS;
1745}
1746/* }}} */
1747
1748ZEND_API int add_property_null_ex(zval *arg, const char *key, uint key_len TSRMLS_DC) /* {{{ */
1749{
1750    zval tmp;
1751    zval z_key;
1752
1753    ZVAL_NULL(&tmp);
1754    ZVAL_STRINGL(&z_key, key, key_len);
1755    Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL TSRMLS_CC);
1756    zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1757    zval_ptr_dtor(&z_key);
1758    return SUCCESS;
1759}
1760/* }}} */
1761
1762ZEND_API int add_property_resource_ex(zval *arg, const char *key, uint key_len, zend_resource *r TSRMLS_DC) /* {{{ */
1763{
1764    zval tmp;
1765    zval z_key;
1766
1767    ZVAL_RES(&tmp, r);
1768    ZVAL_STRINGL(&z_key, key, key_len);
1769    Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL TSRMLS_CC);
1770    zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1771    zval_ptr_dtor(&z_key);
1772    return SUCCESS;
1773}
1774/* }}} */
1775
1776ZEND_API int add_property_double_ex(zval *arg, const char *key, uint key_len, double d TSRMLS_DC) /* {{{ */
1777{
1778    zval tmp;
1779    zval z_key;
1780
1781    ZVAL_DOUBLE(&tmp, d);
1782    ZVAL_STRINGL(&z_key, key, key_len);
1783    Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL TSRMLS_CC);
1784    zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1785    zval_ptr_dtor(&z_key);
1786    return SUCCESS;
1787}
1788/* }}} */
1789
1790ZEND_API int add_property_str_ex(zval *arg, const char *key, uint key_len, zend_string *str TSRMLS_DC) /* {{{ */
1791{
1792    zval tmp;
1793    zval z_key;
1794
1795    ZVAL_STR(&tmp, str);
1796    ZVAL_STRINGL(&z_key, key, key_len);
1797    Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL TSRMLS_CC);
1798    zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1799    zval_ptr_dtor(&z_key);
1800    return SUCCESS;
1801}
1802/* }}} */
1803
1804ZEND_API int add_property_string_ex(zval *arg, const char *key, uint key_len, const char *str TSRMLS_DC) /* {{{ */
1805{
1806    zval tmp;
1807    zval z_key;
1808
1809    ZVAL_STRING(&tmp, str);
1810    ZVAL_STRINGL(&z_key, key, key_len);
1811    Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL TSRMLS_CC);
1812    zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1813    zval_ptr_dtor(&z_key);
1814    return SUCCESS;
1815}
1816/* }}} */
1817
1818ZEND_API int add_property_stringl_ex(zval *arg, const char *key, uint key_len, const char *str, size_t length TSRMLS_DC) /* {{{ */
1819{
1820    zval tmp;
1821    zval z_key;
1822
1823    ZVAL_STRINGL(&tmp, str, length);
1824    ZVAL_STRINGL(&z_key, key, key_len);
1825    Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL TSRMLS_CC);
1826    zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1827    zval_ptr_dtor(&z_key);
1828    return SUCCESS;
1829}
1830/* }}} */
1831
1832ZEND_API int add_property_zval_ex(zval *arg, const char *key, uint key_len, zval *value TSRMLS_DC) /* {{{ */
1833{
1834    zval z_key;
1835
1836    ZVAL_STRINGL(&z_key, key, key_len);
1837    Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, value, NULL TSRMLS_CC);
1838    zval_ptr_dtor(&z_key);
1839    return SUCCESS;
1840}
1841/* }}} */
1842
1843ZEND_API int zend_startup_module_ex(zend_module_entry *module TSRMLS_DC) /* {{{ */
1844{
1845    int name_len;
1846    zend_string *lcname;
1847
1848    if (module->module_started) {
1849        return SUCCESS;
1850    }
1851    module->module_started = 1;
1852
1853    /* Check module dependencies */
1854    if (module->deps) {
1855        const zend_module_dep *dep = module->deps;
1856
1857        while (dep->name) {
1858            if (dep->type == MODULE_DEP_REQUIRED) {
1859                zend_module_entry *req_mod;
1860
1861                name_len = strlen(dep->name);
1862                lcname = zend_string_alloc(name_len, 0);
1863                zend_str_tolower_copy(lcname->val, dep->name, name_len);
1864
1865                if ((req_mod = zend_hash_find_ptr(&module_registry, lcname)) == NULL || !req_mod->module_started) {
1866                    zend_string_free(lcname);
1867                    /* TODO: Check version relationship */
1868                    zend_error(E_CORE_WARNING, "Cannot load module '%s' because required module '%s' is not loaded", module->name, dep->name);
1869                    module->module_started = 0;
1870                    return FAILURE;
1871                }
1872                zend_string_free(lcname);
1873            }
1874            ++dep;
1875        }
1876    }
1877
1878    /* Initialize module globals */
1879    if (module->globals_size) {
1880#ifdef ZTS
1881        ts_allocate_id(module->globals_id_ptr, module->globals_size, (ts_allocate_ctor) module->globals_ctor, (ts_allocate_dtor) module->globals_dtor);
1882#else
1883        if (module->globals_ctor) {
1884            module->globals_ctor(module->globals_ptr TSRMLS_CC);
1885        }
1886#endif
1887    }
1888    if (module->module_startup_func) {
1889        EG(current_module) = module;
1890        if (module->module_startup_func(module->type, module->module_number TSRMLS_CC)==FAILURE) {
1891            zend_error(E_CORE_ERROR,"Unable to start %s module", module->name);
1892            EG(current_module) = NULL;
1893            return FAILURE;
1894        }
1895        EG(current_module) = NULL;
1896    }
1897    return SUCCESS;
1898}
1899/* }}} */
1900
1901static int zend_startup_module_zval(zval *zv TSRMLS_DC) /* {{{ */
1902{
1903    zend_module_entry *module = Z_PTR_P(zv);
1904
1905    return zend_startup_module_ex(module TSRMLS_CC);
1906}
1907/* }}} */
1908
1909
1910static void zend_sort_modules(void *base, size_t count, size_t siz, compare_func_t compare TSRMLS_DC) /* {{{ */
1911{
1912    Bucket *b1 = base;
1913    Bucket *b2;
1914    Bucket *end = b1 + count;
1915    Bucket tmp;
1916    zend_module_entry *m, *r;
1917
1918    while (b1 < end) {
1919try_again:
1920        m = (zend_module_entry*)Z_PTR(b1->val);
1921        if (!m->module_started && m->deps) {
1922            const zend_module_dep *dep = m->deps;
1923            while (dep->name) {
1924                if (dep->type == MODULE_DEP_REQUIRED || dep->type == MODULE_DEP_OPTIONAL) {
1925                    b2 = b1 + 1;
1926                    while (b2 < end) {
1927                        r = (zend_module_entry*)Z_PTR(b2->val);
1928                        if (strcasecmp(dep->name, r->name) == 0) {
1929                            tmp = *b1;
1930                            *b1 = *b2;
1931                            *b2 = tmp;
1932                            goto try_again;
1933                        }
1934                        b2++;
1935                    }
1936                }
1937                dep++;
1938            }
1939        }
1940        b1++;
1941    }
1942}
1943/* }}} */
1944
1945ZEND_API void zend_collect_module_handlers(TSRMLS_D) /* {{{ */
1946{
1947    zend_module_entry *module;
1948    int startup_count = 0;
1949    int shutdown_count = 0;
1950    int post_deactivate_count = 0;
1951    zend_class_entry *ce;
1952    int class_count = 0;
1953
1954    /* Collect extensions with request startup/shutdown handlers */
1955    ZEND_HASH_FOREACH_PTR(&module_registry, module) {
1956        if (module->request_startup_func) {
1957            startup_count++;
1958        }
1959        if (module->request_shutdown_func) {
1960            shutdown_count++;
1961        }
1962        if (module->post_deactivate_func) {
1963            post_deactivate_count++;
1964        }
1965    } ZEND_HASH_FOREACH_END();
1966    module_request_startup_handlers = (zend_module_entry**)malloc(
1967        sizeof(zend_module_entry*) *
1968        (startup_count + 1 +
1969         shutdown_count + 1 +
1970         post_deactivate_count + 1));
1971    module_request_startup_handlers[startup_count] = NULL;
1972    module_request_shutdown_handlers = module_request_startup_handlers + startup_count + 1;
1973    module_request_shutdown_handlers[shutdown_count] = NULL;
1974    module_post_deactivate_handlers = module_request_shutdown_handlers + shutdown_count + 1;
1975    module_post_deactivate_handlers[post_deactivate_count] = NULL;
1976    startup_count = 0;
1977
1978    ZEND_HASH_FOREACH_PTR(&module_registry, module) {
1979        if (module->request_startup_func) {
1980            module_request_startup_handlers[startup_count++] = module;
1981        }
1982        if (module->request_shutdown_func) {
1983            module_request_shutdown_handlers[--shutdown_count] = module;
1984        }
1985        if (module->post_deactivate_func) {
1986            module_post_deactivate_handlers[--post_deactivate_count] = module;
1987        }
1988    } ZEND_HASH_FOREACH_END();
1989
1990    /* Collect internal classes with static members */
1991    ZEND_HASH_FOREACH_PTR(CG(class_table), ce) {
1992        if (ce->type == ZEND_INTERNAL_CLASS &&
1993            ce->default_static_members_count > 0) {
1994            class_count++;
1995        }
1996    } ZEND_HASH_FOREACH_END();
1997
1998    class_cleanup_handlers = (zend_class_entry**)malloc(
1999        sizeof(zend_class_entry*) *
2000        (class_count + 1));
2001    class_cleanup_handlers[class_count] = NULL;
2002
2003    if (class_count) {
2004        ZEND_HASH_FOREACH_PTR(CG(class_table), ce) {
2005            if (ce->type == ZEND_INTERNAL_CLASS &&
2006                ce->default_static_members_count > 0) {
2007                class_cleanup_handlers[--class_count] = ce;
2008            }
2009        } ZEND_HASH_FOREACH_END();
2010    }
2011}
2012/* }}} */
2013
2014ZEND_API int zend_startup_modules(TSRMLS_D) /* {{{ */
2015{
2016    zend_hash_sort(&module_registry, zend_sort_modules, NULL, 0 TSRMLS_CC);
2017    zend_hash_apply(&module_registry, zend_startup_module_zval TSRMLS_CC);
2018    return SUCCESS;
2019}
2020/* }}} */
2021
2022ZEND_API void zend_destroy_modules(void) /* {{{ */
2023{
2024    free(class_cleanup_handlers);
2025    free(module_request_startup_handlers);
2026    zend_hash_graceful_reverse_destroy(&module_registry);
2027}
2028/* }}} */
2029
2030ZEND_API zend_module_entry* zend_register_module_ex(zend_module_entry *module TSRMLS_DC) /* {{{ */
2031{
2032    int name_len;
2033    zend_string *lcname;
2034    zend_module_entry *module_ptr;
2035
2036    if (!module) {
2037        return NULL;
2038    }
2039
2040#if 0
2041    zend_printf("%s: Registering module %d\n", module->name, module->module_number);
2042#endif
2043
2044    /* Check module dependencies */
2045    if (module->deps) {
2046        const zend_module_dep *dep = module->deps;
2047
2048        while (dep->name) {
2049            if (dep->type == MODULE_DEP_CONFLICTS) {
2050                name_len = strlen(dep->name);
2051                lcname = zend_string_alloc(name_len, 0);
2052                zend_str_tolower_copy(lcname->val, dep->name, name_len);
2053
2054                if (zend_hash_exists(&module_registry, lcname)) {
2055                    zend_string_free(lcname);
2056                    /* TODO: Check version relationship */
2057                    zend_error(E_CORE_WARNING, "Cannot load module '%s' because conflicting module '%s' is already loaded", module->name, dep->name);
2058                    return NULL;
2059                }
2060                zend_string_free(lcname);
2061            }
2062            ++dep;
2063        }
2064    }
2065
2066    name_len = strlen(module->name);
2067    lcname = zend_string_alloc(name_len, 1);
2068    zend_str_tolower_copy(lcname->val, module->name, name_len);
2069
2070    if ((module_ptr = zend_hash_add_mem(&module_registry, lcname, module, sizeof(zend_module_entry))) == NULL) {
2071        zend_error(E_CORE_WARNING, "Module '%s' already loaded", module->name);
2072        zend_string_release(lcname);
2073        return NULL;
2074    }
2075    zend_string_release(lcname);
2076    module = module_ptr;
2077    EG(current_module) = module;
2078
2079    if (module->functions && zend_register_functions(NULL, module->functions, NULL, module->type TSRMLS_CC)==FAILURE) {
2080        EG(current_module) = NULL;
2081        zend_error(E_CORE_WARNING,"%s: Unable to register functions, unable to load", module->name);
2082        return NULL;
2083    }
2084
2085    EG(current_module) = NULL;
2086    return module;
2087}
2088/* }}} */
2089
2090ZEND_API zend_module_entry* zend_register_internal_module(zend_module_entry *module TSRMLS_DC) /* {{{ */
2091{
2092    module->module_number = zend_next_free_module();
2093    module->type = MODULE_PERSISTENT;
2094    return zend_register_module_ex(module TSRMLS_CC);
2095}
2096/* }}} */
2097
2098ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce, const zend_function *fptr, int error_type TSRMLS_DC) /* {{{ */
2099{
2100    char lcname[16];
2101    int name_len;
2102
2103    /* we don't care if the function name is longer, in fact lowercasing only
2104     * the beginning of the name speeds up the check process */
2105    name_len = fptr->common.function_name->len;
2106    zend_str_tolower_copy(lcname, fptr->common.function_name->val, MIN(name_len, sizeof(lcname)-1));
2107    lcname[sizeof(lcname)-1] = '\0'; /* zend_str_tolower_copy won't necessarily set the zero byte */
2108
2109    if (name_len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME) - 1) && fptr->common.num_args != 0) {
2110        zend_error(error_type, "Destructor %s::%s() cannot take arguments", ce->name->val, ZEND_DESTRUCTOR_FUNC_NAME);
2111    } else if (name_len == sizeof(ZEND_CLONE_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME) - 1) && fptr->common.num_args != 0) {
2112        zend_error(error_type, "Method %s::%s() cannot accept any arguments", ce->name->val, ZEND_CLONE_FUNC_NAME);
2113    } else if (name_len == sizeof(ZEND_GET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME) - 1)) {
2114        if (fptr->common.num_args != 1) {
2115            zend_error(error_type, "Method %s::%s() must take exactly 1 argument", ce->name->val, ZEND_GET_FUNC_NAME);
2116        } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1)) {
2117            zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ce->name->val, ZEND_GET_FUNC_NAME);
2118        }
2119    } else if (name_len == sizeof(ZEND_SET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME) - 1)) {
2120        if (fptr->common.num_args != 2) {
2121            zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ce->name->val, ZEND_SET_FUNC_NAME);
2122        } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
2123            zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ce->name->val, ZEND_SET_FUNC_NAME);
2124        }
2125    } else if (name_len == sizeof(ZEND_UNSET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME) - 1)) {
2126        if (fptr->common.num_args != 1) {
2127            zend_error(error_type, "Method %s::%s() must take exactly 1 argument", ce->name->val, ZEND_UNSET_FUNC_NAME);
2128        } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1)) {
2129            zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ce->name->val, ZEND_UNSET_FUNC_NAME);
2130        }
2131    } else if (name_len == sizeof(ZEND_ISSET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME) - 1)) {
2132        if (fptr->common.num_args != 1) {
2133            zend_error(error_type, "Method %s::%s() must take exactly 1 argument", ce->name->val, ZEND_ISSET_FUNC_NAME);
2134        } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1)) {
2135            zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ce->name->val, ZEND_ISSET_FUNC_NAME);
2136        }
2137    } else if (name_len == sizeof(ZEND_CALL_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME) - 1)) {
2138        if (fptr->common.num_args != 2) {
2139            zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ce->name->val, ZEND_CALL_FUNC_NAME);
2140        } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
2141            zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ce->name->val, ZEND_CALL_FUNC_NAME);
2142        }
2143    } else if (name_len == sizeof(ZEND_CALLSTATIC_FUNC_NAME) - 1 &&
2144        !memcmp(lcname, ZEND_CALLSTATIC_FUNC_NAME, sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1)
2145    ) {
2146        if (fptr->common.num_args != 2) {
2147            zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ce->name->val, ZEND_CALLSTATIC_FUNC_NAME);
2148        } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
2149            zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ce->name->val, ZEND_CALLSTATIC_FUNC_NAME);
2150        }
2151    } else if (name_len == sizeof(ZEND_TOSTRING_FUNC_NAME) - 1 &&
2152        !memcmp(lcname, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && fptr->common.num_args != 0
2153    ) {
2154        zend_error(error_type, "Method %s::%s() cannot take arguments", ce->name->val, ZEND_TOSTRING_FUNC_NAME);
2155    } else if (name_len == sizeof(ZEND_DEBUGINFO_FUNC_NAME) - 1 &&
2156        !memcmp(lcname, ZEND_DEBUGINFO_FUNC_NAME, sizeof(ZEND_DEBUGINFO_FUNC_NAME)-1) && fptr->common.num_args != 0) {
2157        zend_error(error_type, "Method %s::%s() cannot take arguments", ce->name->val, ZEND_DEBUGINFO_FUNC_NAME);
2158    }
2159}
2160/* }}} */
2161
2162/* registers all functions in *library_functions in the function hash */
2163ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_function_entry *functions, HashTable *function_table, int type TSRMLS_DC) /* {{{ */
2164{
2165    const zend_function_entry *ptr = functions;
2166    zend_function function, *reg_function;
2167    zend_internal_function *internal_function = (zend_internal_function *)&function;
2168    int count=0, unload=0;
2169    HashTable *target_function_table = function_table;
2170    int error_type;
2171    zend_function *ctor = NULL, *dtor = NULL, *clone = NULL, *__get = NULL, *__set = NULL, *__unset = NULL, *__isset = NULL, *__call = NULL, *__callstatic = NULL, *__tostring = NULL, *__debugInfo = NULL;
2172    zend_string *lowercase_name;
2173    int fname_len;
2174    const char *lc_class_name = NULL;
2175    int class_name_len = 0;
2176
2177    if (type==MODULE_PERSISTENT) {
2178        error_type = E_CORE_WARNING;
2179    } else {
2180        error_type = E_WARNING;
2181    }
2182
2183    if (!target_function_table) {
2184        target_function_table = CG(function_table);
2185    }
2186    internal_function->type = ZEND_INTERNAL_FUNCTION;
2187    internal_function->module = EG(current_module);
2188
2189    if (scope) {
2190        class_name_len = scope->name->len;
2191        if ((lc_class_name = zend_memrchr(scope->name->val, '\\', class_name_len))) {
2192            ++lc_class_name;
2193            class_name_len -= (lc_class_name - scope->name->val);
2194            lc_class_name = zend_str_tolower_dup(lc_class_name, class_name_len);
2195        } else {
2196            lc_class_name = zend_str_tolower_dup(scope->name->val, class_name_len);
2197        }
2198    }
2199
2200    while (ptr->fname) {
2201        fname_len = strlen(ptr->fname);
2202        internal_function->handler = ptr->handler;
2203        internal_function->function_name = zend_new_interned_string(zend_string_init(ptr->fname, fname_len, 1) TSRMLS_CC);
2204        internal_function->scope = scope;
2205        internal_function->prototype = NULL;
2206        if (ptr->flags) {
2207            if (!(ptr->flags & ZEND_ACC_PPP_MASK)) {
2208                if (ptr->flags != ZEND_ACC_DEPRECATED || scope) {
2209                    zend_error(error_type, "Invalid access level for %s%s%s() - access must be exactly one of public, protected or private", scope ? scope->name->val : "", scope ? "::" : "", ptr->fname);
2210                }
2211                internal_function->fn_flags = ZEND_ACC_PUBLIC | ptr->flags;
2212            } else {
2213                internal_function->fn_flags = ptr->flags;
2214            }
2215        } else {
2216            internal_function->fn_flags = ZEND_ACC_PUBLIC;
2217        }
2218        if (ptr->arg_info) {
2219            zend_internal_function_info *info = (zend_internal_function_info*)ptr->arg_info;
2220
2221            internal_function->arg_info = (zend_arg_info*)ptr->arg_info+1;
2222            internal_function->num_args = ptr->num_args;
2223            /* Currently you cannot denote that the function can accept less arguments than num_args */
2224            if (info->required_num_args == -1) {
2225                internal_function->required_num_args = ptr->num_args;
2226            } else {
2227                internal_function->required_num_args = info->required_num_args;
2228            }
2229            if (info->return_reference) {
2230                internal_function->fn_flags |= ZEND_ACC_RETURN_REFERENCE;
2231            }
2232            if (ptr->arg_info[ptr->num_args].is_variadic) {
2233                internal_function->fn_flags |= ZEND_ACC_VARIADIC;
2234            }
2235        } else {
2236            internal_function->arg_info = NULL;
2237            internal_function->num_args = 0;
2238            internal_function->required_num_args = 0;
2239        }
2240        if (ptr->flags & ZEND_ACC_ABSTRACT) {
2241            if (scope) {
2242                /* This is a class that must be abstract itself. Here we set the check info. */
2243                scope->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
2244                if (!(scope->ce_flags & ZEND_ACC_INTERFACE)) {
2245                    /* Since the class is not an interface it needs to be declared as a abstract class. */
2246                    /* Since here we are handling internal functions only we can add the keyword flag. */
2247                    /* This time we set the flag for the keyword 'abstract'. */
2248                    scope->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
2249                }
2250            }
2251            if (ptr->flags & ZEND_ACC_STATIC && (!scope || !(scope->ce_flags & ZEND_ACC_INTERFACE))) {
2252                zend_error(error_type, "Static function %s%s%s() cannot be abstract", scope ? scope->name->val : "", scope ? "::" : "", ptr->fname);
2253            }
2254        } else {
2255            if (scope && (scope->ce_flags & ZEND_ACC_INTERFACE)) {
2256                efree((char*)lc_class_name);
2257                zend_error(error_type, "Interface %s cannot contain non abstract method %s()", scope->name->val, ptr->fname);
2258                return FAILURE;
2259            }
2260            if (!internal_function->handler) {
2261                if (scope) {
2262                    efree((char*)lc_class_name);
2263                }
2264                zend_error(error_type, "Method %s%s%s() cannot be a NULL function", scope ? scope->name->val : "", scope ? "::" : "", ptr->fname);
2265                zend_unregister_functions(functions, count, target_function_table TSRMLS_CC);
2266                return FAILURE;
2267            }
2268        }
2269        lowercase_name = zend_string_alloc(fname_len, 1);
2270        zend_str_tolower_copy(lowercase_name->val, ptr->fname, fname_len);
2271        lowercase_name = zend_new_interned_string(lowercase_name TSRMLS_CC);
2272        reg_function = malloc(sizeof(zend_internal_function));
2273        memcpy(reg_function, &function, sizeof(zend_internal_function));
2274        if (zend_hash_add_ptr(target_function_table, lowercase_name, reg_function) == NULL) {
2275            unload=1;
2276            free(reg_function);
2277            zend_string_release(lowercase_name);
2278            break;
2279        }
2280
2281        /* If types of arguments have to be checked */
2282        if (reg_function->common.arg_info && reg_function->common.num_args) {
2283            int i;
2284            for (i = 0; i < reg_function->common.num_args; i++) {
2285                if (reg_function->common.arg_info[i].class_name ||
2286                    reg_function->common.arg_info[i].type_hint) {
2287                    reg_function->common.fn_flags |= ZEND_ACC_HAS_TYPE_HINTS;
2288                    break;
2289                }
2290            }
2291        }
2292
2293        if (scope) {
2294            /* Look for ctor, dtor, clone
2295             * If it's an old-style constructor, store it only if we don't have
2296             * a constructor already.
2297             */
2298            if ((fname_len == class_name_len) && !ctor && !memcmp(lowercase_name->val, lc_class_name, class_name_len+1)) {
2299                ctor = reg_function;
2300            } else if (zend_string_equals_literal(lowercase_name, ZEND_CONSTRUCTOR_FUNC_NAME)) {
2301                ctor = reg_function;
2302            } else if (zend_string_equals_literal(lowercase_name, ZEND_DESTRUCTOR_FUNC_NAME)) {
2303                dtor = reg_function;
2304                if (internal_function->num_args) {
2305                    zend_error(error_type, "Destructor %s::%s() cannot take arguments", scope->name->val, ptr->fname);
2306                }
2307            } else if (zend_string_equals_literal(lowercase_name, ZEND_CLONE_FUNC_NAME)) {
2308                clone = reg_function;
2309            } else if (zend_string_equals_literal(lowercase_name, ZEND_CALL_FUNC_NAME)) {
2310                __call = reg_function;
2311            } else if (zend_string_equals_literal(lowercase_name, ZEND_CALLSTATIC_FUNC_NAME)) {
2312                __callstatic = reg_function;
2313            } else if (zend_string_equals_literal(lowercase_name, ZEND_TOSTRING_FUNC_NAME)) {
2314                __tostring = reg_function;
2315            } else if (zend_string_equals_literal(lowercase_name, ZEND_GET_FUNC_NAME)) {
2316                __get = reg_function;
2317            } else if (zend_string_equals_literal(lowercase_name, ZEND_SET_FUNC_NAME)) {
2318                __set = reg_function;
2319            } else if (zend_string_equals_literal(lowercase_name, ZEND_UNSET_FUNC_NAME)) {
2320                __unset = reg_function;
2321            } else if (zend_string_equals_literal(lowercase_name, ZEND_ISSET_FUNC_NAME)) {
2322                __isset = reg_function;
2323            } else if (zend_string_equals_literal(lowercase_name, ZEND_DEBUGINFO_FUNC_NAME)) {
2324                __debugInfo = reg_function;
2325            } else {
2326                reg_function = NULL;
2327            }
2328            if (reg_function) {
2329                zend_check_magic_method_implementation(scope, reg_function, error_type TSRMLS_CC);
2330            }
2331        }
2332        ptr++;
2333        count++;
2334        zend_string_release(lowercase_name);
2335    }
2336    if (unload) { /* before unloading, display all remaining bad function in the module */
2337        if (scope) {
2338            efree((char*)lc_class_name);
2339        }
2340        while (ptr->fname) {
2341            fname_len = strlen(ptr->fname);
2342            lowercase_name = zend_string_alloc(fname_len, 0);
2343            zend_str_tolower_copy(lowercase_name->val, ptr->fname, fname_len);
2344            if (zend_hash_exists(target_function_table, lowercase_name)) {
2345                zend_error(error_type, "Function registration failed - duplicate name - %s%s%s", scope ? scope->name->val : "", scope ? "::" : "", ptr->fname);
2346            }
2347            zend_string_free(lowercase_name);
2348            ptr++;
2349        }
2350        zend_unregister_functions(functions, count, target_function_table TSRMLS_CC);
2351        return FAILURE;
2352    }
2353    if (scope) {
2354        scope->constructor = ctor;
2355        scope->destructor = dtor;
2356        scope->clone = clone;
2357        scope->__call = __call;
2358        scope->__callstatic = __callstatic;
2359        scope->__tostring = __tostring;
2360        scope->__get = __get;
2361        scope->__set = __set;
2362        scope->__unset = __unset;
2363        scope->__isset = __isset;
2364        scope->__debugInfo = __debugInfo;
2365        if (ctor) {
2366            ctor->common.fn_flags |= ZEND_ACC_CTOR;
2367            if (ctor->common.fn_flags & ZEND_ACC_STATIC) {
2368                zend_error(error_type, "Constructor %s::%s() cannot be static", scope->name->val, ctor->common.function_name->val);
2369            }
2370            ctor->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2371        }
2372        if (dtor) {
2373            dtor->common.fn_flags |= ZEND_ACC_DTOR;
2374            if (dtor->common.fn_flags & ZEND_ACC_STATIC) {
2375                zend_error(error_type, "Destructor %s::%s() cannot be static", scope->name->val, dtor->common.function_name->val);
2376            }
2377            dtor->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2378        }
2379        if (clone) {
2380            clone->common.fn_flags |= ZEND_ACC_CLONE;
2381            if (clone->common.fn_flags & ZEND_ACC_STATIC) {
2382                zend_error(error_type, "Constructor %s::%s() cannot be static", scope->name->val, clone->common.function_name->val);
2383            }
2384            clone->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2385        }
2386        if (__call) {
2387            if (__call->common.fn_flags & ZEND_ACC_STATIC) {
2388                zend_error(error_type, "Method %s::%s() cannot be static", scope->name->val, __call->common.function_name->val);
2389            }
2390            __call->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2391        }
2392        if (__callstatic) {
2393            if (!(__callstatic->common.fn_flags & ZEND_ACC_STATIC)) {
2394                zend_error(error_type, "Method %s::%s() must be static", scope->name->val, __callstatic->common.function_name->val);
2395            }
2396            __callstatic->common.fn_flags |= ZEND_ACC_STATIC;
2397        }
2398        if (__tostring) {
2399            if (__tostring->common.fn_flags & ZEND_ACC_STATIC) {
2400                zend_error(error_type, "Method %s::%s() cannot be static", scope->name->val, __tostring->common.function_name->val);
2401            }
2402            __tostring->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2403        }
2404        if (__get) {
2405            if (__get->common.fn_flags & ZEND_ACC_STATIC) {
2406                zend_error(error_type, "Method %s::%s() cannot be static", scope->name->val, __get->common.function_name->val);
2407            }
2408            __get->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2409        }
2410        if (__set) {
2411            if (__set->common.fn_flags & ZEND_ACC_STATIC) {
2412                zend_error(error_type, "Method %s::%s() cannot be static", scope->name->val, __set->common.function_name->val);
2413            }
2414            __set->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2415        }
2416        if (__unset) {
2417            if (__unset->common.fn_flags & ZEND_ACC_STATIC) {
2418                zend_error(error_type, "Method %s::%s() cannot be static", scope->name->val, __unset->common.function_name->val);
2419            }
2420            __unset->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2421        }
2422        if (__isset) {
2423            if (__isset->common.fn_flags & ZEND_ACC_STATIC) {
2424                zend_error(error_type, "Method %s::%s() cannot be static", scope->name->val, __isset->common.function_name->val);
2425            }
2426            __isset->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2427        }
2428        if (__debugInfo) {
2429            if (__debugInfo->common.fn_flags & ZEND_ACC_STATIC) {
2430                zend_error(error_type, "Method %s::%s() cannot be static", scope->name->val, __debugInfo->common.function_name->val);
2431            }
2432        }
2433        efree((char*)lc_class_name);
2434    }
2435    return SUCCESS;
2436}
2437/* }}} */
2438
2439/* count=-1 means erase all functions, otherwise,
2440 * erase the first count functions
2441 */
2442ZEND_API void zend_unregister_functions(const zend_function_entry *functions, int count, HashTable *function_table TSRMLS_DC) /* {{{ */
2443{
2444    const zend_function_entry *ptr = functions;
2445    int i=0;
2446    HashTable *target_function_table = function_table;
2447    zend_string *lowercase_name;
2448    int fname_len;
2449
2450    if (!target_function_table) {
2451        target_function_table = CG(function_table);
2452    }
2453    while (ptr->fname) {
2454        if (count!=-1 && i>=count) {
2455            break;
2456        }
2457        fname_len = strlen(ptr->fname);
2458        lowercase_name = zend_string_alloc(fname_len, 0);
2459        zend_str_tolower_copy(lowercase_name->val, ptr->fname, fname_len);
2460        zend_hash_del(target_function_table, lowercase_name);
2461        zend_string_free(lowercase_name);
2462        ptr++;
2463        i++;
2464    }
2465}
2466/* }}} */
2467
2468ZEND_API int zend_startup_module(zend_module_entry *module TSRMLS_DC) /* {{{ */
2469{
2470    if ((module = zend_register_internal_module(module TSRMLS_CC)) != NULL && zend_startup_module_ex(module TSRMLS_CC) == SUCCESS) {
2471        return SUCCESS;
2472    }
2473    return FAILURE;
2474}
2475/* }}} */
2476
2477ZEND_API int zend_get_module_started(const char *module_name) /* {{{ */
2478{
2479    zend_module_entry *module;
2480
2481    module = zend_hash_str_find_ptr(&module_registry, module_name, strlen(module_name));
2482    return (module && module->module_started) ? SUCCESS : FAILURE;
2483}
2484/* }}} */
2485
2486static int clean_module_class(zval *el, void *arg TSRMLS_DC) /* {{{ */
2487{
2488    zend_class_entry *ce = (zend_class_entry *)Z_PTR_P(el);
2489    int module_number = *(int *)arg;
2490    if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module->module_number == module_number) {
2491        return ZEND_HASH_APPLY_REMOVE;
2492    } else {
2493        return ZEND_HASH_APPLY_KEEP;
2494    }
2495}
2496/* }}} */
2497
2498static void clean_module_classes(int module_number TSRMLS_DC) /* {{{ */
2499{
2500    zend_hash_apply_with_argument(EG(class_table), clean_module_class, (void *) &module_number TSRMLS_CC);
2501}
2502/* }}} */
2503
2504void module_destructor(zend_module_entry *module) /* {{{ */
2505{
2506    TSRMLS_FETCH();
2507
2508    if (module->type == MODULE_TEMPORARY) {
2509        zend_clean_module_rsrc_dtors(module->module_number TSRMLS_CC);
2510        clean_module_constants(module->module_number TSRMLS_CC);
2511        clean_module_classes(module->module_number TSRMLS_CC);
2512    }
2513
2514    if (module->module_started && module->module_shutdown_func) {
2515#if 0
2516        zend_printf("%s: Module shutdown\n", module->name);
2517#endif
2518        module->module_shutdown_func(module->type, module->module_number TSRMLS_CC);
2519    }
2520
2521    /* Deinitilaise module globals */
2522    if (module->globals_size) {
2523#ifdef ZTS
2524        if (*module->globals_id_ptr) {
2525            ts_free_id(*module->globals_id_ptr);
2526        }
2527#else
2528        if (module->globals_dtor) {
2529            module->globals_dtor(module->globals_ptr TSRMLS_CC);
2530        }
2531#endif
2532    }
2533
2534    module->module_started=0;
2535    if (module->functions) {
2536        zend_unregister_functions(module->functions, -1, NULL TSRMLS_CC);
2537    }
2538
2539#if HAVE_LIBDL
2540#if !(defined(NETWARE) && defined(APACHE_1_BUILD))
2541    if (module->handle && !getenv("ZEND_DONT_UNLOAD_MODULES")) {
2542        DL_UNLOAD(module->handle);
2543    }
2544#endif
2545#endif
2546}
2547/* }}} */
2548
2549ZEND_API void zend_activate_modules(TSRMLS_D) /* {{{ */
2550{
2551    zend_module_entry **p = module_request_startup_handlers;
2552
2553    while (*p) {
2554        zend_module_entry *module = *p;
2555
2556        if (module->request_startup_func(module->type, module->module_number TSRMLS_CC)==FAILURE) {
2557            zend_error(E_WARNING, "request_startup() for %s module failed", module->name);
2558            exit(1);
2559        }
2560        p++;
2561    }
2562}
2563/* }}} */
2564
2565/* call request shutdown for all modules */
2566static int module_registry_cleanup(zval *zv TSRMLS_DC) /* {{{ */
2567{
2568    zend_module_entry *module = Z_PTR_P(zv);
2569
2570    if (module->request_shutdown_func) {
2571#if 0
2572        zend_printf("%s: Request shutdown\n", module->name);
2573#endif
2574        module->request_shutdown_func(module->type, module->module_number TSRMLS_CC);
2575    }
2576    return 0;
2577}
2578/* }}} */
2579
2580ZEND_API void zend_deactivate_modules(TSRMLS_D) /* {{{ */
2581{
2582    EG(current_execute_data) = NULL; /* we're no longer executing anything */
2583
2584    zend_try {
2585        if (EG(full_tables_cleanup)) {
2586            zend_hash_reverse_apply(&module_registry, module_registry_cleanup TSRMLS_CC);
2587        } else {
2588            zend_module_entry **p = module_request_shutdown_handlers;
2589
2590            while (*p) {
2591                zend_module_entry *module = *p;
2592
2593                module->request_shutdown_func(module->type, module->module_number TSRMLS_CC);
2594                p++;
2595            }
2596        }
2597    } zend_end_try();
2598}
2599/* }}} */
2600
2601ZEND_API void zend_cleanup_internal_classes(TSRMLS_D) /* {{{ */
2602{
2603    zend_class_entry **p = class_cleanup_handlers;
2604
2605    while (*p) {
2606        zend_cleanup_internal_class_data(*p TSRMLS_CC);
2607        p++;
2608    }
2609}
2610/* }}} */
2611
2612int module_registry_unload_temp(const zend_module_entry *module TSRMLS_DC) /* {{{ */
2613{
2614    return (module->type == MODULE_TEMPORARY) ? ZEND_HASH_APPLY_REMOVE : ZEND_HASH_APPLY_STOP;
2615}
2616/* }}} */
2617
2618static int module_registry_unload_temp_wrapper(zval *el TSRMLS_DC) /* {{{ */
2619{
2620    zend_module_entry *module = (zend_module_entry *)Z_PTR_P(el);
2621    return module_registry_unload_temp((const zend_module_entry *)module TSRMLS_CC);
2622}
2623/* }}} */
2624
2625static int exec_done_cb(zval *el TSRMLS_DC) /* {{{ */
2626{
2627    zend_module_entry *module = (zend_module_entry *)Z_PTR_P(el);
2628    if (module->post_deactivate_func) {
2629        module->post_deactivate_func();
2630    }
2631    return 0;
2632}
2633/* }}} */
2634
2635ZEND_API void zend_post_deactivate_modules(TSRMLS_D) /* {{{ */
2636{
2637    if (EG(full_tables_cleanup)) {
2638        zend_hash_apply(&module_registry, exec_done_cb TSRMLS_CC);
2639        zend_hash_reverse_apply(&module_registry, module_registry_unload_temp_wrapper TSRMLS_CC);
2640    } else {
2641        zend_module_entry **p = module_post_deactivate_handlers;
2642
2643        while (*p) {
2644            zend_module_entry *module = *p;
2645
2646            module->post_deactivate_func();
2647            p++;
2648        }
2649    }
2650}
2651/* }}} */
2652
2653/* return the next free module number */
2654int zend_next_free_module(void) /* {{{ */
2655{
2656    return zend_hash_num_elements(&module_registry) + 1;
2657}
2658/* }}} */
2659
2660static zend_class_entry *do_register_internal_class(zend_class_entry *orig_class_entry, uint32_t ce_flags TSRMLS_DC) /* {{{ */
2661{
2662    zend_class_entry *class_entry = malloc(sizeof(zend_class_entry));
2663    zend_string *lowercase_name = zend_string_alloc(orig_class_entry->name->len, 1);
2664    *class_entry = *orig_class_entry;
2665
2666    class_entry->type = ZEND_INTERNAL_CLASS;
2667    zend_initialize_class_data(class_entry, 0 TSRMLS_CC);
2668    class_entry->ce_flags = ce_flags | ZEND_ACC_CONSTANTS_UPDATED;
2669    class_entry->info.internal.module = EG(current_module);
2670
2671    if (class_entry->info.internal.builtin_functions) {
2672        zend_register_functions(class_entry, class_entry->info.internal.builtin_functions, &class_entry->function_table, MODULE_PERSISTENT TSRMLS_CC);
2673    }
2674
2675    zend_str_tolower_copy(lowercase_name->val, orig_class_entry->name->val, class_entry->name->len);
2676    lowercase_name = zend_new_interned_string(lowercase_name TSRMLS_CC);
2677    zend_hash_update_ptr(CG(class_table), lowercase_name, class_entry);
2678    zend_string_release(lowercase_name);
2679    return class_entry;
2680}
2681/* }}} */
2682
2683/* If parent_ce is not NULL then it inherits from parent_ce
2684 * If parent_ce is NULL and parent_name isn't then it looks for the parent and inherits from it
2685 * If both parent_ce and parent_name are NULL it does a regular class registration
2686 * If parent_name is specified but not found NULL is returned
2687 */
2688ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *class_entry, zend_class_entry *parent_ce TSRMLS_DC) /* {{{ */
2689{
2690    zend_class_entry *register_class;
2691
2692    register_class = zend_register_internal_class(class_entry TSRMLS_CC);
2693
2694    if (parent_ce) {
2695        zend_do_inheritance(register_class, parent_ce TSRMLS_CC);
2696    }
2697    return register_class;
2698}
2699/* }}} */
2700
2701ZEND_API void zend_class_implements(zend_class_entry *class_entry TSRMLS_DC, int num_interfaces, ...) /* {{{ */
2702{
2703    zend_class_entry *interface_entry;
2704    va_list interface_list;
2705    va_start(interface_list, num_interfaces);
2706
2707    while (num_interfaces--) {
2708        interface_entry = va_arg(interface_list, zend_class_entry *);
2709        zend_do_implement_interface(class_entry, interface_entry TSRMLS_CC);
2710    }
2711
2712    va_end(interface_list);
2713}
2714/* }}} */
2715
2716/* A class that contains at least one abstract method automatically becomes an abstract class.
2717 */
2718ZEND_API zend_class_entry *zend_register_internal_class(zend_class_entry *orig_class_entry TSRMLS_DC) /* {{{ */
2719{
2720    return do_register_internal_class(orig_class_entry, 0 TSRMLS_CC);
2721}
2722/* }}} */
2723
2724ZEND_API zend_class_entry *zend_register_internal_interface(zend_class_entry *orig_class_entry TSRMLS_DC) /* {{{ */
2725{
2726    return do_register_internal_class(orig_class_entry, ZEND_ACC_INTERFACE TSRMLS_CC);
2727}
2728/* }}} */
2729
2730ZEND_API int zend_register_class_alias_ex(const char *name, int name_len, zend_class_entry *ce TSRMLS_DC) /* {{{ */
2731{
2732    zend_string *lcname;
2733
2734    if (name[0] == '\\') {
2735        lcname = zend_string_alloc(name_len-1, 1);
2736        zend_str_tolower_copy(lcname->val, name+1, name_len-1);
2737    } else {
2738        lcname = zend_string_alloc(name_len, 1);
2739        zend_str_tolower_copy(lcname->val, name, name_len);
2740    }
2741    ce = zend_hash_add_ptr(CG(class_table), lcname, ce);
2742    zend_string_release(lcname);
2743    if (ce) {
2744        ce->refcount++;
2745        return SUCCESS;
2746    }
2747    return FAILURE;
2748}
2749/* }}} */
2750
2751ZEND_API int zend_set_hash_symbol(zval *symbol, const char *name, int name_length, zend_bool is_ref, int num_symbol_tables, ...) /* {{{ */
2752{
2753    HashTable *symbol_table;
2754    va_list symbol_table_list;
2755
2756    if (num_symbol_tables <= 0) return FAILURE;
2757
2758    if (is_ref) {
2759        ZVAL_MAKE_REF(symbol);
2760    }
2761
2762    va_start(symbol_table_list, num_symbol_tables);
2763    while (num_symbol_tables-- > 0) {
2764        symbol_table = va_arg(symbol_table_list, HashTable *);
2765        zend_hash_str_update(symbol_table, name, name_length, symbol);
2766        if (Z_REFCOUNTED_P(symbol)) {
2767            Z_ADDREF_P(symbol);
2768        }
2769    }
2770    va_end(symbol_table_list);
2771    return SUCCESS;
2772}
2773/* }}} */
2774
2775/* Disabled functions support */
2776
2777/* {{{ proto void display_disabled_function(void)
2778Dummy function which displays an error when a disabled function is called. */
2779ZEND_API ZEND_FUNCTION(display_disabled_function)
2780{
2781    zend_error(E_WARNING, "%s() has been disabled for security reasons", get_active_function_name(TSRMLS_C));
2782}
2783/* }}} */
2784
2785static zend_function_entry disabled_function[] = {
2786    ZEND_FE(display_disabled_function,          NULL)
2787    ZEND_FE_END
2788};
2789
2790ZEND_API int zend_disable_function(char *function_name, uint function_name_length TSRMLS_DC) /* {{{ */
2791{
2792    int ret;
2793
2794    ret = zend_hash_str_del(CG(function_table), function_name, function_name_length);
2795    if (ret == FAILURE) {
2796        return FAILURE;
2797    }
2798    disabled_function[0].fname = function_name;
2799    return zend_register_functions(NULL, disabled_function, CG(function_table), MODULE_PERSISTENT TSRMLS_CC);
2800}
2801/* }}} */
2802
2803#ifdef ZEND_WIN32
2804#pragma optimize("", off)
2805#endif
2806static zend_object *display_disabled_class(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
2807{
2808    zend_object *intern;
2809
2810    intern = zend_objects_new(class_type TSRMLS_CC);
2811    zend_error(E_WARNING, "%s() has been disabled for security reasons", class_type->name->val);
2812    return intern;
2813}
2814#ifdef ZEND_WIN32
2815#pragma optimize("", on)
2816#endif
2817/* }}} */
2818
2819static const zend_function_entry disabled_class_new[] = {
2820    ZEND_FE_END
2821};
2822
2823ZEND_API int zend_disable_class(char *class_name, uint class_name_length TSRMLS_DC) /* {{{ */
2824{
2825    zend_class_entry *disabled_class;
2826    zend_string *key;
2827
2828    key = zend_string_alloc(class_name_length, 0);
2829    zend_str_tolower_copy(key->val, class_name, class_name_length);
2830    disabled_class = zend_hash_find_ptr(CG(class_table), key);
2831    if (!disabled_class) {
2832        return FAILURE;
2833    }
2834    INIT_CLASS_ENTRY_INIT_METHODS((*disabled_class), disabled_class_new, NULL, NULL, NULL, NULL, NULL);
2835    disabled_class->create_object = display_disabled_class;
2836    zend_hash_clean(&disabled_class->function_table);
2837    return SUCCESS;
2838}
2839/* }}} */
2840
2841static int zend_is_callable_check_class(zend_string *name, zend_fcall_info_cache *fcc, int *strict_class, char **error TSRMLS_DC) /* {{{ */
2842{
2843    int ret = 0;
2844    zend_class_entry *ce;
2845    int name_len = name->len;
2846    zend_string *lcname;
2847    ALLOCA_FLAG(use_heap);
2848
2849    STR_ALLOCA_ALLOC(lcname, name_len, use_heap);
2850    zend_str_tolower_copy(lcname->val, name->val, name_len);
2851
2852    *strict_class = 0;
2853    if (zend_string_equals_literal(lcname, "self")) {
2854        if (!EG(scope)) {
2855            if (error) *error = estrdup("cannot access self:: when no class scope is active");
2856        } else {
2857            fcc->called_scope = EG(current_execute_data) ? EG(current_execute_data)->called_scope : NULL;
2858            fcc->calling_scope = EG(scope);
2859            if (!fcc->object && Z_OBJ(EG(This))) {
2860                fcc->object = Z_OBJ(EG(This));
2861            }
2862            ret = 1;
2863        }
2864    } else if (zend_string_equals_literal(lcname, "parent")) {
2865        if (!EG(scope)) {
2866            if (error) *error = estrdup("cannot access parent:: when no class scope is active");
2867        } else if (!EG(scope)->parent) {
2868            if (error) *error = estrdup("cannot access parent:: when current class scope has no parent");
2869        } else {
2870            fcc->called_scope = EG(current_execute_data) ? EG(current_execute_data)->called_scope : NULL;
2871            fcc->calling_scope = EG(scope)->parent;
2872            if (!fcc->object && Z_OBJ(EG(This))) {
2873                fcc->object = Z_OBJ(EG(This));
2874            }
2875            *strict_class = 1;
2876            ret = 1;
2877        }
2878    } else if (zend_string_equals_literal(lcname, "static")) {
2879        if (!EG(current_execute_data) || !EG(current_execute_data)->called_scope) {
2880            if (error) *error = estrdup("cannot access static:: when no class scope is active");
2881        } else {
2882            fcc->called_scope = EG(current_execute_data)->called_scope;
2883            fcc->calling_scope = EG(current_execute_data)->called_scope;
2884            if (!fcc->object && Z_OBJ(EG(This))) {
2885                fcc->object = Z_OBJ(EG(This));
2886            }
2887            *strict_class = 1;
2888            ret = 1;
2889        }
2890    } else if ((ce = zend_lookup_class_ex(name, NULL, 1 TSRMLS_CC)) != NULL) {
2891        zend_class_entry *scope;
2892        zend_execute_data *ex = EG(current_execute_data);
2893
2894        while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) {
2895            ex = ex->prev_execute_data;
2896        }
2897        scope = ex ? ex->func->common.scope : NULL;
2898        fcc->calling_scope = ce;
2899        if (scope && !fcc->object && Z_OBJ(EG(This)) &&
2900            instanceof_function(Z_OBJCE(EG(This)), scope TSRMLS_CC) &&
2901            instanceof_function(scope, fcc->calling_scope TSRMLS_CC)) {
2902            fcc->object = Z_OBJ(EG(This));
2903            fcc->called_scope = Z_OBJCE(EG(This));
2904        } else {
2905            fcc->called_scope = fcc->object ? zend_get_class_entry(fcc->object TSRMLS_CC) : fcc->calling_scope;
2906        }
2907        *strict_class = 1;
2908        ret = 1;
2909    } else {
2910        if (error) zend_spprintf(error, 0, "class '%.*s' not found", name_len, name->val);
2911    }
2912    STR_ALLOCA_FREE(lcname, use_heap);
2913    return ret;
2914}
2915/* }}} */
2916
2917static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fcall_info_cache *fcc, int strict_class, char **error TSRMLS_DC) /* {{{ */
2918{
2919    zend_class_entry *ce_org = fcc->calling_scope;
2920    int retval = 0;
2921    zend_string *mname, *cname;
2922    zend_string *lmname;
2923    const char *colon;
2924    int clen, mlen;
2925    zend_class_entry *last_scope;
2926    HashTable *ftable;
2927    int call_via_handler = 0;
2928    ALLOCA_FLAG(use_heap)
2929
2930    if (error) {
2931        *error = NULL;
2932    }
2933
2934    fcc->calling_scope = NULL;
2935    fcc->function_handler = NULL;
2936
2937    if (!ce_org) {
2938        zend_string *lmname;
2939
2940        /* Skip leading \ */
2941        if (UNEXPECTED(Z_STRVAL_P(callable)[0] == '\\')) {
2942            STR_ALLOCA_INIT(lmname, Z_STRVAL_P(callable) + 1, Z_STRLEN_P(callable) - 1, use_heap);
2943        } else {
2944            lmname = Z_STR_P(callable);
2945        }
2946        /* Check if function with given name exists.
2947         * This may be a compound name that includes namespace name */
2948        if (EXPECTED((fcc->function_handler = zend_hash_find_ptr(EG(function_table), lmname)) != NULL)) {
2949            if (lmname != Z_STR_P(callable)) {
2950                STR_ALLOCA_FREE(lmname, use_heap);
2951            }
2952            return 1;
2953        } else {
2954            if (lmname == Z_STR_P(callable)) {
2955                STR_ALLOCA_INIT(lmname, Z_STRVAL_P(callable), Z_STRLEN_P(callable), use_heap);
2956            } else {
2957                zend_string_forget_hash_val(lmname);
2958            }
2959            zend_str_tolower(lmname->val, lmname->len);
2960            if ((fcc->function_handler = zend_hash_find_ptr(EG(function_table), lmname)) != NULL) {
2961                STR_ALLOCA_FREE(lmname, use_heap);
2962                return 1;
2963            }
2964        }
2965        if (lmname != Z_STR_P(callable)) {
2966            STR_ALLOCA_FREE(lmname, use_heap);
2967        }
2968    }
2969
2970    /* Split name into class/namespace and method/function names */
2971    if ((colon = zend_memrchr(Z_STRVAL_P(callable), ':', Z_STRLEN_P(callable))) != NULL &&
2972        colon > Z_STRVAL_P(callable) &&
2973        *(colon-1) == ':'
2974    ) {
2975        colon--;
2976        clen = colon - Z_STRVAL_P(callable);
2977        mlen = Z_STRLEN_P(callable) - clen - 2;
2978
2979        if (colon == Z_STRVAL_P(callable)) {
2980            if (error) zend_spprintf(error, 0, "invalid function name");
2981            return 0;
2982        }
2983
2984        /* This is a compound name.
2985         * Try to fetch class and then find static method. */
2986        last_scope = EG(scope);
2987        if (ce_org) {
2988            EG(scope) = ce_org;
2989        }
2990
2991        cname = zend_string_init(Z_STRVAL_P(callable), clen, 0);
2992        if (!zend_is_callable_check_class(cname, fcc, &strict_class, error TSRMLS_CC)) {
2993            zend_string_release(cname);
2994            EG(scope) = last_scope;
2995            return 0;
2996        }
2997        zend_string_release(cname);
2998        EG(scope) = last_scope;
2999
3000        ftable = &fcc->calling_scope->function_table;
3001        if (ce_org && !instanceof_function(ce_org, fcc->calling_scope TSRMLS_CC)) {
3002            if (error) zend_spprintf(error, 0, "class '%s' is not a subclass of '%s'", ce_org->name->val, fcc->calling_scope->name->val);
3003            return 0;
3004        }
3005        mname = zend_string_init(Z_STRVAL_P(callable) + clen + 2, mlen, 0);
3006    } else if (ce_org) {
3007        /* Try to fetch find static method of given class. */
3008        mlen = Z_STRLEN_P(callable);
3009        mname = Z_STR_P(callable);
3010        zend_string_addref(mname);
3011        ftable = &ce_org->function_table;
3012        fcc->calling_scope = ce_org;
3013    } else {
3014        /* We already checked for plain function before. */
3015        if (error && !(check_flags & IS_CALLABLE_CHECK_SILENT)) {
3016            zend_spprintf(error, 0, "function '%s' not found or invalid function name", Z_STRVAL_P(callable));
3017        }
3018        return 0;
3019    }
3020
3021    lmname = zend_string_alloc(mlen, 0);
3022    zend_str_tolower_copy(lmname->val, mname->val, mlen);
3023    if (strict_class &&
3024        fcc->calling_scope &&
3025        zend_string_equals_literal(lmname, ZEND_CONSTRUCTOR_FUNC_NAME)) {
3026        fcc->function_handler = fcc->calling_scope->constructor;
3027        if (fcc->function_handler) {
3028            retval = 1;
3029        }
3030    } else if ((fcc->function_handler = zend_hash_find_ptr(ftable, lmname)) != NULL) {
3031        retval = 1;
3032        if ((fcc->function_handler->op_array.fn_flags & ZEND_ACC_CHANGED) &&
3033            !strict_class && EG(scope) &&
3034            instanceof_function(fcc->function_handler->common.scope, EG(scope) TSRMLS_CC)) {
3035            zend_function *priv_fbc;
3036
3037            if ((priv_fbc = zend_hash_find_ptr(&EG(scope)->function_table, lmname)) != NULL
3038                && priv_fbc->common.fn_flags & ZEND_ACC_PRIVATE
3039                && priv_fbc->common.scope == EG(scope)) {
3040                fcc->function_handler = priv_fbc;
3041            }
3042        }
3043        if ((check_flags & IS_CALLABLE_CHECK_NO_ACCESS) == 0 &&
3044            (fcc->calling_scope &&
3045             ((fcc->object && fcc->calling_scope->__call) ||
3046              (!fcc->object && fcc->calling_scope->__callstatic)))) {
3047            if (fcc->function_handler->op_array.fn_flags & ZEND_ACC_PRIVATE) {
3048                if (!zend_check_private(fcc->function_handler, fcc->object ? zend_get_class_entry(fcc->object TSRMLS_CC) : EG(scope), lmname TSRMLS_CC)) {
3049                    retval = 0;
3050                    fcc->function_handler = NULL;
3051                    goto get_function_via_handler;
3052                }
3053            } else if (fcc->function_handler->common.fn_flags & ZEND_ACC_PROTECTED) {
3054                if (!zend_check_protected(fcc->function_handler->common.scope, EG(scope))) {
3055                    retval = 0;
3056                    fcc->function_handler = NULL;
3057                    goto get_function_via_handler;
3058                }
3059            }
3060        }
3061    } else {
3062get_function_via_handler:
3063        if (fcc->object && fcc->calling_scope == ce_org) {
3064            if (strict_class && ce_org->__call) {
3065                fcc->function_handler = emalloc(sizeof(zend_internal_function));
3066                fcc->function_handler->internal_function.type = ZEND_INTERNAL_FUNCTION;
3067                fcc->function_handler->internal_function.module = (ce_org->type == ZEND_INTERNAL_CLASS) ? ce_org->info.internal.module : NULL;
3068                fcc->function_handler->internal_function.handler = zend_std_call_user_call;
3069                fcc->function_handler->internal_function.arg_info = NULL;
3070                fcc->function_handler->internal_function.num_args = 0;
3071                fcc->function_handler->internal_function.scope = ce_org;
3072                fcc->function_handler->internal_function.fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
3073                fcc->function_handler->internal_function.function_name = mname;
3074                zend_string_addref(mname);
3075                call_via_handler = 1;
3076                retval = 1;
3077            } else if (fcc->object->handlers->get_method) {
3078                fcc->function_handler = fcc->object->handlers->get_method(&fcc->object, mname, NULL TSRMLS_CC);
3079                if (fcc->function_handler) {
3080                    if (strict_class &&
3081                        (!fcc->function_handler->common.scope ||
3082                         !instanceof_function(ce_org, fcc->function_handler->common.scope TSRMLS_CC))) {
3083                        if ((fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0) {
3084                            if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION) {
3085                                zend_string_release(fcc->function_handler->common.function_name);
3086                            }
3087                            efree(fcc->function_handler);
3088                        }
3089                    } else {
3090                        retval = 1;
3091                        call_via_handler = (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0;
3092                    }
3093                }
3094            }
3095        } else if (fcc->calling_scope) {
3096            if (fcc->calling_scope->get_static_method) {
3097                fcc->function_handler = fcc->calling_scope->get_static_method(fcc->calling_scope, mname TSRMLS_CC);
3098            } else {
3099                fcc->function_handler = zend_std_get_static_method(fcc->calling_scope, mname, NULL TSRMLS_CC);
3100            }
3101            if (fcc->function_handler) {
3102                retval = 1;
3103                call_via_handler = (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0;
3104                if (call_via_handler && !fcc->object && Z_OBJ(EG(This)) &&
3105                    Z_OBJ_HT(EG(This))->get_class_entry &&
3106                    instanceof_function(Z_OBJCE(EG(This)), fcc->calling_scope TSRMLS_CC)) {
3107                    fcc->object = Z_OBJ(EG(This));
3108                }
3109            }
3110        }
3111    }
3112
3113    if (retval) {
3114        if (fcc->calling_scope && !call_via_handler) {
3115            if (!fcc->object && (fcc->function_handler->common.fn_flags & ZEND_ACC_ABSTRACT)) {
3116                if (error) {
3117                    zend_spprintf(error, 0, "cannot call abstract method %s::%s()", fcc->calling_scope->name->val, fcc->function_handler->common.function_name->val);
3118                    retval = 0;
3119                } else {
3120                    zend_error(E_ERROR, "Cannot call abstract method %s::%s()", fcc->calling_scope->name->val, fcc->function_handler->common.function_name->val);
3121                }
3122            } else if (!fcc->object && !(fcc->function_handler->common.fn_flags & ZEND_ACC_STATIC)) {
3123                int severity;
3124                char *verb;
3125                if (fcc->function_handler->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
3126                    severity = E_STRICT;
3127                    verb = "should not";
3128                } else {
3129                    /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */
3130                    severity = E_ERROR;
3131                    verb = "cannot";
3132                }
3133                if ((check_flags & IS_CALLABLE_CHECK_IS_STATIC) != 0) {
3134                    retval = 0;
3135                }
3136                if (Z_OBJ(EG(This)) && instanceof_function(Z_OBJCE(EG(This)), fcc->calling_scope TSRMLS_CC)) {
3137                    fcc->object = Z_OBJ(EG(This));
3138                    if (error) {
3139                        zend_spprintf(error, 0, "non-static method %s::%s() %s be called statically, assuming $this from compatible context %s", fcc->calling_scope->name->val, fcc->function_handler->common.function_name->val, verb, Z_OBJCE(EG(This))->name->val);
3140                        if (severity == E_ERROR) {
3141                            retval = 0;
3142                        }
3143                    } else if (retval) {
3144                        zend_error(severity, "Non-static method %s::%s() %s be called statically, assuming $this from compatible context %s", fcc->calling_scope->name->val, fcc->function_handler->common.function_name->val, verb, Z_OBJCE(EG(This))->name->val);
3145                    }
3146                } else {
3147                    if (error) {
3148                        zend_spprintf(error, 0, "non-static method %s::%s() %s be called statically", fcc->calling_scope->name->val, fcc->function_handler->common.function_name->val, verb);
3149                        if (severity == E_ERROR) {
3150                            retval = 0;
3151                        }
3152                    } else if (retval) {
3153                        zend_error(severity, "Non-static method %s::%s() %s be called statically", fcc->calling_scope->name->val, fcc->function_handler->common.function_name->val, verb);
3154                    }
3155                }
3156            }
3157            if (retval && (check_flags & IS_CALLABLE_CHECK_NO_ACCESS) == 0) {
3158                if (fcc->function_handler->op_array.fn_flags & ZEND_ACC_PRIVATE) {
3159                    if (!zend_check_private(fcc->function_handler, fcc->object ? zend_get_class_entry(fcc->object TSRMLS_CC) : EG(scope), lmname TSRMLS_CC)) {
3160                        if (error) {
3161                            if (*error) {
3162                                efree(*error);
3163                            }
3164                            zend_spprintf(error, 0, "cannot access private method %s::%s()", fcc->calling_scope->name->val, fcc->function_handler->common.function_name->val);
3165                        }
3166                        retval = 0;
3167                    }
3168                } else if ((fcc->function_handler->common.fn_flags & ZEND_ACC_PROTECTED)) {
3169                    if (!zend_check_protected(fcc->function_handler->common.scope, EG(scope))) {
3170                        if (error) {
3171                            if (*error) {
3172                                efree(*error);
3173                            }
3174                            zend_spprintf(error, 0, "cannot access protected method %s::%s()", fcc->calling_scope->name->val, fcc->function_handler->common.function_name->val);
3175                        }
3176                        retval = 0;
3177                    }
3178                }
3179            }
3180        }
3181    } else if (error && !(check_flags & IS_CALLABLE_CHECK_SILENT)) {
3182        if (fcc->calling_scope) {
3183            if (error) zend_spprintf(error, 0, "class '%s' does not have a method '%s'", fcc->calling_scope->name->val, mname->val);
3184        } else {
3185            if (error) zend_spprintf(error, 0, "function '%s' does not exist", mname->val);
3186        }
3187    }
3188    zend_string_free(lmname);
3189    zend_string_release(mname);
3190
3191    if (fcc->object) {
3192        fcc->called_scope = zend_get_class_entry(fcc->object TSRMLS_CC);
3193    }
3194    if (retval) {
3195        fcc->initialized = 1;
3196    }
3197    return retval;
3198}
3199/* }}} */
3200
3201ZEND_API zend_bool zend_is_callable_ex(zval *callable, zend_object *object, uint check_flags, zend_string **callable_name, zend_fcall_info_cache *fcc, char **error TSRMLS_DC) /* {{{ */
3202{
3203    zend_bool ret;
3204    zend_fcall_info_cache fcc_local;
3205
3206    if (callable_name) {
3207        *callable_name = NULL;
3208    }
3209    if (fcc == NULL) {
3210        fcc = &fcc_local;
3211    }
3212    if (error) {
3213        *error = NULL;
3214    }
3215
3216    fcc->initialized = 0;
3217    fcc->calling_scope = NULL;
3218    fcc->called_scope = NULL;
3219    fcc->function_handler = NULL;
3220    fcc->calling_scope = NULL;
3221    fcc->object = NULL;
3222
3223    if (object &&
3224        (!EG(objects_store).object_buckets ||
3225         !IS_OBJ_VALID(EG(objects_store).object_buckets[object->handle]))) {
3226        return 0;
3227    }
3228
3229    switch (Z_TYPE_P(callable)) {
3230        case IS_STRING:
3231            if (object) {
3232                fcc->object = object;
3233                fcc->calling_scope = zend_get_class_entry(object TSRMLS_CC);
3234                if (callable_name) {
3235                    char *ptr;
3236
3237                    *callable_name = zend_string_alloc(fcc->calling_scope->name->len + Z_STRLEN_P(callable) + sizeof("::") - 1, 0);
3238                    ptr = (*callable_name)->val;
3239                    memcpy(ptr, fcc->calling_scope->name->val, fcc->calling_scope->name->len);
3240                    ptr += fcc->calling_scope->name->len;
3241                    memcpy(ptr, "::", sizeof("::") - 1);
3242                    ptr += sizeof("::") - 1;
3243                    memcpy(ptr, Z_STRVAL_P(callable), Z_STRLEN_P(callable) + 1);
3244                }
3245            } else if (callable_name) {
3246                *callable_name = zend_string_copy(Z_STR_P(callable));
3247            }
3248            if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
3249                fcc->called_scope = fcc->calling_scope;
3250                return 1;
3251            }
3252
3253            ret = zend_is_callable_check_func(check_flags, callable, fcc, 0, error TSRMLS_CC);
3254            if (fcc == &fcc_local &&
3255                fcc->function_handler &&
3256                ((fcc->function_handler->type == ZEND_INTERNAL_FUNCTION &&
3257                  (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER)) ||
3258                 fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
3259                 fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
3260                if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION) {
3261                    zend_string_release(fcc->function_handler->common.function_name);
3262                }
3263                efree(fcc->function_handler);
3264            }
3265            return ret;
3266
3267        case IS_ARRAY:
3268            {
3269                zval *method = NULL;
3270                zval *obj = NULL;
3271                int strict_class = 0;
3272
3273                if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2) {
3274                    obj = zend_hash_index_find(Z_ARRVAL_P(callable), 0);
3275                    method = zend_hash_index_find(Z_ARRVAL_P(callable), 1);
3276                }
3277
3278                do {
3279                    if (obj == NULL || method == NULL) {
3280                        break;
3281                    }
3282
3283                    ZVAL_DEREF(method);
3284                    if (Z_TYPE_P(method) != IS_STRING) {
3285                        break;
3286                    }
3287
3288                    ZVAL_DEREF(obj);
3289                    if (Z_TYPE_P(obj) == IS_STRING) {
3290                        if (callable_name) {
3291                            char *ptr;
3292
3293
3294                            *callable_name = zend_string_alloc(Z_STRLEN_P(obj) + Z_STRLEN_P(method) + sizeof("::") - 1, 0);
3295                            ptr = (*callable_name)->val;
3296                            memcpy(ptr, Z_STRVAL_P(obj), Z_STRLEN_P(obj));
3297                            ptr += Z_STRLEN_P(obj);
3298                            memcpy(ptr, "::", sizeof("::") - 1);
3299                            ptr += sizeof("::") - 1;
3300                            memcpy(ptr, Z_STRVAL_P(method), Z_STRLEN_P(method) + 1);
3301                        }
3302
3303                        if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
3304                            return 1;
3305                        }
3306
3307                        if (!zend_is_callable_check_class(Z_STR_P(obj), fcc, &strict_class, error TSRMLS_CC)) {
3308                            return 0;
3309                        }
3310
3311                    } else if (Z_TYPE_P(obj) == IS_OBJECT) {
3312                        if (!EG(objects_store).object_buckets ||
3313                            !IS_OBJ_VALID(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(obj)])) {
3314                            return 0;
3315                        }
3316
3317                        fcc->calling_scope = Z_OBJCE_P(obj); /* TBFixed: what if it's overloaded? */
3318
3319                        fcc->object = Z_OBJ_P(obj);
3320
3321                        if (callable_name) {
3322                            char *ptr;
3323
3324                            *callable_name = zend_string_alloc(fcc->calling_scope->name->len + Z_STRLEN_P(method) + sizeof("::") - 1, 0);
3325                            ptr = (*callable_name)->val;
3326                            memcpy(ptr, fcc->calling_scope->name->val, fcc->calling_scope->name->len);
3327                            ptr += fcc->calling_scope->name->len;
3328                            memcpy(ptr, "::", sizeof("::") - 1);
3329                            ptr += sizeof("::") - 1;
3330                            memcpy(ptr, Z_STRVAL_P(method), Z_STRLEN_P(method) + 1);
3331                        }
3332
3333                        if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
3334                            fcc->called_scope = fcc->calling_scope;
3335                            return 1;
3336                        }
3337                    } else {
3338                        break;
3339                    }
3340
3341                    ret = zend_is_callable_check_func(check_flags, method, fcc, strict_class, error TSRMLS_CC);
3342                    if (fcc == &fcc_local &&
3343                        fcc->function_handler &&
3344                        ((fcc->function_handler->type == ZEND_INTERNAL_FUNCTION &&
3345                          (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER)) ||
3346                         fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
3347                         fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
3348                        if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION) {
3349                            zend_string_release(fcc->function_handler->common.function_name);
3350                        }
3351                        efree(fcc->function_handler);
3352                    }
3353                    return ret;
3354
3355                } while (0);
3356                if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2) {
3357                    if (!obj || (!Z_ISREF_P(obj)?
3358                                (Z_TYPE_P(obj) != IS_STRING && Z_TYPE_P(obj) != IS_OBJECT) :
3359                                (Z_TYPE_P(Z_REFVAL_P(obj)) != IS_STRING && Z_TYPE_P(Z_REFVAL_P(obj)) != IS_OBJECT))) {
3360                        if (error) zend_spprintf(error, 0, "first array member is not a valid class name or object");
3361                    } else {
3362                        if (error) zend_spprintf(error, 0, "second array member is not a valid method");
3363                    }
3364                } else {
3365                    if (error) zend_spprintf(error, 0, "array must have exactly two members");
3366                }
3367                if (callable_name) {
3368                    *callable_name = zend_string_init("Array", sizeof("Array")-1, 0);
3369                }
3370            }
3371            return 0;
3372
3373        case IS_OBJECT:
3374            if (Z_OBJ_HANDLER_P(callable, get_closure) && Z_OBJ_HANDLER_P(callable, get_closure)(callable, &fcc->calling_scope, &fcc->function_handler, &fcc->object TSRMLS_CC) == SUCCESS) {
3375                fcc->called_scope = fcc->calling_scope;
3376                if (callable_name) {
3377                    zend_class_entry *ce = Z_OBJCE_P(callable); /* TBFixed: what if it's overloaded? */
3378
3379                    *callable_name = zend_string_alloc(ce->name->len + sizeof("::__invoke") - 1, 0);
3380                    memcpy((*callable_name)->val, ce->name->val, ce->name->len);
3381                    memcpy((*callable_name)->val + ce->name->len, "::__invoke", sizeof("::__invoke"));
3382                }
3383                return 1;
3384            }
3385            /* break missing intentionally */
3386
3387        default:
3388            if (callable_name) {
3389                *callable_name = zval_get_string(callable);
3390            }
3391            if (error) zend_spprintf(error, 0, "no array or string given");
3392            return 0;
3393    }
3394}
3395/* }}} */
3396
3397ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, zend_string **callable_name TSRMLS_DC) /* {{{ */
3398{
3399    return zend_is_callable_ex(callable, NULL, check_flags, callable_name, NULL, NULL TSRMLS_CC);
3400}
3401/* }}} */
3402
3403ZEND_API zend_bool zend_make_callable(zval *callable, zend_string **callable_name TSRMLS_DC) /* {{{ */
3404{
3405    zend_fcall_info_cache fcc;
3406
3407    if (zend_is_callable_ex(callable, NULL, IS_CALLABLE_STRICT, callable_name, &fcc, NULL TSRMLS_CC)) {
3408        if (Z_TYPE_P(callable) == IS_STRING && fcc.calling_scope) {
3409            zval_dtor(callable);
3410            array_init(callable);
3411            add_next_index_str(callable, zend_string_copy(fcc.calling_scope->name));
3412            add_next_index_str(callable, zend_string_copy(fcc.function_handler->common.function_name));
3413        }
3414        if (fcc.function_handler &&
3415            ((fcc.function_handler->type == ZEND_INTERNAL_FUNCTION &&
3416              (fcc.function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER)) ||
3417             fcc.function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
3418             fcc.function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
3419            if (fcc.function_handler->type != ZEND_OVERLOADED_FUNCTION) {
3420                zend_string_release(fcc.function_handler->common.function_name);
3421            }
3422            efree(fcc.function_handler);
3423        }
3424        return 1;
3425    }
3426    return 0;
3427}
3428/* }}} */
3429
3430ZEND_API int zend_fcall_info_init(zval *callable, uint check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string **callable_name, char **error TSRMLS_DC) /* {{{ */
3431{
3432    if (!zend_is_callable_ex(callable, NULL, check_flags, callable_name, fcc, error TSRMLS_CC)) {
3433        return FAILURE;
3434    }
3435
3436    fci->size = sizeof(*fci);
3437    fci->function_table = fcc->calling_scope ? &fcc->calling_scope->function_table : EG(function_table);
3438    fci->object = fcc->object;
3439    ZVAL_COPY_VALUE(&fci->function_name, callable);
3440    fci->retval = NULL;
3441    fci->param_count = 0;
3442    fci->params = NULL;
3443    fci->no_separation = 1;
3444    fci->symbol_table = NULL;
3445
3446    return SUCCESS;
3447}
3448/* }}} */
3449
3450ZEND_API void zend_fcall_info_args_clear(zend_fcall_info *fci, int free_mem) /* {{{ */
3451{
3452    if (fci->params) {
3453        int i;
3454
3455        for (i = 0; i < fci->param_count; i++) {
3456            zval_ptr_dtor(&fci->params[i]);
3457        }
3458        if (free_mem) {
3459            efree(fci->params);
3460            fci->params = NULL;
3461        }
3462    }
3463    fci->param_count = 0;
3464}
3465/* }}} */
3466
3467ZEND_API void zend_fcall_info_args_save(zend_fcall_info *fci, int *param_count, zval **params) /* {{{ */
3468{
3469    *param_count = fci->param_count;
3470    *params = fci->params;
3471    fci->param_count = 0;
3472    fci->params = NULL;
3473}
3474/* }}} */
3475
3476ZEND_API void zend_fcall_info_args_restore(zend_fcall_info *fci, int param_count, zval *params) /* {{{ */
3477{
3478    zend_fcall_info_args_clear(fci, 1);
3479    fci->param_count = param_count;
3480    fci->params = params;
3481}
3482/* }}} */
3483
3484ZEND_API int zend_fcall_info_args_ex(zend_fcall_info *fci, zend_function *func, zval *args TSRMLS_DC) /* {{{ */
3485{
3486    zval *arg, *params;
3487    int n = 1;
3488
3489    zend_fcall_info_args_clear(fci, !args);
3490
3491    if (!args) {
3492        return SUCCESS;
3493    }
3494
3495    if (Z_TYPE_P(args) != IS_ARRAY) {
3496        return FAILURE;
3497    }
3498
3499    fci->param_count = zend_hash_num_elements(Z_ARRVAL_P(args));
3500    fci->params = params = (zval *) erealloc(fci->params, fci->param_count * sizeof(zval));
3501
3502    ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args), arg) {
3503        if (func && !Z_ISREF_P(arg) && ARG_SHOULD_BE_SENT_BY_REF(func, n)) {
3504            ZVAL_NEW_REF(params, arg);
3505            if (Z_REFCOUNTED_P(arg)) {
3506                Z_ADDREF_P(arg);
3507            }
3508        } else {
3509            ZVAL_COPY(params, arg);
3510        }
3511        params++;
3512        n++;
3513    } ZEND_HASH_FOREACH_END();
3514
3515    return SUCCESS;
3516}
3517/* }}} */
3518
3519ZEND_API int zend_fcall_info_args(zend_fcall_info *fci, zval *args TSRMLS_DC) /* {{{ */
3520{
3521    return zend_fcall_info_args_ex(fci, NULL, args TSRMLS_CC);
3522}
3523/* }}} */
3524
3525ZEND_API int zend_fcall_info_argp(zend_fcall_info *fci TSRMLS_DC, int argc, zval *argv) /* {{{ */
3526{
3527    int i;
3528
3529    if (argc < 0) {
3530        return FAILURE;
3531    }
3532
3533    zend_fcall_info_args_clear(fci, !argc);
3534
3535    if (argc) {
3536        fci->param_count = argc;
3537        fci->params = (zval *) erealloc(fci->params, fci->param_count * sizeof(zval));
3538
3539        for (i = 0; i < argc; ++i) {
3540            ZVAL_COPY_VALUE(&fci->params[i], &argv[i]);
3541        }
3542    }
3543
3544    return SUCCESS;
3545}
3546/* }}} */
3547
3548ZEND_API int zend_fcall_info_argv(zend_fcall_info *fci TSRMLS_DC, int argc, va_list *argv) /* {{{ */
3549{
3550    int i;
3551    zval *arg;
3552
3553    if (argc < 0) {
3554        return FAILURE;
3555    }
3556
3557    zend_fcall_info_args_clear(fci, !argc);
3558
3559    if (argc) {
3560        fci->param_count = argc;
3561        fci->params = (zval *) erealloc(fci->params, fci->param_count * sizeof(zval));
3562
3563        for (i = 0; i < argc; ++i) {
3564            arg = va_arg(*argv, zval *);
3565            ZVAL_COPY_VALUE(&fci->params[i], arg);
3566        }
3567    }
3568
3569    return SUCCESS;
3570}
3571/* }}} */
3572
3573ZEND_API int zend_fcall_info_argn(zend_fcall_info *fci TSRMLS_DC, int argc, ...) /* {{{ */
3574{
3575    int ret;
3576    va_list argv;
3577
3578    va_start(argv, argc);
3579    ret = zend_fcall_info_argv(fci TSRMLS_CC, argc, &argv);
3580    va_end(argv);
3581
3582    return ret;
3583}
3584/* }}} */
3585
3586ZEND_API int zend_fcall_info_call(zend_fcall_info *fci, zend_fcall_info_cache *fcc, zval *retval_ptr, zval *args TSRMLS_DC) /* {{{ */
3587{
3588    zval retval, *org_params = NULL;
3589    int result, org_count = 0;
3590
3591    fci->retval = retval_ptr ? retval_ptr : &retval;
3592    if (args) {
3593        zend_fcall_info_args_save(fci, &org_count, &org_params);
3594        zend_fcall_info_args(fci, args TSRMLS_CC);
3595    }
3596    result = zend_call_function(fci, fcc TSRMLS_CC);
3597
3598    if (!retval_ptr && Z_TYPE(retval) != IS_UNDEF) {
3599        zval_ptr_dtor(&retval);
3600    }
3601    if (args) {
3602        zend_fcall_info_args_restore(fci, org_count, org_params);
3603    }
3604    return result;
3605}
3606/* }}} */
3607
3608ZEND_API const char *zend_get_module_version(const char *module_name) /* {{{ */
3609{
3610    zend_string *lname;
3611    int name_len = strlen(module_name);
3612    zend_module_entry *module;
3613
3614    lname = zend_string_alloc(name_len, 0);
3615    zend_str_tolower_copy(lname->val, module_name, name_len);
3616    module = zend_hash_find_ptr(&module_registry, lname);
3617    zend_string_free(lname);
3618    return module ? module->version : NULL;
3619}
3620/* }}} */
3621
3622ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment TSRMLS_DC) /* {{{ */
3623{
3624    zend_property_info *property_info, *property_info_ptr;
3625
3626    if (ce->type == ZEND_INTERNAL_CLASS) {
3627        property_info = pemalloc(sizeof(zend_property_info), 1);
3628    } else {
3629        property_info = zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
3630    }
3631
3632    if (Z_CONSTANT_P(property)) {
3633        ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
3634    }
3635    if (!(access_type & ZEND_ACC_PPP_MASK)) {
3636        access_type |= ZEND_ACC_PUBLIC;
3637    }
3638    if (access_type & ZEND_ACC_STATIC) {
3639        if ((property_info_ptr = zend_hash_find_ptr(&ce->properties_info, name)) != NULL &&
3640            (property_info_ptr->flags & ZEND_ACC_STATIC) != 0) {
3641            property_info->offset = property_info_ptr->offset;
3642            zval_ptr_dtor(&ce->default_static_members_table[property_info->offset]);
3643            zend_hash_del(&ce->properties_info, name);
3644        } else {
3645            property_info->offset = ce->default_static_members_count++;
3646            ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(zval) * ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
3647        }
3648        ZVAL_COPY_VALUE(&ce->default_static_members_table[property_info->offset], property);
3649        if (ce->type == ZEND_USER_CLASS) {
3650            ce->static_members_table = ce->default_static_members_table;
3651        }
3652    } else {
3653        if ((property_info_ptr = zend_hash_find_ptr(&ce->properties_info, name)) != NULL &&
3654            (property_info_ptr->flags & ZEND_ACC_STATIC) == 0) {
3655            property_info->offset = property_info_ptr->offset;
3656            zval_ptr_dtor(&ce->default_properties_table[property_info->offset]);
3657            zend_hash_del(&ce->properties_info, name);
3658        } else {
3659            property_info->offset = ce->default_properties_count++;
3660            ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval) * ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
3661        }
3662        ZVAL_COPY_VALUE(&ce->default_properties_table[property_info->offset], property);
3663    }
3664    if (ce->type & ZEND_INTERNAL_CLASS) {
3665        switch(Z_TYPE_P(property)) {
3666            case IS_ARRAY:
3667            case IS_OBJECT:
3668            case IS_RESOURCE:
3669                zend_error(E_CORE_ERROR, "Internal zval's can't be arrays, objects or resources");
3670                break;
3671            default:
3672                break;
3673        }
3674    }
3675    switch (access_type & ZEND_ACC_PPP_MASK) {
3676        case ZEND_ACC_PRIVATE: {
3677                property_info->name = zend_mangle_property_name(ce->name->val, ce->name->len, name->val, name->len, ce->type & ZEND_INTERNAL_CLASS);
3678            }
3679            break;
3680        case ZEND_ACC_PROTECTED: {
3681                property_info->name = zend_mangle_property_name("*", 1, name->val, name->len, ce->type & ZEND_INTERNAL_CLASS);
3682            }
3683            break;
3684        case ZEND_ACC_PUBLIC:
3685            property_info->name = zend_string_copy(name);
3686            break;
3687    }
3688
3689    property_info->name = zend_new_interned_string(property_info->name TSRMLS_CC);
3690    property_info->flags = access_type;
3691    property_info->doc_comment = doc_comment;
3692    property_info->ce = ce;
3693    zend_hash_update_ptr(&ce->properties_info, name, property_info);
3694
3695    return SUCCESS;
3696}
3697/* }}} */
3698
3699ZEND_API int zend_declare_property(zend_class_entry *ce, const char *name, int name_length, zval *property, int access_type TSRMLS_DC) /* {{{ */
3700{
3701    zend_string *key = zend_string_init(name, name_length, ce->type & ZEND_INTERNAL_CLASS);
3702    int ret = zend_declare_property_ex(ce, key, property, access_type, NULL TSRMLS_CC);
3703    zend_string_release(key);
3704    return ret;
3705}
3706/* }}} */
3707
3708ZEND_API int zend_declare_property_null(zend_class_entry *ce, const char *name, int name_length, int access_type TSRMLS_DC) /* {{{ */
3709{
3710    zval property;
3711
3712    ZVAL_NULL(&property);
3713    return zend_declare_property(ce, name, name_length, &property, access_type TSRMLS_CC);
3714}
3715/* }}} */
3716
3717ZEND_API int zend_declare_property_bool(zend_class_entry *ce, const char *name, int name_length, zend_long value, int access_type TSRMLS_DC) /* {{{ */
3718{
3719    zval property;
3720
3721    ZVAL_BOOL(&property, value);
3722    return zend_declare_property(ce, name, name_length, &property, access_type TSRMLS_CC);
3723}
3724/* }}} */
3725
3726ZEND_API int zend_declare_property_long(zend_class_entry *ce, const char *name, int name_length, zend_long value, int access_type TSRMLS_DC) /* {{{ */
3727{
3728    zval property;
3729
3730    ZVAL_LONG(&property, value);
3731    return zend_declare_property(ce, name, name_length, &property, access_type TSRMLS_CC);
3732}
3733/* }}} */
3734
3735ZEND_API int zend_declare_property_double(zend_class_entry *ce, const char *name, int name_length, double value, int access_type TSRMLS_DC) /* {{{ */
3736{
3737    zval property;
3738
3739    ZVAL_DOUBLE(&property, value);
3740    return zend_declare_property(ce, name, name_length, &property, access_type TSRMLS_CC);
3741}
3742/* }}} */
3743
3744ZEND_API int zend_declare_property_string(zend_class_entry *ce, const char *name, int name_length, const char *value, int access_type TSRMLS_DC) /* {{{ */
3745{
3746    zval property;
3747
3748    ZVAL_NEW_STR(&property, zend_string_init(value, strlen(value), ce->type & ZEND_INTERNAL_CLASS));
3749    return zend_declare_property(ce, name, name_length, &property, access_type TSRMLS_CC);
3750}
3751/* }}} */
3752
3753ZEND_API int zend_declare_property_stringl(zend_class_entry *ce, const char *name, int name_length, const char *value, size_t value_len, int access_type TSRMLS_DC) /* {{{ */
3754{
3755    zval property;
3756
3757    ZVAL_NEW_STR(&property, zend_string_init(value, value_len, ce->type & ZEND_INTERNAL_CLASS));
3758    return zend_declare_property(ce, name, name_length, &property, access_type TSRMLS_CC);
3759}
3760/* }}} */
3761
3762ZEND_API int zend_declare_class_constant(zend_class_entry *ce, const char *name, size_t name_length, zval *value TSRMLS_DC) /* {{{ */
3763{
3764    if (Z_CONSTANT_P(value)) {
3765        ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
3766    }
3767    return zend_hash_str_update(&ce->constants_table, name, name_length, value) ?
3768        SUCCESS : FAILURE;
3769}
3770/* }}} */
3771
3772ZEND_API int zend_declare_class_constant_null(zend_class_entry *ce, const char *name, size_t name_length TSRMLS_DC) /* {{{ */
3773{
3774    zval constant;
3775
3776    ZVAL_NULL(&constant);
3777    return zend_declare_class_constant(ce, name, name_length, &constant TSRMLS_CC);
3778}
3779/* }}} */
3780
3781ZEND_API int zend_declare_class_constant_long(zend_class_entry *ce, const char *name, size_t name_length, zend_long value TSRMLS_DC) /* {{{ */
3782{
3783    zval constant;
3784
3785    ZVAL_LONG(&constant, value);
3786    return zend_declare_class_constant(ce, name, name_length, &constant TSRMLS_CC);
3787}
3788/* }}} */
3789
3790ZEND_API int zend_declare_class_constant_bool(zend_class_entry *ce, const char *name, size_t name_length, zend_bool value TSRMLS_DC) /* {{{ */
3791{
3792    zval constant;
3793
3794    ZVAL_BOOL(&constant, value);
3795    return zend_declare_class_constant(ce, name, name_length, &constant TSRMLS_CC);
3796}
3797/* }}} */
3798
3799ZEND_API int zend_declare_class_constant_double(zend_class_entry *ce, const char *name, size_t name_length, double value TSRMLS_DC) /* {{{ */
3800{
3801    zval constant;
3802
3803    ZVAL_DOUBLE(&constant, value);
3804    return zend_declare_class_constant(ce, name, name_length, &constant TSRMLS_CC);
3805}
3806/* }}} */
3807
3808ZEND_API int zend_declare_class_constant_stringl(zend_class_entry *ce, const char *name, size_t name_length, const char *value, size_t value_length TSRMLS_DC) /* {{{ */
3809{
3810    zval constant;
3811
3812    ZVAL_NEW_STR(&constant, zend_string_init(value, value_length, ce->type & ZEND_INTERNAL_CLASS));
3813    return zend_declare_class_constant(ce, name, name_length, &constant TSRMLS_CC);
3814}
3815/* }}} */
3816
3817ZEND_API int zend_declare_class_constant_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value TSRMLS_DC) /* {{{ */
3818{
3819    return zend_declare_class_constant_stringl(ce, name, name_length, value, strlen(value) TSRMLS_CC);
3820}
3821/* }}} */
3822
3823ZEND_API void zend_update_property(zend_class_entry *scope, zval *object, const char *name, int name_length, zval *value TSRMLS_DC) /* {{{ */
3824{
3825    zval property;
3826    zend_class_entry *old_scope = EG(scope);
3827
3828    EG(scope) = scope;
3829
3830    if (!Z_OBJ_HT_P(object)->write_property) {
3831        zend_string *class_name = zend_get_object_classname(Z_OBJ_P(object) TSRMLS_CC);
3832        zend_error(E_CORE_ERROR, "Property %s of class %s cannot be updated", name, class_name->val);
3833    }
3834    ZVAL_STRINGL(&property, name, name_length);
3835    Z_OBJ_HT_P(object)->write_property(object, &property, value, NULL TSRMLS_CC);
3836    zval_ptr_dtor(&property);
3837
3838    EG(scope) = old_scope;
3839}
3840/* }}} */
3841
3842ZEND_API void zend_update_property_null(zend_class_entry *scope, zval *object, const char *name, int name_length TSRMLS_DC) /* {{{ */
3843{
3844    zval tmp;
3845
3846    ZVAL_NULL(&tmp);
3847    zend_update_property(scope, object, name, name_length, &tmp TSRMLS_CC);
3848}
3849/* }}} */
3850
3851ZEND_API void zend_update_property_bool(zend_class_entry *scope, zval *object, const char *name, int name_length, zend_long value TSRMLS_DC) /* {{{ */
3852{
3853    zval tmp;
3854
3855    ZVAL_BOOL(&tmp, value);
3856    zend_update_property(scope, object, name, name_length, &tmp TSRMLS_CC);
3857}
3858/* }}} */
3859
3860ZEND_API void zend_update_property_long(zend_class_entry *scope, zval *object, const char *name, int name_length, zend_long value TSRMLS_DC) /* {{{ */
3861{
3862    zval tmp;
3863
3864    ZVAL_LONG(&tmp, value);
3865    zend_update_property(scope, object, name, name_length, &tmp TSRMLS_CC);
3866}
3867/* }}} */
3868
3869ZEND_API void zend_update_property_double(zend_class_entry *scope, zval *object, const char *name, int name_length, double value TSRMLS_DC) /* {{{ */
3870{
3871    zval tmp;
3872
3873    ZVAL_DOUBLE(&tmp, value);
3874    zend_update_property(scope, object, name, name_length, &tmp TSRMLS_CC);
3875}
3876/* }}} */
3877
3878ZEND_API void zend_update_property_str(zend_class_entry *scope, zval *object, const char *name, int name_length, zend_string *value TSRMLS_DC) /* {{{ */
3879{
3880    zval tmp;
3881
3882    ZVAL_STR(&tmp, value);
3883    zend_update_property(scope, object, name, name_length, &tmp TSRMLS_CC);
3884}
3885/* }}} */
3886
3887ZEND_API void zend_update_property_string(zend_class_entry *scope, zval *object, const char *name, int name_length, const char *value TSRMLS_DC) /* {{{ */
3888{
3889    zval tmp;
3890
3891    ZVAL_STRING(&tmp, value);
3892    Z_SET_REFCOUNT(tmp, 0);
3893    zend_update_property(scope, object, name, name_length, &tmp TSRMLS_CC);
3894}
3895/* }}} */
3896
3897ZEND_API void zend_update_property_stringl(zend_class_entry *scope, zval *object, const char *name, int name_length, const char *value, size_t value_len TSRMLS_DC) /* {{{ */
3898{
3899    zval tmp;
3900
3901    ZVAL_STRINGL(&tmp, value, value_len);
3902    Z_SET_REFCOUNT(tmp, 0);
3903    zend_update_property(scope, object, name, name_length, &tmp TSRMLS_CC);
3904}
3905/* }}} */
3906
3907ZEND_API int zend_update_static_property(zend_class_entry *scope, const char *name, int name_length, zval *value TSRMLS_DC) /* {{{ */
3908{
3909    zval *property;
3910    zend_class_entry *old_scope = EG(scope);
3911    zend_string *key = zend_string_init(name, name_length, 0);
3912
3913    EG(scope) = scope;
3914    property = zend_std_get_static_property(scope, key, 0, NULL TSRMLS_CC);
3915    EG(scope) = old_scope;
3916    zend_string_free(key);
3917    if (!property) {
3918        return FAILURE;
3919    } else {
3920        if (property != value) {
3921            if (Z_ISREF_P(property)) {
3922                zval_dtor(property);
3923                ZVAL_COPY_VALUE(property, value);
3924                if (Z_REFCOUNT_P(value) > 0) {
3925                    zval_opt_copy_ctor(property);
3926                }
3927            } else {
3928                zval garbage;
3929
3930                ZVAL_COPY_VALUE(&garbage, property);
3931                Z_ADDREF_P(value);
3932                if (Z_ISREF_P(value)) {
3933                    SEPARATE_ZVAL(value);
3934                }
3935                ZVAL_COPY_VALUE(property, value);
3936                zval_ptr_dtor(&garbage);
3937            }
3938        }
3939        return SUCCESS;
3940    }
3941}
3942/* }}} */
3943
3944ZEND_API int zend_update_static_property_null(zend_class_entry *scope, const char *name, int name_length TSRMLS_DC) /* {{{ */
3945{
3946    zval tmp;
3947
3948    ZVAL_NULL(&tmp);
3949    return zend_update_static_property(scope, name, name_length, &tmp TSRMLS_CC);
3950}
3951/* }}} */
3952
3953ZEND_API int zend_update_static_property_bool(zend_class_entry *scope, const char *name, int name_length, zend_long value TSRMLS_DC) /* {{{ */
3954{
3955    zval tmp;
3956
3957    ZVAL_BOOL(&tmp, value);
3958    return zend_update_static_property(scope, name, name_length, &tmp TSRMLS_CC);
3959}
3960/* }}} */
3961
3962ZEND_API int zend_update_static_property_long(zend_class_entry *scope, const char *name, int name_length, zend_long value TSRMLS_DC) /* {{{ */
3963{
3964    zval tmp;
3965
3966    ZVAL_LONG(&tmp, value);
3967    return zend_update_static_property(scope, name, name_length, &tmp TSRMLS_CC);
3968}
3969/* }}} */
3970
3971ZEND_API int zend_update_static_property_double(zend_class_entry *scope, const char *name, int name_length, double value TSRMLS_DC) /* {{{ */
3972{
3973    zval tmp;
3974
3975    ZVAL_DOUBLE(&tmp, value);
3976    return zend_update_static_property(scope, name, name_length, &tmp TSRMLS_CC);
3977}
3978/* }}} */
3979
3980ZEND_API int zend_update_static_property_string(zend_class_entry *scope, const char *name, int name_length, const char *value TSRMLS_DC) /* {{{ */
3981{
3982    zval tmp;
3983
3984    ZVAL_STRING(&tmp, value);
3985    Z_SET_REFCOUNT(tmp, 0);
3986    return zend_update_static_property(scope, name, name_length, &tmp TSRMLS_CC);
3987}
3988/* }}} */
3989
3990ZEND_API int zend_update_static_property_stringl(zend_class_entry *scope, const char *name, int name_length, const char *value, size_t value_len TSRMLS_DC) /* {{{ */
3991{
3992    zval tmp;
3993
3994    ZVAL_STRINGL(&tmp, value, value_len);
3995    Z_SET_REFCOUNT(tmp, 0);
3996    return zend_update_static_property(scope, name, name_length, &tmp TSRMLS_CC);
3997}
3998/* }}} */
3999
4000ZEND_API zval *zend_read_property(zend_class_entry *scope, zval *object, const char *name, int name_length, zend_bool silent TSRMLS_DC) /* {{{ */
4001{
4002    zval property, *value;
4003    zend_class_entry *old_scope = EG(scope);
4004    zval rv;
4005
4006    EG(scope) = scope;
4007
4008    if (!Z_OBJ_HT_P(object)->read_property) {
4009        zend_string *class_name = zend_get_object_classname(Z_OBJ_P(object) TSRMLS_CC);
4010        zend_error(E_CORE_ERROR, "Property %s of class %s cannot be read", name, class_name->val);
4011    }
4012
4013    ZVAL_STRINGL(&property, name, name_length);
4014    value = Z_OBJ_HT_P(object)->read_property(object, &property, silent?BP_VAR_IS:BP_VAR_R, NULL, &rv TSRMLS_CC);
4015    zval_ptr_dtor(&property);
4016
4017    EG(scope) = old_scope;
4018    return value;
4019}
4020/* }}} */
4021
4022ZEND_API zval *zend_read_static_property(zend_class_entry *scope, const char *name, int name_length, zend_bool silent TSRMLS_DC) /* {{{ */
4023{
4024    zval *property;
4025    zend_class_entry *old_scope = EG(scope);
4026    zend_string *key = zend_string_init(name, name_length, 0);
4027
4028    EG(scope) = scope;
4029    property = zend_std_get_static_property(scope, key, silent, NULL TSRMLS_CC);
4030    EG(scope) = old_scope;
4031    zend_string_free(key);
4032
4033    return property;
4034}
4035/* }}} */
4036
4037ZEND_API void zend_save_error_handling(zend_error_handling *current TSRMLS_DC) /* {{{ */
4038{
4039    current->handling = EG(error_handling);
4040    current->exception = EG(exception_class);
4041    ZVAL_COPY(&current->user_handler, &EG(user_error_handler));
4042}
4043/* }}} */
4044
4045ZEND_API void zend_replace_error_handling(zend_error_handling_t error_handling, zend_class_entry *exception_class, zend_error_handling *current TSRMLS_DC) /* {{{ */
4046{
4047    if (current) {
4048        zend_save_error_handling(current TSRMLS_CC);
4049        if (error_handling != EH_NORMAL && Z_TYPE(EG(user_error_handler)) != IS_UNDEF) {
4050            zval_ptr_dtor(&EG(user_error_handler));
4051            ZVAL_UNDEF(&EG(user_error_handler));
4052        }
4053    }
4054    EG(error_handling) = error_handling;
4055    EG(exception_class) = error_handling == EH_THROW ? exception_class : NULL;
4056}
4057/* }}} */
4058
4059static int same_zval(zval *zv1, zval *zv2)  /* {{{ */
4060{
4061    if (Z_TYPE_P(zv1) != Z_TYPE_P(zv2)) {
4062        return 0;
4063    }
4064    switch (Z_TYPE_P(zv1)) {
4065        case IS_UNDEF:
4066        case IS_NULL:
4067        case IS_FALSE:
4068        case IS_TRUE:
4069            return 1;
4070        case IS_LONG:
4071            return Z_LVAL_P(zv1) == Z_LVAL_P(zv2);
4072        case IS_DOUBLE:
4073            return Z_LVAL_P(zv1) == Z_LVAL_P(zv2);
4074        case IS_STRING:
4075        case IS_ARRAY:
4076        case IS_OBJECT:
4077        case IS_RESOURCE:
4078            return Z_COUNTED_P(zv1) == Z_COUNTED_P(zv2);
4079        default:
4080            return 0;
4081    }
4082}
4083/* }}} */
4084
4085ZEND_API void zend_restore_error_handling(zend_error_handling *saved TSRMLS_DC) /* {{{ */
4086{
4087    EG(error_handling) = saved->handling;
4088    EG(exception_class) = saved->handling == EH_THROW ? saved->exception : NULL;
4089    if (Z_TYPE(saved->user_handler) != IS_UNDEF
4090        && !same_zval(&saved->user_handler, &EG(user_error_handler))) {
4091        zval_ptr_dtor(&EG(user_error_handler));
4092        ZVAL_COPY_VALUE(&EG(user_error_handler), &saved->user_handler);
4093    } else if (Z_TYPE(saved->user_handler)) {
4094        zval_ptr_dtor(&saved->user_handler);
4095    }
4096    ZVAL_UNDEF(&saved->user_handler);
4097}
4098/* }}} */
4099
4100ZEND_API zend_string* zend_find_alias_name(zend_class_entry *ce, zend_string *name) /* {{{ */
4101{
4102    zend_trait_alias *alias, **alias_ptr;
4103
4104    if ((alias_ptr = ce->trait_aliases)) {
4105        alias = *alias_ptr;
4106        while (alias) {
4107            if (alias->alias->len == name->len &&
4108                !strncasecmp(name->val, alias->alias->val, alias->alias->len)) {
4109                return alias->alias;
4110            }
4111            alias_ptr++;
4112            alias = *alias_ptr;
4113        }
4114    }
4115
4116    return name;
4117}
4118/* }}} */
4119
4120ZEND_API zend_string *zend_resolve_method_name(zend_class_entry *ce, zend_function *f) /* {{{ */
4121{
4122    zend_function *func;
4123    HashTable *function_table;
4124    zend_string *name;
4125
4126    if (f->common.type != ZEND_USER_FUNCTION ||
4127        *(f->op_array.refcount) < 2 ||
4128        !f->common.scope ||
4129        !f->common.scope->trait_aliases) {
4130        return f->common.function_name;
4131    }
4132
4133    function_table = &ce->function_table;
4134    ZEND_HASH_FOREACH_STR_KEY_PTR(function_table, name, func) {
4135        if (func == f) {
4136            if (!name) {
4137                return f->common.function_name;
4138            }
4139            if (name->len == f->common.function_name->len &&
4140                !strncasecmp(name->val, f->common.function_name->val, f->common.function_name->len)) {
4141                return f->common.function_name;
4142            }
4143            return zend_find_alias_name(f->common.scope, name);
4144        }
4145    } ZEND_HASH_FOREACH_END();
4146    return f->common.function_name;
4147}
4148/* }}} */
4149
4150/*
4151 * Local variables:
4152 * tab-width: 4
4153 * c-basic-offset: 4
4154 * indent-tabs-mode: t
4155 * End:
4156 */
4157