1/*
2   +----------------------------------------------------------------------+
3   | Zend Engine                                                          |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1998-2015 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   +----------------------------------------------------------------------+
18*/
19
20/* $Id$ */
21
22#include <ctype.h>
23
24#include "zend.h"
25#include "zend_operators.h"
26#include "zend_variables.h"
27#include "zend_globals.h"
28#include "zend_list.h"
29#include "zend_API.h"
30#include "zend_strtod.h"
31#include "zend_exceptions.h"
32#include "zend_closures.h"
33
34#if ZEND_USE_TOLOWER_L
35#include <locale.h>
36static _locale_t current_locale = NULL;
37/* this is true global! may lead to strange effects on ZTS, but so may setlocale() */
38#define zend_tolower(c) _tolower_l(c, current_locale)
39#else
40#define zend_tolower(c) tolower(c)
41#endif
42
43#define TYPE_PAIR(t1,t2) (((t1) << 4) | (t2))
44
45static const unsigned char tolower_map[256] = {
460x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
470x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
480x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
490x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
500x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
510x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x5b,0x5c,0x5d,0x5e,0x5f,
520x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
530x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
540x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
550x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
560xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
570xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
580xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
590xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
600xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
610xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
62};
63
64#define zend_tolower_ascii(c) (tolower_map[(unsigned char)(c)])
65
66/**
67 * Functions using locale lowercase:
68        zend_binary_strncasecmp_l
69        zend_binary_strcasecmp_l
70        zend_binary_zval_strcasecmp
71        zend_binary_zval_strncasecmp
72        string_compare_function_ex
73        string_case_compare_function
74 * Functions using ascii lowercase:
75        zend_str_tolower_copy
76        zend_str_tolower_dup
77        zend_str_tolower
78        zend_binary_strcasecmp
79        zend_binary_strncasecmp
80 */
81
82ZEND_API int ZEND_FASTCALL zend_atoi(const char *str, int str_len) /* {{{ */
83{
84    int retval;
85
86    if (!str_len) {
87        str_len = (int)strlen(str);
88    }
89    retval = ZEND_STRTOL(str, NULL, 0);
90    if (str_len>0) {
91        switch (str[str_len-1]) {
92            case 'g':
93            case 'G':
94                retval *= 1024;
95                /* break intentionally missing */
96            case 'm':
97            case 'M':
98                retval *= 1024;
99                /* break intentionally missing */
100            case 'k':
101            case 'K':
102                retval *= 1024;
103                break;
104        }
105    }
106    return retval;
107}
108/* }}} */
109
110ZEND_API zend_long ZEND_FASTCALL zend_atol(const char *str, int str_len) /* {{{ */
111{
112    zend_long retval;
113
114    if (!str_len) {
115        str_len = (int)strlen(str);
116    }
117    retval = ZEND_STRTOL(str, NULL, 0);
118    if (str_len>0) {
119        switch (str[str_len-1]) {
120            case 'g':
121            case 'G':
122                retval *= 1024;
123                /* break intentionally missing */
124            case 'm':
125            case 'M':
126                retval *= 1024;
127                /* break intentionally missing */
128            case 'k':
129            case 'K':
130                retval *= 1024;
131                break;
132        }
133    }
134    return retval;
135}
136/* }}} */
137
138ZEND_API void ZEND_FASTCALL convert_scalar_to_number(zval *op) /* {{{ */
139{
140try_again:
141    switch (Z_TYPE_P(op)) {
142        case IS_REFERENCE:
143            if (Z_REFCOUNT_P(op) == 1) {
144                ZVAL_UNREF(op);
145            } else {
146                Z_DELREF_P(op);
147                ZVAL_COPY_VALUE(op, Z_REFVAL_P(op));
148            }
149            goto try_again;
150        case IS_STRING:
151            {
152                zend_string *str;
153
154                str = Z_STR_P(op);
155                if ((Z_TYPE_INFO_P(op)=is_numeric_string(str->val, str->len, &Z_LVAL_P(op), &Z_DVAL_P(op), 1)) == 0) {
156                    ZVAL_LONG(op, 0);
157                }
158                zend_string_release(str);
159                break;
160            }
161        case IS_NULL:
162        case IS_FALSE:
163            ZVAL_LONG(op, 0);
164            break;
165        case IS_TRUE:
166            ZVAL_LONG(op, 1);
167            break;
168        case IS_RESOURCE:
169            {
170                zend_long l = Z_RES_HANDLE_P(op);
171                zval_ptr_dtor(op);
172                ZVAL_LONG(op, l);
173            }
174            break;
175        case IS_OBJECT:
176            convert_to_long_base(op, 10);
177            break;
178    }
179}
180/* }}} */
181
182/* {{{ zendi_convert_scalar_to_number */
183#define zendi_convert_scalar_to_number(op, holder, result)          \
184    if (op==result) {                                               \
185        if (Z_TYPE_P(op) != IS_LONG) {                              \
186            convert_scalar_to_number(op);                   \
187        }                                                           \
188    } else {                                                        \
189        switch (Z_TYPE_P(op)) {                                     \
190            case IS_STRING:                                         \
191                {                                                   \
192                    if ((Z_TYPE_INFO(holder)=is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &Z_LVAL(holder), &Z_DVAL(holder), 1)) == 0) {    \
193                        ZVAL_LONG(&(holder), 0);                            \
194                    }                                                       \
195                    (op) = &(holder);                                       \
196                    break;                                                  \
197                }                                                           \
198            case IS_NULL:                                                   \
199            case IS_FALSE:                                                  \
200                ZVAL_LONG(&(holder), 0);                                    \
201                (op) = &(holder);                                           \
202                break;                                                      \
203            case IS_TRUE:                                                   \
204                ZVAL_LONG(&(holder), 1);                                    \
205                (op) = &(holder);                                           \
206                break;                                                      \
207            case IS_RESOURCE:                                               \
208                ZVAL_LONG(&(holder), Z_RES_HANDLE_P(op));                   \
209                (op) = &(holder);                                           \
210                break;                                                      \
211            case IS_OBJECT:                                                 \
212                ZVAL_DUP(&(holder), op);                                        \
213                convert_to_long_base(&(holder), 10);                        \
214                if (Z_TYPE(holder) == IS_LONG) {                            \
215                    (op) = &(holder);                                       \
216                }                                                           \
217                break;                                                      \
218        }                                                                   \
219    }
220
221/* }}} */
222
223/* {{{ convert_object_to_type */
224#define convert_object_to_type(op, dst, ctype, conv_func)                                   \
225    ZVAL_UNDEF(dst);                                                                        \
226    if (Z_OBJ_HT_P(op)->cast_object) {                                                      \
227        if (Z_OBJ_HT_P(op)->cast_object(op, dst, ctype) == FAILURE) {               \
228            zend_error(E_RECOVERABLE_ERROR,                                                 \
229                "Object of class %s could not be converted to %s", Z_OBJCE_P(op)->name->val,\
230            zend_get_type_by_const(ctype));                                                 \
231        }                                                                                   \
232    } else if (Z_OBJ_HT_P(op)->get) {                                                       \
233        zval *newop = Z_OBJ_HT_P(op)->get(op, dst);                             \
234        if (Z_TYPE_P(newop) != IS_OBJECT) {                                                 \
235            /* for safety - avoid loop */                                                   \
236            ZVAL_COPY_VALUE(dst, newop);                                                    \
237            conv_func(dst);                                                                 \
238        }                                                                                   \
239    }
240
241/* }}} */
242
243#define convert_op1_op2_long(op1, op1_lval, op2, op2_lval, op, op_func) \
244    do {                                                                \
245        if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {                     \
246            if (Z_ISREF_P(op1)) {                                       \
247                op1 = Z_REFVAL_P(op1);                                  \
248                if (Z_TYPE_P(op1) == IS_LONG) {                         \
249                    op1_lval = Z_LVAL_P(op1);                           \
250                    break;                                              \
251                }                                                       \
252            }                                                           \
253            ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(op, op_func);          \
254            op1_lval = _zval_get_long_func(op1);                        \
255        } else {                                                        \
256            op1_lval = Z_LVAL_P(op1);                                   \
257        }                                                               \
258    } while (0);                                                        \
259    do {                                                                \
260        if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {                     \
261            if (Z_ISREF_P(op2)) {                                       \
262                op2 = Z_REFVAL_P(op2);                                  \
263                if (Z_TYPE_P(op2) == IS_LONG) {                         \
264                    op2_lval = Z_LVAL_P(op2);                           \
265                    break;                                              \
266                }                                                       \
267            }                                                           \
268            ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(op);                   \
269            op2_lval = _zval_get_long_func(op2);                        \
270        } else {                                                        \
271            op2_lval = Z_LVAL_P(op2);                                   \
272        }                                                               \
273    } while (0);
274
275ZEND_API void ZEND_FASTCALL convert_to_long(zval *op) /* {{{ */
276{
277    if (Z_TYPE_P(op) != IS_LONG) {
278        convert_to_long_base(op, 10);
279    }
280}
281/* }}} */
282
283ZEND_API void ZEND_FASTCALL convert_to_long_base(zval *op, int base) /* {{{ */
284{
285    zend_long tmp;
286
287    switch (Z_TYPE_P(op)) {
288        case IS_NULL:
289        case IS_FALSE:
290            ZVAL_LONG(op, 0);
291            break;
292        case IS_TRUE:
293            ZVAL_LONG(op, 1);
294            break;
295        case IS_RESOURCE:
296            tmp = Z_RES_HANDLE_P(op);
297            zval_ptr_dtor(op);
298            ZVAL_LONG(op, tmp);
299            break;
300        case IS_LONG:
301            break;
302        case IS_DOUBLE:
303            ZVAL_LONG(op, zend_dval_to_lval(Z_DVAL_P(op)));
304            break;
305        case IS_STRING:
306            {
307                zend_string *str = Z_STR_P(op);
308
309                ZVAL_LONG(op, ZEND_STRTOL(str->val, NULL, base));
310                zend_string_release(str);
311            }
312            break;
313        case IS_ARRAY:
314            tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
315            zval_dtor(op);
316            ZVAL_LONG(op, tmp);
317            break;
318        case IS_OBJECT:
319            {
320                zval dst;
321
322                convert_object_to_type(op, &dst, IS_LONG, convert_to_long);
323                zval_dtor(op);
324
325                if (Z_TYPE(dst) == IS_LONG) {
326                    ZVAL_COPY_VALUE(op, &dst);
327                } else {
328                    zend_error(E_NOTICE, "Object of class %s could not be converted to int", Z_OBJCE_P(op)->name->val);
329
330                    ZVAL_LONG(op, 1);
331                }
332                return;
333            }
334        EMPTY_SWITCH_DEFAULT_CASE()
335    }
336}
337/* }}} */
338
339ZEND_API void ZEND_FASTCALL convert_to_double(zval *op) /* {{{ */
340{
341    double tmp;
342
343    switch (Z_TYPE_P(op)) {
344        case IS_NULL:
345        case IS_FALSE:
346            ZVAL_DOUBLE(op, 0.0);
347            break;
348        case IS_TRUE:
349            ZVAL_DOUBLE(op, 1.0);
350            break;
351        case IS_RESOURCE: {
352                double d = (double) Z_RES_HANDLE_P(op);
353                zval_ptr_dtor(op);
354                ZVAL_DOUBLE(op, d);
355            }
356            break;
357        case IS_LONG:
358            ZVAL_DOUBLE(op, (double) Z_LVAL_P(op));
359            break;
360        case IS_DOUBLE:
361            break;
362        case IS_STRING:
363            {
364                zend_string *str = Z_STR_P(op);
365
366                ZVAL_DOUBLE(op, zend_strtod(str->val, NULL));
367                zend_string_release(str);
368            }
369            break;
370        case IS_ARRAY:
371            tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
372            zval_dtor(op);
373            ZVAL_DOUBLE(op, tmp);
374            break;
375        case IS_OBJECT:
376            {
377                zval dst;
378
379                convert_object_to_type(op, &dst, IS_DOUBLE, convert_to_double);
380                zval_dtor(op);
381
382                if (Z_TYPE(dst) == IS_DOUBLE) {
383                    ZVAL_COPY_VALUE(op, &dst);
384                } else {
385                    zend_error(E_NOTICE, "Object of class %s could not be converted to float", Z_OBJCE_P(op)->name->val);
386
387                    ZVAL_DOUBLE(op, 1.0);
388                }
389                break;
390            }
391        EMPTY_SWITCH_DEFAULT_CASE()
392    }
393}
394/* }}} */
395
396ZEND_API void ZEND_FASTCALL convert_to_null(zval *op) /* {{{ */
397{
398    if (Z_TYPE_P(op) == IS_OBJECT) {
399        if (Z_OBJ_HT_P(op)->cast_object) {
400            zval org;
401
402            ZVAL_COPY_VALUE(&org, op);
403            if (Z_OBJ_HT_P(op)->cast_object(&org, op, IS_NULL) == SUCCESS) {
404                zval_dtor(&org);
405                return;
406            }
407            ZVAL_COPY_VALUE(op, &org);
408        }
409    }
410
411    zval_dtor(op);
412    ZVAL_NULL(op);
413}
414/* }}} */
415
416ZEND_API void ZEND_FASTCALL convert_to_boolean(zval *op) /* {{{ */
417{
418    int tmp;
419
420    switch (Z_TYPE_P(op)) {
421        case IS_FALSE:
422        case IS_TRUE:
423            break;
424        case IS_NULL:
425            ZVAL_FALSE(op);
426            break;
427        case IS_RESOURCE: {
428                zend_long l = (Z_RES_HANDLE_P(op) ? 1 : 0);
429
430                zval_ptr_dtor(op);
431                ZVAL_BOOL(op, l);
432            }
433            break;
434        case IS_LONG:
435            ZVAL_BOOL(op, Z_LVAL_P(op) ? 1 : 0);
436            break;
437        case IS_DOUBLE:
438            ZVAL_BOOL(op, Z_DVAL_P(op) ? 1 : 0);
439            break;
440        case IS_STRING:
441            {
442                zend_string *str = Z_STR_P(op);
443
444                if (str->len == 0
445                    || (str->len == 1 && str->val[0] == '0')) {
446                    ZVAL_FALSE(op);
447                } else {
448                    ZVAL_TRUE(op);
449                }
450                zend_string_release(str);
451            }
452            break;
453        case IS_ARRAY:
454            tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
455            zval_dtor(op);
456            ZVAL_BOOL(op, tmp);
457            break;
458        case IS_OBJECT:
459            {
460                zval dst;
461
462                convert_object_to_type(op, &dst, _IS_BOOL, convert_to_boolean);
463                zval_dtor(op);
464
465                if (Z_TYPE(dst) == IS_FALSE || Z_TYPE(dst) == IS_TRUE) {
466                    ZVAL_COPY_VALUE(op, &dst);
467                } else {
468                    ZVAL_TRUE(op);
469                }
470                break;
471            }
472        EMPTY_SWITCH_DEFAULT_CASE()
473    }
474}
475/* }}} */
476
477ZEND_API void ZEND_FASTCALL _convert_to_cstring(zval *op ZEND_FILE_LINE_DC) /* {{{ */
478{
479    _convert_to_string(op ZEND_FILE_LINE_CC);
480}
481/* }}} */
482
483ZEND_API void ZEND_FASTCALL _convert_to_string(zval *op ZEND_FILE_LINE_DC) /* {{{ */
484{
485    switch (Z_TYPE_P(op)) {
486        case IS_UNDEF:
487        case IS_NULL:
488        case IS_FALSE: {
489            ZVAL_EMPTY_STRING(op);
490            break;
491        }
492        case IS_TRUE:
493            ZVAL_NEW_STR(op, zend_string_init("1", 1, 0));
494            break;
495        case IS_STRING:
496            break;
497        case IS_RESOURCE: {
498            char buf[sizeof("Resource id #") + MAX_LENGTH_OF_LONG];
499            int len = snprintf(buf, sizeof(buf), "Resource id #" ZEND_LONG_FMT, (zend_long)Z_RES_HANDLE_P(op));
500            zval_ptr_dtor(op);
501            ZVAL_NEW_STR(op, zend_string_init(buf, len, 0));
502            break;
503        }
504        case IS_LONG: {
505            ZVAL_NEW_STR(op, zend_long_to_str(Z_LVAL_P(op)));
506            break;
507        }
508        case IS_DOUBLE: {
509            zend_string *str;
510            double dval = Z_DVAL_P(op);
511
512            str = zend_strpprintf(0, "%.*G", (int) EG(precision), dval);
513            /* %G already handles removing trailing zeros from the fractional part, yay */
514            ZVAL_NEW_STR(op, str);
515            break;
516        }
517        case IS_ARRAY:
518            zend_error(E_NOTICE, "Array to string conversion");
519            zval_dtor(op);
520            ZVAL_NEW_STR(op, zend_string_init("Array", sizeof("Array")-1, 0));
521            break;
522        case IS_OBJECT: {
523            zval dst;
524
525            convert_object_to_type(op, &dst, IS_STRING, convert_to_string);
526
527            if (Z_TYPE(dst) == IS_STRING) {
528                zval_dtor(op);
529                ZVAL_COPY_VALUE(op, &dst);
530            } else {
531                zend_error(E_NOTICE, "Object of class %s to string conversion", Z_OBJCE_P(op)->name->val);
532                zval_dtor(op);
533                ZVAL_NEW_STR(op, zend_string_init("Object", sizeof("Object")-1, 0));
534            }
535            break;
536        }
537        EMPTY_SWITCH_DEFAULT_CASE()
538    }
539}
540/* }}} */
541
542static void convert_scalar_to_array(zval *op) /* {{{ */
543{
544    zval entry;
545
546    ZVAL_COPY_VALUE(&entry, op);
547
548    ZVAL_NEW_ARR(op);
549    zend_hash_init(Z_ARRVAL_P(op), 8, NULL, ZVAL_PTR_DTOR, 0);
550    zend_hash_index_add_new(Z_ARRVAL_P(op), 0, &entry);
551}
552/* }}} */
553
554ZEND_API void ZEND_FASTCALL convert_to_array(zval *op) /* {{{ */
555{
556
557    switch (Z_TYPE_P(op)) {
558        case IS_ARRAY:
559            break;
560/* OBJECTS_OPTIMIZE */
561        case IS_OBJECT:
562            if (Z_OBJCE_P(op) == zend_ce_closure) {
563                convert_scalar_to_array(op);
564            } else {
565                if (Z_OBJ_HT_P(op)->get_properties) {
566                    HashTable *obj_ht = Z_OBJ_HT_P(op)->get_properties(op);
567                    if (obj_ht) {
568                        zval arr;
569                        ZVAL_ARR(&arr, zend_array_dup(obj_ht));
570                        zval_dtor(op);
571                        ZVAL_COPY_VALUE(op, &arr);
572                        return;
573                    }
574                } else {
575                    zval dst;
576                    convert_object_to_type(op, &dst, IS_ARRAY, convert_to_array);
577
578                    if (Z_TYPE(dst) == IS_ARRAY) {
579                        zval_dtor(op);
580                        ZVAL_COPY_VALUE(op, &dst);
581                        return;
582                    }
583                }
584
585                zval_dtor(op);
586                array_init(op);
587            }
588            break;
589        case IS_NULL:
590            ZVAL_NEW_ARR(op);
591            zend_hash_init(Z_ARRVAL_P(op), 8, NULL, ZVAL_PTR_DTOR, 0);
592            break;
593        default:
594            convert_scalar_to_array(op);
595            break;
596    }
597}
598/* }}} */
599
600ZEND_API void ZEND_FASTCALL convert_to_object(zval *op) /* {{{ */
601{
602
603    switch (Z_TYPE_P(op)) {
604        case IS_ARRAY:
605            {
606                HashTable *properties = emalloc(sizeof(HashTable));
607                zend_array *arr = Z_ARR_P(op);
608
609                memcpy(properties, Z_ARRVAL_P(op), sizeof(HashTable));
610                object_and_properties_init(op, zend_standard_class_def, properties);
611                if (--GC_REFCOUNT(arr) == 0) {
612                    efree_size(arr, sizeof(zend_array));
613                }
614                break;
615            }
616        case IS_OBJECT:
617            break;
618        case IS_NULL:
619            object_init(op);
620            break;
621        default: {
622            zval tmp;
623            ZVAL_COPY_VALUE(&tmp, op);
624            object_init(op);
625            zend_hash_str_add_new(Z_OBJPROP_P(op), "scalar", sizeof("scalar")-1, &tmp);
626            break;
627        }
628    }
629}
630/* }}} */
631
632ZEND_API void multi_convert_to_long_ex(int argc, ...) /* {{{ */
633{
634    zval *arg;
635    va_list ap;
636
637    va_start(ap, argc);
638
639    while (argc--) {
640        arg = va_arg(ap, zval *);
641        convert_to_long_ex(arg);
642    }
643
644    va_end(ap);
645}
646/* }}} */
647
648ZEND_API void multi_convert_to_double_ex(int argc, ...) /* {{{ */
649{
650    zval *arg;
651    va_list ap;
652
653    va_start(ap, argc);
654
655    while (argc--) {
656        arg = va_arg(ap, zval *);
657        convert_to_double_ex(arg);
658    }
659
660    va_end(ap);
661}
662/* }}} */
663
664ZEND_API void multi_convert_to_string_ex(int argc, ...) /* {{{ */
665{
666    zval *arg;
667    va_list ap;
668
669    va_start(ap, argc);
670
671    while (argc--) {
672        arg = va_arg(ap, zval *);
673        convert_to_string_ex(arg);
674    }
675
676    va_end(ap);
677}
678/* }}} */
679
680ZEND_API zend_long ZEND_FASTCALL _zval_get_long_func(zval *op) /* {{{ */
681{
682try_again:
683    switch (Z_TYPE_P(op)) {
684        case IS_NULL:
685        case IS_FALSE:
686            return 0;
687        case IS_TRUE:
688            return 1;
689        case IS_RESOURCE:
690            return Z_RES_HANDLE_P(op);
691        case IS_LONG:
692            return Z_LVAL_P(op);
693        case IS_DOUBLE:
694            return zend_dval_to_lval(Z_DVAL_P(op));
695        case IS_STRING:
696            return ZEND_STRTOL(Z_STRVAL_P(op), NULL, 10);
697        case IS_ARRAY:
698            return zend_hash_num_elements(Z_ARRVAL_P(op)) ? 1 : 0;
699        case IS_OBJECT:
700            {
701                zval dst;
702                convert_object_to_type(op, &dst, IS_LONG, convert_to_long);
703                if (Z_TYPE(dst) == IS_LONG) {
704                    return Z_LVAL(dst);
705                } else {
706                    zend_error(E_NOTICE, "Object of class %s could not be converted to int", Z_OBJCE_P(op)->name->val);
707                    return 1;
708                }
709            }
710        case IS_REFERENCE:
711            op = Z_REFVAL_P(op);
712            goto try_again;
713        EMPTY_SWITCH_DEFAULT_CASE()
714    }
715    return 0;
716}
717/* }}} */
718
719ZEND_API double ZEND_FASTCALL _zval_get_double_func(zval *op) /* {{{ */
720{
721try_again:
722    switch (Z_TYPE_P(op)) {
723        case IS_NULL:
724        case IS_FALSE:
725            return 0.0;
726        case IS_TRUE:
727            return 1.0;
728        case IS_RESOURCE:
729            return (double) Z_RES_HANDLE_P(op);
730        case IS_LONG:
731            return (double) Z_LVAL_P(op);
732        case IS_DOUBLE:
733            return Z_DVAL_P(op);
734        case IS_STRING:
735            return zend_strtod(Z_STRVAL_P(op), NULL);
736        case IS_ARRAY:
737            return zend_hash_num_elements(Z_ARRVAL_P(op)) ? 1.0 : 0.0;
738        case IS_OBJECT:
739            {
740                zval dst;
741                convert_object_to_type(op, &dst, IS_DOUBLE, convert_to_double);
742
743                if (Z_TYPE(dst) == IS_DOUBLE) {
744                    return Z_DVAL(dst);
745                } else {
746                    zend_error(E_NOTICE, "Object of class %s could not be converted to double", Z_OBJCE_P(op)->name->val);
747
748                    return 1.0;
749                }
750            }
751        case IS_REFERENCE:
752            op = Z_REFVAL_P(op);
753            goto try_again;
754        EMPTY_SWITCH_DEFAULT_CASE()
755    }
756    return 0.0;
757}
758/* }}} */
759
760ZEND_API zend_string* ZEND_FASTCALL _zval_get_string_func(zval *op) /* {{{ */
761{
762try_again:
763    switch (Z_TYPE_P(op)) {
764        case IS_UNDEF:
765        case IS_NULL:
766        case IS_FALSE:
767            return STR_EMPTY_ALLOC();
768        case IS_TRUE:
769            return zend_string_init("1", 1, 0);
770        case IS_RESOURCE: {
771            char buf[sizeof("Resource id #") + MAX_LENGTH_OF_LONG];
772            int len;
773
774            len = snprintf(buf, sizeof(buf), "Resource id #" ZEND_LONG_FMT, (zend_long)Z_RES_HANDLE_P(op));
775            return zend_string_init(buf, len, 0);
776        }
777        case IS_LONG: {
778            return zend_long_to_str(Z_LVAL_P(op));
779        }
780        case IS_DOUBLE: {
781            return zend_strpprintf(0, "%.*G", (int) EG(precision), Z_DVAL_P(op));
782        }
783        case IS_ARRAY:
784            zend_error(E_NOTICE, "Array to string conversion");
785            return zend_string_init("Array", sizeof("Array")-1, 0);
786        case IS_OBJECT: {
787            zval tmp;
788            if (Z_OBJ_HT_P(op)->cast_object) {
789                if (Z_OBJ_HT_P(op)->cast_object(op, &tmp, IS_STRING) == SUCCESS) {
790                    return Z_STR(tmp);
791                }
792            } else if (Z_OBJ_HT_P(op)->get) {
793                zval *z = Z_OBJ_HT_P(op)->get(op, &tmp);
794                if (Z_TYPE_P(z) != IS_OBJECT) {
795                    zend_string *str = zval_get_string(z);
796                    zval_ptr_dtor(z);
797                    return str;
798                }
799                zval_ptr_dtor(z);
800            }
801            zend_error(EG(exception) ? E_ERROR : E_RECOVERABLE_ERROR, "Object of class %s could not be converted to string", Z_OBJCE_P(op)->name->val);
802            return STR_EMPTY_ALLOC();
803        }
804        case IS_REFERENCE:
805            op = Z_REFVAL_P(op);
806            goto try_again;
807        case IS_STRING:
808            return zend_string_copy(Z_STR_P(op));
809        EMPTY_SWITCH_DEFAULT_CASE()
810    }
811    return NULL;
812}
813/* }}} */
814
815ZEND_API int ZEND_FASTCALL add_function(zval *result, zval *op1, zval *op2) /* {{{ */
816{
817    zval op1_copy, op2_copy;
818    int converted = 0;
819
820    while (1) {
821        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
822            case TYPE_PAIR(IS_LONG, IS_LONG): {
823                zend_long lval = Z_LVAL_P(op1) + Z_LVAL_P(op2);
824
825                /* check for overflow by comparing sign bits */
826                if ((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK)
827                    && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (lval & LONG_SIGN_MASK)) {
828
829                    ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2));
830                } else {
831                    ZVAL_LONG(result, lval);
832                }
833                return SUCCESS;
834            }
835
836            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
837                ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
838                return SUCCESS;
839
840            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
841                ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
842                return SUCCESS;
843
844            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
845                ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
846                return SUCCESS;
847
848            case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
849                if ((result == op1) && (result == op2)) {
850                    /* $a += $a */
851                    return SUCCESS;
852                }
853                if (result != op1) {
854                    ZVAL_DUP(result, op1);
855                }
856                zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), zval_add_ref, 0);
857                return SUCCESS;
858
859            default:
860                if (Z_ISREF_P(op1)) {
861                    op1 = Z_REFVAL_P(op1);
862                } else if (Z_ISREF_P(op2)) {
863                    op2 = Z_REFVAL_P(op2);
864                } else if (!converted) {
865                    ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_ADD, add_function);
866
867                    zendi_convert_scalar_to_number(op1, op1_copy, result);
868                    zendi_convert_scalar_to_number(op2, op2_copy, result);
869                    converted = 1;
870                } else {
871                    zend_error(E_EXCEPTION | E_ERROR, "Unsupported operand types");
872                    return FAILURE; /* unknown datatype */
873                }
874        }
875    }
876}
877/* }}} */
878
879ZEND_API int ZEND_FASTCALL sub_function(zval *result, zval *op1, zval *op2) /* {{{ */
880{
881    zval op1_copy, op2_copy;
882    int converted = 0;
883
884    while (1) {
885        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
886            case TYPE_PAIR(IS_LONG, IS_LONG): {
887                zend_long lval = Z_LVAL_P(op1) - Z_LVAL_P(op2);
888
889                /* check for overflow by comparing sign bits */
890                if ((Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(op2) & LONG_SIGN_MASK)
891                    && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (lval & LONG_SIGN_MASK)) {
892
893                    ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2));
894                } else {
895                    ZVAL_LONG(result, lval);
896                }
897                return SUCCESS;
898
899            }
900            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
901                ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) - Z_DVAL_P(op2));
902                return SUCCESS;
903
904            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
905                ZVAL_DOUBLE(result, Z_DVAL_P(op1) - ((double)Z_LVAL_P(op2)));
906                return SUCCESS;
907
908            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
909                ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2));
910                return SUCCESS;
911
912            default:
913                if (Z_ISREF_P(op1)) {
914                    op1 = Z_REFVAL_P(op1);
915                } else if (Z_ISREF_P(op2)) {
916                    op2 = Z_REFVAL_P(op2);
917                } else if (!converted) {
918                    ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB, sub_function);
919
920                    zendi_convert_scalar_to_number(op1, op1_copy, result);
921                    zendi_convert_scalar_to_number(op2, op2_copy, result);
922                    converted = 1;
923                } else {
924                    zend_error(E_EXCEPTION | E_ERROR, "Unsupported operand types");
925                    return FAILURE; /* unknown datatype */
926                }
927        }
928    }
929}
930/* }}} */
931
932ZEND_API int ZEND_FASTCALL mul_function(zval *result, zval *op1, zval *op2) /* {{{ */
933{
934    zval op1_copy, op2_copy;
935    int converted = 0;
936
937    while (1) {
938        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
939            case TYPE_PAIR(IS_LONG, IS_LONG): {
940                zend_long overflow;
941
942                ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1),Z_LVAL_P(op2), Z_LVAL_P(result),Z_DVAL_P(result),overflow);
943                Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG;
944                return SUCCESS;
945
946            }
947            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
948                ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2));
949                return SUCCESS;
950
951            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
952                ZVAL_DOUBLE(result, Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2)));
953                return SUCCESS;
954
955            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
956                ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2));
957                return SUCCESS;
958
959            default:
960                if (Z_ISREF_P(op1)) {
961                    op1 = Z_REFVAL_P(op1);
962                } else if (Z_ISREF_P(op2)) {
963                    op2 = Z_REFVAL_P(op2);
964                } else if (!converted) {
965                    ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MUL, mul_function);
966
967                    zendi_convert_scalar_to_number(op1, op1_copy, result);
968                    zendi_convert_scalar_to_number(op2, op2_copy, result);
969                    converted = 1;
970                } else {
971                    zend_error(E_EXCEPTION | E_ERROR, "Unsupported operand types");
972                    return FAILURE; /* unknown datatype */
973                }
974        }
975    }
976}
977/* }}} */
978
979ZEND_API int ZEND_FASTCALL pow_function(zval *result, zval *op1, zval *op2) /* {{{ */
980{
981    zval op1_copy, op2_copy;
982    int converted = 0;
983
984    while (1) {
985        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
986            case TYPE_PAIR(IS_LONG, IS_LONG):
987                if (Z_LVAL_P(op2) >= 0) {
988                    zend_long l1 = 1, l2 = Z_LVAL_P(op1), i = Z_LVAL_P(op2);
989
990                    if (i == 0) {
991                        ZVAL_LONG(result, 1L);
992                        return SUCCESS;
993                    } else if (l2 == 0) {
994                        ZVAL_LONG(result, 0);
995                        return SUCCESS;
996                    }
997
998                    while (i >= 1) {
999                        zend_long overflow;
1000                        double dval = 0.0;
1001
1002                        if (i % 2) {
1003                            --i;
1004                            ZEND_SIGNED_MULTIPLY_LONG(l1, l2, l1, dval, overflow);
1005                            if (overflow) {
1006                                ZVAL_DOUBLE(result, dval * pow(l2, i));
1007                                return SUCCESS;
1008                            }
1009                        } else {
1010                            i /= 2;
1011                            ZEND_SIGNED_MULTIPLY_LONG(l2, l2, l2, dval, overflow);
1012                            if (overflow) {
1013                                ZVAL_DOUBLE(result, (double)l1 * pow(dval, i));
1014                                return SUCCESS;
1015                            }
1016                        }
1017                    }
1018                    /* i == 0 */
1019                    ZVAL_LONG(result, l1);
1020                } else {
1021                    ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), (double)Z_LVAL_P(op2)));
1022                }
1023                return SUCCESS;
1024
1025            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1026                ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), Z_DVAL_P(op2)));
1027                return SUCCESS;
1028
1029            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1030                ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), (double)Z_LVAL_P(op2)));
1031                return SUCCESS;
1032
1033            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1034                ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), Z_DVAL_P(op2)));
1035                return SUCCESS;
1036
1037            default:
1038                if (Z_ISREF_P(op1)) {
1039                    op1 = Z_REFVAL_P(op1);
1040                } else if (Z_ISREF_P(op2)) {
1041                    op2 = Z_REFVAL_P(op2);
1042                } else if (!converted) {
1043                    ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_POW, pow_function);
1044
1045                    if (Z_TYPE_P(op1) == IS_ARRAY) {
1046                        ZVAL_LONG(result, 0);
1047                        return SUCCESS;
1048                    } else {
1049                        zendi_convert_scalar_to_number(op1, op1_copy, result);
1050                    }
1051                    if (Z_TYPE_P(op2) == IS_ARRAY) {
1052                        ZVAL_LONG(result, 1L);
1053                        return SUCCESS;
1054                    } else {
1055                        zendi_convert_scalar_to_number(op2, op2_copy, result);
1056                    }
1057                    converted = 1;
1058                } else {
1059                    zend_error(E_EXCEPTION | E_ERROR, "Unsupported operand types");
1060                    return FAILURE;
1061                }
1062        }
1063    }
1064}
1065/* }}} */
1066
1067ZEND_API int ZEND_FASTCALL div_function(zval *result, zval *op1, zval *op2) /* {{{ */
1068{
1069    zval op1_copy, op2_copy;
1070    int converted = 0;
1071
1072    while (1) {
1073        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
1074            case TYPE_PAIR(IS_LONG, IS_LONG):
1075                if (Z_LVAL_P(op2) == 0) {
1076                    zend_error(E_WARNING, "Division by zero");
1077                    ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1) / (double) Z_LVAL_P(op2)));
1078                    return SUCCESS;
1079                } else if (Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == ZEND_LONG_MIN) {
1080                    /* Prevent overflow error/crash */
1081                    ZVAL_DOUBLE(result, (double) ZEND_LONG_MIN / -1);
1082                    return SUCCESS;
1083                }
1084                if (Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0) { /* integer */
1085                    ZVAL_LONG(result, Z_LVAL_P(op1) / Z_LVAL_P(op2));
1086                } else {
1087                    ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1)) / Z_LVAL_P(op2));
1088                }
1089                return SUCCESS;
1090
1091            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1092                if (Z_LVAL_P(op2) == 0) {
1093                    zend_error(E_WARNING, "Division by zero");
1094                }
1095                ZVAL_DOUBLE(result, Z_DVAL_P(op1) / (double)Z_LVAL_P(op2));
1096                return SUCCESS;
1097
1098            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1099                if (Z_DVAL_P(op2) == 0) {
1100                    zend_error(E_WARNING, "Division by zero");
1101                }
1102                ZVAL_DOUBLE(result, (double)Z_LVAL_P(op1) / Z_DVAL_P(op2));
1103                return SUCCESS;
1104
1105            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1106                if (Z_DVAL_P(op2) == 0) {
1107                    zend_error(E_WARNING, "Division by zero");
1108                }
1109                ZVAL_DOUBLE(result, Z_DVAL_P(op1) / Z_DVAL_P(op2));
1110                return SUCCESS;
1111
1112            default:
1113                if (Z_ISREF_P(op1)) {
1114                    op1 = Z_REFVAL_P(op1);
1115                } else if (Z_ISREF_P(op2)) {
1116                    op2 = Z_REFVAL_P(op2);
1117                } else if (!converted) {
1118                    ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV, div_function);
1119
1120                    zendi_convert_scalar_to_number(op1, op1_copy, result);
1121                    zendi_convert_scalar_to_number(op2, op2_copy, result);
1122                    converted = 1;
1123                } else {
1124                    zend_error(E_EXCEPTION | E_ERROR, "Unsupported operand types");
1125                    return FAILURE; /* unknown datatype */
1126                }
1127        }
1128    }
1129}
1130/* }}} */
1131
1132ZEND_API int ZEND_FASTCALL mod_function(zval *result, zval *op1, zval *op2) /* {{{ */
1133{
1134    zend_long op1_lval, op2_lval;
1135
1136    convert_op1_op2_long(op1, op1_lval, op2, op2_lval, ZEND_MOD, mod_function);
1137
1138    if (op1 == result) {
1139        zval_dtor(result);
1140    }
1141
1142    if (op2_lval == 0) {
1143        /* modulus by zero */
1144        if (EG(current_execute_data) && !CG(in_compilation)) {
1145            zend_throw_exception_ex(NULL, 0, "Division by zero");
1146        } else {
1147            zend_error_noreturn(E_ERROR, "Division by zero");
1148        }
1149        ZVAL_UNDEF(result);
1150        return FAILURE;
1151    }
1152
1153    if (op2_lval == -1) {
1154        /* Prevent overflow error/crash if op1==LONG_MIN */
1155        ZVAL_LONG(result, 0);
1156        return SUCCESS;
1157    }
1158
1159    ZVAL_LONG(result, op1_lval % op2_lval);
1160    return SUCCESS;
1161}
1162/* }}} */
1163
1164ZEND_API int ZEND_FASTCALL boolean_xor_function(zval *result, zval *op1, zval *op2) /* {{{ */
1165{
1166    int op1_val, op2_val;
1167
1168    do {
1169        if (Z_TYPE_P(op1) == IS_FALSE) {
1170            op1_val = 0;
1171        } else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1172            op1_val = 1;
1173        } else {
1174            if (Z_ISREF_P(op1)) {
1175                op1 = Z_REFVAL_P(op1);
1176                if (Z_TYPE_P(op1) == IS_FALSE) {
1177                    op1_val = 0;
1178                    break;
1179                } else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1180                    op1_val = 1;
1181                    break;
1182                }
1183            }
1184            ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BOOL_XOR, boolean_xor_function);
1185            op1_val = zval_is_true(op1);
1186        }
1187    } while (0);
1188    do {
1189        if (Z_TYPE_P(op2) == IS_FALSE) {
1190            op2_val = 0;
1191        } else if (EXPECTED(Z_TYPE_P(op2) == IS_TRUE)) {
1192            op2_val = 1;
1193        } else {
1194            if (Z_ISREF_P(op2)) {
1195                op2 = Z_REFVAL_P(op2);
1196                if (Z_TYPE_P(op2) == IS_FALSE) {
1197                    op2_val = 0;
1198                    break;
1199                } else if (EXPECTED(Z_TYPE_P(op2) == IS_TRUE)) {
1200                    op2_val = 1;
1201                    break;
1202                }
1203            }
1204            ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BOOL_XOR);
1205            op2_val = zval_is_true(op2);
1206        }
1207    } while (0);
1208
1209    ZVAL_BOOL(result, op1_val ^ op2_val);
1210    return SUCCESS;
1211}
1212/* }}} */
1213
1214ZEND_API int ZEND_FASTCALL boolean_not_function(zval *result, zval *op1) /* {{{ */
1215{
1216    if (Z_TYPE_P(op1) < IS_TRUE) {
1217        ZVAL_TRUE(result);
1218    } else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1219        ZVAL_FALSE(result);
1220    } else {
1221        if (Z_ISREF_P(op1)) {
1222            op1 = Z_REFVAL_P(op1);
1223            if (Z_TYPE_P(op1) < IS_TRUE) {
1224                ZVAL_TRUE(result);
1225                return SUCCESS;
1226            } else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1227                ZVAL_FALSE(result);
1228                return SUCCESS;
1229            }
1230        }
1231        ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BOOL_NOT);
1232
1233        ZVAL_BOOL(result, !zval_is_true(op1));
1234    }
1235    return SUCCESS;
1236}
1237/* }}} */
1238
1239ZEND_API int ZEND_FASTCALL bitwise_not_function(zval *result, zval *op1) /* {{{ */
1240{
1241try_again:
1242    switch (Z_TYPE_P(op1)) {
1243        case IS_LONG:
1244            ZVAL_LONG(result, ~Z_LVAL_P(op1));
1245            return SUCCESS;
1246        case IS_DOUBLE:
1247            ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1)));
1248            return SUCCESS;
1249        case IS_STRING: {
1250            size_t i;
1251
1252            ZVAL_NEW_STR(result, zend_string_alloc(Z_STRLEN_P(op1), 0));
1253            for (i = 0; i < Z_STRLEN_P(op1); i++) {
1254                Z_STRVAL_P(result)[i] = ~Z_STRVAL_P(op1)[i];
1255            }
1256            Z_STRVAL_P(result)[i] = 0;
1257            return SUCCESS;
1258        }
1259        case IS_REFERENCE:
1260            op1 = Z_REFVAL_P(op1);
1261            goto try_again;
1262        default:
1263            ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BW_NOT);
1264
1265            zend_error(E_EXCEPTION | E_ERROR, "Unsupported operand types");
1266            return FAILURE;
1267    }
1268}
1269/* }}} */
1270
1271ZEND_API int ZEND_FASTCALL bitwise_or_function(zval *result, zval *op1, zval *op2) /* {{{ */
1272{
1273    zend_long op1_lval, op2_lval;
1274
1275    if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1276        ZVAL_LONG(result, Z_LVAL_P(op1) | Z_LVAL_P(op2));
1277        return SUCCESS;
1278    }
1279
1280    ZVAL_DEREF(op1);
1281    ZVAL_DEREF(op2);
1282
1283    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1284        zval *longer, *shorter;
1285        zend_string *str;
1286        size_t i;
1287
1288        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1289            longer = op1;
1290            shorter = op2;
1291        } else {
1292            longer = op2;
1293            shorter = op1;
1294        }
1295
1296        str = zend_string_alloc(Z_STRLEN_P(longer), 0);
1297        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1298            str->val[i] = Z_STRVAL_P(longer)[i] | Z_STRVAL_P(shorter)[i];
1299        }
1300        memcpy(str->val + i, Z_STRVAL_P(longer) + i, Z_STRLEN_P(longer) - i + 1);
1301        if (result==op1) {
1302            zend_string_release(Z_STR_P(result));
1303        }
1304        ZVAL_NEW_STR(result, str);
1305        return SUCCESS;
1306    }
1307
1308    if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1309        ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_OR, bitwise_or_function);
1310        op1_lval = _zval_get_long_func(op1);
1311    } else {
1312        op1_lval = Z_LVAL_P(op1);
1313    }
1314    if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1315        ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_OR);
1316        op2_lval = _zval_get_long_func(op2);
1317    } else {
1318        op2_lval = Z_LVAL_P(op2);
1319    }
1320
1321    if (op1 == result) {
1322        zval_dtor(result);
1323    }
1324    ZVAL_LONG(result, op1_lval | op2_lval);
1325    return SUCCESS;
1326}
1327/* }}} */
1328
1329ZEND_API int ZEND_FASTCALL bitwise_and_function(zval *result, zval *op1, zval *op2) /* {{{ */
1330{
1331    zend_long op1_lval, op2_lval;
1332
1333    if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1334        ZVAL_LONG(result, Z_LVAL_P(op1) & Z_LVAL_P(op2));
1335        return SUCCESS;
1336    }
1337
1338    ZVAL_DEREF(op1);
1339    ZVAL_DEREF(op2);
1340
1341    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1342        zval *longer, *shorter;
1343        zend_string *str;
1344        size_t i;
1345
1346        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1347            longer = op1;
1348            shorter = op2;
1349        } else {
1350            longer = op2;
1351            shorter = op1;
1352        }
1353
1354        str = zend_string_alloc(Z_STRLEN_P(shorter), 0);
1355        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1356            str->val[i] = Z_STRVAL_P(shorter)[i] & Z_STRVAL_P(longer)[i];
1357        }
1358        str->val[i] = 0;
1359        if (result==op1) {
1360            zend_string_release(Z_STR_P(result));
1361        }
1362        ZVAL_NEW_STR(result, str);
1363        return SUCCESS;
1364    }
1365
1366    if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1367        ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_AND, bitwise_or_function);
1368        op1_lval = _zval_get_long_func(op1);
1369    } else {
1370        op1_lval = Z_LVAL_P(op1);
1371    }
1372    if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1373        ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_AND);
1374        op2_lval = _zval_get_long_func(op2);
1375    } else {
1376        op2_lval = Z_LVAL_P(op2);
1377    }
1378
1379    if (op1 == result) {
1380        zval_dtor(result);
1381    }
1382    ZVAL_LONG(result, op1_lval & op2_lval);
1383    return SUCCESS;
1384}
1385/* }}} */
1386
1387ZEND_API int ZEND_FASTCALL bitwise_xor_function(zval *result, zval *op1, zval *op2) /* {{{ */
1388{
1389    zend_long op1_lval, op2_lval;
1390
1391    if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1392        ZVAL_LONG(result, Z_LVAL_P(op1) ^ Z_LVAL_P(op2));
1393        return SUCCESS;
1394    }
1395
1396    ZVAL_DEREF(op1);
1397    ZVAL_DEREF(op2);
1398
1399    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1400        zval *longer, *shorter;
1401        zend_string *str;
1402        size_t i;
1403
1404        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1405            longer = op1;
1406            shorter = op2;
1407        } else {
1408            longer = op2;
1409            shorter = op1;
1410        }
1411
1412        str = zend_string_alloc(Z_STRLEN_P(shorter), 0);
1413        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1414            str->val[i] = Z_STRVAL_P(shorter)[i] ^ Z_STRVAL_P(longer)[i];
1415        }
1416        str->val[i] = 0;
1417        if (result==op1) {
1418            zend_string_release(Z_STR_P(result));
1419        }
1420        ZVAL_NEW_STR(result, str);
1421        return SUCCESS;
1422    }
1423
1424    if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1425        ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_XOR, bitwise_or_function);
1426        op1_lval = _zval_get_long_func(op1);
1427    } else {
1428        op1_lval = Z_LVAL_P(op1);
1429    }
1430    if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1431        ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_XOR);
1432        op2_lval = _zval_get_long_func(op2);
1433    } else {
1434        op2_lval = Z_LVAL_P(op2);
1435    }
1436
1437    if (op1 == result) {
1438        zval_dtor(result);
1439    }
1440    ZVAL_LONG(result, op1_lval ^ op2_lval);
1441    return SUCCESS;
1442}
1443/* }}} */
1444
1445ZEND_API int ZEND_FASTCALL shift_left_function(zval *result, zval *op1, zval *op2) /* {{{ */
1446{
1447    zend_long op1_lval, op2_lval;
1448
1449    convert_op1_op2_long(op1, op1_lval, op2, op2_lval, ZEND_SL, shift_left_function);
1450
1451    if (op1 == result) {
1452        zval_dtor(result);
1453    }
1454
1455    /* prevent wrapping quirkiness on some processors where << 64 + x == << x */
1456    if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
1457        if (EXPECTED(op2_lval > 0)) {
1458            ZVAL_LONG(result, 0);
1459            return SUCCESS;
1460        } else {
1461            if (EG(current_execute_data) && !CG(in_compilation)) {
1462                zend_throw_exception_ex(NULL, 0, "Bit shift by negative number");
1463            } else {
1464                zend_error_noreturn(E_ERROR, "Bit shift by negative number");
1465            }
1466            ZVAL_UNDEF(result);
1467            return FAILURE;
1468        }
1469    }
1470
1471    ZVAL_LONG(result, op1_lval << op2_lval);
1472    return SUCCESS;
1473}
1474/* }}} */
1475
1476ZEND_API int ZEND_FASTCALL shift_right_function(zval *result, zval *op1, zval *op2) /* {{{ */
1477{
1478    zend_long op1_lval, op2_lval;
1479
1480    convert_op1_op2_long(op1, op1_lval, op2, op2_lval, ZEND_SR, shift_right_function);
1481
1482    if (op1 == result) {
1483        zval_dtor(result);
1484    }
1485
1486    /* prevent wrapping quirkiness on some processors where >> 64 + x == >> x */
1487    if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
1488        if (EXPECTED(op2_lval > 0)) {
1489            ZVAL_LONG(result, (op1_lval < 0) ? -1 : 0);
1490            return SUCCESS;
1491        } else {
1492            if (EG(current_execute_data) && !CG(in_compilation)) {
1493                zend_throw_exception_ex(NULL, 0, "Bit shift by negative number");
1494            } else {
1495                zend_error_noreturn(E_ERROR, "Bit shift by negative number");
1496            }
1497            ZVAL_UNDEF(result);
1498            return FAILURE;
1499        }
1500    }
1501
1502    ZVAL_LONG(result, op1_lval >> op2_lval);
1503    return SUCCESS;
1504}
1505/* }}} */
1506
1507ZEND_API int ZEND_FASTCALL concat_function(zval *result, zval *op1, zval *op2) /* {{{ */
1508{
1509    zval op1_copy, op2_copy;
1510    int use_copy1 = 0, use_copy2 = 0;
1511
1512    do {
1513        if (UNEXPECTED(Z_TYPE_P(op1) != IS_STRING)) {
1514            if (Z_ISREF_P(op1)) {
1515                op1 = Z_REFVAL_P(op1);
1516                if (Z_TYPE_P(op1) == IS_STRING) break;
1517            }
1518            ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT, concat_function);
1519            use_copy1 = zend_make_printable_zval(op1, &op1_copy);
1520            if (use_copy1) {
1521                /* We have created a converted copy of op1. Therefore, op1 won't become the result so
1522                 * we have to free it.
1523                 */
1524                if (result == op1) {
1525                    zval_dtor(op1);
1526                    if (UNEXPECTED(op1 == op2)) {
1527                        op2 = &op1_copy;
1528                    }
1529                }
1530                op1 = &op1_copy;
1531            }
1532        }
1533    } while (0);
1534    do {
1535        if (UNEXPECTED(Z_TYPE_P(op2) != IS_STRING)) {
1536            if (Z_ISREF_P(op2)) {
1537                op2 = Z_REFVAL_P(op2);
1538                if (Z_TYPE_P(op2) == IS_STRING) break;
1539            }
1540            ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_CONCAT);
1541            use_copy2 = zend_make_printable_zval(op2, &op2_copy);
1542            if (use_copy2) {
1543                op2 = &op2_copy;
1544            }
1545        }
1546    } while (0);
1547
1548    {
1549        size_t op1_len = Z_STRLEN_P(op1);
1550        size_t op2_len = Z_STRLEN_P(op2);
1551        size_t result_len = op1_len + op2_len;
1552        zend_string *result_str;
1553
1554        if (UNEXPECTED(op1_len > SIZE_MAX - op2_len)) {
1555            zend_error(E_EXCEPTION | E_ERROR, "String size overflow");
1556            ZVAL_FALSE(result);
1557            return FAILURE;
1558        }
1559
1560        if (result == op1 && Z_REFCOUNTED_P(result)) {
1561            /* special case, perform operations on result */
1562            result_str = zend_string_extend(Z_STR_P(result), result_len, 0);
1563        } else {
1564            result_str = zend_string_alloc(result_len, 0);
1565            memcpy(result_str->val, Z_STRVAL_P(op1), op1_len);
1566        }
1567
1568        /* This has to happen first to account for the cases where result == op1 == op2 and
1569         * the realloc is done. In this case this line will also update Z_STRVAL_P(op2) to
1570         * point to the new string. The first op2_len bytes of result will still be the same. */
1571        ZVAL_NEW_STR(result, result_str);
1572
1573        memcpy(result_str->val + op1_len, Z_STRVAL_P(op2), op2_len);
1574        result_str->val[result_len] = '\0';
1575    }
1576
1577    if (UNEXPECTED(use_copy1)) {
1578        zval_dtor(op1);
1579    }
1580    if (UNEXPECTED(use_copy2)) {
1581        zval_dtor(op2);
1582    }
1583    return SUCCESS;
1584}
1585/* }}} */
1586
1587ZEND_API int string_compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool case_insensitive) /* {{{ */
1588{
1589    zend_string *str1 = zval_get_string(op1);
1590    zend_string *str2 = zval_get_string(op2);
1591
1592    if (case_insensitive) {
1593        ZVAL_LONG(result, zend_binary_strcasecmp_l(str1->val, str1->len, str2->val, str1->len));
1594    } else {
1595        ZVAL_LONG(result, zend_binary_strcmp(str1->val, str1->len, str2->val, str2->len));
1596    }
1597
1598    zend_string_release(str1);
1599    zend_string_release(str2);
1600    return SUCCESS;
1601}
1602/* }}} */
1603
1604ZEND_API int string_compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
1605{
1606    if (EXPECTED(Z_TYPE_P(op1) == IS_STRING) &&
1607        EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
1608        if (Z_STR_P(op1) == Z_STR_P(op2)) {
1609            ZVAL_LONG(result, 0);
1610        } else {
1611            ZVAL_LONG(result, zend_binary_strcmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2)));
1612        }
1613    } else {
1614        zend_string *str1 = zval_get_string(op1);
1615        zend_string *str2 = zval_get_string(op2);
1616
1617        ZVAL_LONG(result, zend_binary_strcmp(str1->val, str1->len, str2->val, str2->len));
1618
1619        zend_string_release(str1);
1620        zend_string_release(str2);
1621    }
1622    return SUCCESS;
1623}
1624/* }}} */
1625
1626ZEND_API int string_case_compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
1627{
1628    if (EXPECTED(Z_TYPE_P(op1) == IS_STRING) &&
1629        EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
1630        if (Z_STR_P(op1) == Z_STR_P(op2)) {
1631            ZVAL_LONG(result, 0);
1632        } else {
1633            ZVAL_LONG(result, zend_binary_strcasecmp_l(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2)));
1634        }
1635    } else {
1636        zend_string *str1 = zval_get_string(op1);
1637        zend_string *str2 = zval_get_string(op2);
1638
1639        ZVAL_LONG(result, zend_binary_strcasecmp_l(str1->val, str1->len, str2->val, str1->len));
1640
1641        zend_string_release(str1);
1642        zend_string_release(str2);
1643    }
1644    return SUCCESS;
1645}
1646/* }}} */
1647
1648#if HAVE_STRCOLL
1649ZEND_API int string_locale_compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
1650{
1651    zend_string *str1 = zval_get_string(op1);
1652    zend_string *str2 = zval_get_string(op2);
1653
1654    ZVAL_LONG(result, strcoll(str1->val, str2->val));
1655
1656    zend_string_release(str1);
1657    zend_string_release(str2);
1658    return SUCCESS;
1659}
1660/* }}} */
1661#endif
1662
1663ZEND_API int numeric_compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
1664{
1665    double d1, d2;
1666
1667    d1 = zval_get_double(op1);
1668    d2 = zval_get_double(op2);
1669
1670    ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(d1 - d2));
1671
1672    return SUCCESS;
1673}
1674/* }}} */
1675
1676static inline void zend_free_obj_get_result(zval *op) /* {{{ */
1677{
1678    if (Z_REFCOUNTED_P(op)) {
1679        if (Z_REFCOUNT_P(op) == 0) {
1680            zval_dtor(op);
1681        } else {
1682            zval_ptr_dtor(op);
1683        }
1684    }
1685}
1686/* }}} */
1687
1688ZEND_API int compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
1689{
1690    int ret;
1691    int converted = 0;
1692    zval op1_copy, op2_copy;
1693    zval *op_free, tmp_free;
1694
1695    while (1) {
1696        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
1697            case TYPE_PAIR(IS_LONG, IS_LONG):
1698                ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0));
1699                return SUCCESS;
1700
1701            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1702                Z_DVAL_P(result) = Z_DVAL_P(op1) - (double)Z_LVAL_P(op2);
1703                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1704                return SUCCESS;
1705
1706            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1707                Z_DVAL_P(result) = (double)Z_LVAL_P(op1) - Z_DVAL_P(op2);
1708                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1709                return SUCCESS;
1710
1711            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1712                if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
1713                    ZVAL_LONG(result, 0);
1714                } else {
1715                    Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2);
1716                    ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1717                }
1718                return SUCCESS;
1719
1720            case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
1721                ZVAL_LONG(result, zend_compare_arrays(op1, op2));
1722                return SUCCESS;
1723
1724            case TYPE_PAIR(IS_NULL, IS_NULL):
1725            case TYPE_PAIR(IS_NULL, IS_FALSE):
1726            case TYPE_PAIR(IS_FALSE, IS_NULL):
1727            case TYPE_PAIR(IS_FALSE, IS_FALSE):
1728            case TYPE_PAIR(IS_TRUE, IS_TRUE):
1729                ZVAL_LONG(result, 0);
1730                return SUCCESS;
1731
1732            case TYPE_PAIR(IS_NULL, IS_TRUE):
1733                ZVAL_LONG(result, -1);
1734                return SUCCESS;
1735
1736            case TYPE_PAIR(IS_TRUE, IS_NULL):
1737                ZVAL_LONG(result, 1);
1738                return SUCCESS;
1739
1740            case TYPE_PAIR(IS_STRING, IS_STRING):
1741                if (Z_STR_P(op1) == Z_STR_P(op2)) {
1742                    ZVAL_LONG(result, 0);
1743                    return SUCCESS;
1744                }
1745                ZVAL_LONG(result, zendi_smart_strcmp(op1, op2));
1746                return SUCCESS;
1747
1748            case TYPE_PAIR(IS_NULL, IS_STRING):
1749                ZVAL_LONG(result, Z_STRLEN_P(op2) == 0 ? 0 : -1);
1750                return SUCCESS;
1751
1752            case TYPE_PAIR(IS_STRING, IS_NULL):
1753                ZVAL_LONG(result, Z_STRLEN_P(op1) == 0 ? 0 : 1);
1754                return SUCCESS;
1755
1756            case TYPE_PAIR(IS_OBJECT, IS_NULL):
1757                ZVAL_LONG(result, 1);
1758                return SUCCESS;
1759
1760            case TYPE_PAIR(IS_NULL, IS_OBJECT):
1761                ZVAL_LONG(result, -1);
1762                return SUCCESS;
1763
1764            default:
1765                if (Z_ISREF_P(op1)) {
1766                    op1 = Z_REFVAL_P(op1);
1767                    continue;
1768                } else if (Z_ISREF_P(op2)) {
1769                    op2 = Z_REFVAL_P(op2);
1770                    continue;
1771                }
1772
1773                if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, compare)) {
1774                    return Z_OBJ_HANDLER_P(op1, compare)(result, op1, op2);
1775                } else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, compare)) {
1776                    return Z_OBJ_HANDLER_P(op2, compare)(result, op1, op2);
1777                }
1778
1779                if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) == IS_OBJECT) {
1780                    if (Z_OBJ_P(op1) == Z_OBJ_P(op2)) {
1781                        /* object handles are identical, apparently this is the same object */
1782                        ZVAL_LONG(result, 0);
1783                        return SUCCESS;
1784                    }
1785                    if (Z_OBJ_HANDLER_P(op1, compare_objects) == Z_OBJ_HANDLER_P(op2, compare_objects)) {
1786                        ZVAL_LONG(result, Z_OBJ_HANDLER_P(op1, compare_objects)(op1, op2));
1787                        return SUCCESS;
1788                    }
1789                }
1790                if (Z_TYPE_P(op1) == IS_OBJECT) {
1791                    if (Z_OBJ_HT_P(op1)->get) {
1792                        zval rv;
1793                        op_free = Z_OBJ_HT_P(op1)->get(op1, &rv);
1794                        ret = compare_function(result, op_free, op2);
1795                        zend_free_obj_get_result(op_free);
1796                        return ret;
1797                    } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) {
1798                        ZVAL_UNDEF(&tmp_free);
1799                        if (Z_OBJ_HT_P(op1)->cast_object(op1, &tmp_free, ((Z_TYPE_P(op2) == IS_FALSE || Z_TYPE_P(op2) == IS_TRUE) ? _IS_BOOL : Z_TYPE_P(op2))) == FAILURE) {
1800                            ZVAL_LONG(result, 1);
1801                            zend_free_obj_get_result(&tmp_free);
1802                            return SUCCESS;
1803                        }
1804                        ret = compare_function(result, &tmp_free, op2);
1805                        zend_free_obj_get_result(&tmp_free);
1806                        return ret;
1807                    }
1808                }
1809                if (Z_TYPE_P(op2) == IS_OBJECT) {
1810                    if (Z_OBJ_HT_P(op2)->get) {
1811                        zval rv;
1812                        op_free = Z_OBJ_HT_P(op2)->get(op2, &rv);
1813                        ret = compare_function(result, op1, op_free);
1814                        zend_free_obj_get_result(op_free);
1815                        return ret;
1816                    } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) {
1817                        ZVAL_UNDEF(&tmp_free);
1818                        if (Z_OBJ_HT_P(op2)->cast_object(op2, &tmp_free, ((Z_TYPE_P(op1) == IS_FALSE || Z_TYPE_P(op1) == IS_TRUE) ? _IS_BOOL : Z_TYPE_P(op1))) == FAILURE) {
1819                            ZVAL_LONG(result, -1);
1820                            zend_free_obj_get_result(&tmp_free);
1821                            return SUCCESS;
1822                        }
1823                        ret = compare_function(result, op1, &tmp_free);
1824                        zend_free_obj_get_result(&tmp_free);
1825                        return ret;
1826                    } else if (Z_TYPE_P(op1) == IS_OBJECT) {
1827                        ZVAL_LONG(result, 1);
1828                        return SUCCESS;
1829                    }
1830                }
1831                if (!converted) {
1832                    if (Z_TYPE_P(op1) == IS_NULL || Z_TYPE_P(op1) == IS_FALSE) {
1833                        ZVAL_LONG(result, zval_is_true(op2) ? -1 : 0);
1834                        return SUCCESS;
1835                    } else if (Z_TYPE_P(op2) == IS_NULL || Z_TYPE_P(op2) == IS_FALSE) {
1836                        ZVAL_LONG(result, zval_is_true(op1) ? 1 : 0);
1837                        return SUCCESS;
1838                    } else if (Z_TYPE_P(op1) == IS_TRUE) {
1839                        ZVAL_LONG(result, zval_is_true(op2) ? 0 : 1);
1840                        return SUCCESS;
1841                    } else if (Z_TYPE_P(op2) == IS_TRUE) {
1842                        ZVAL_LONG(result, zval_is_true(op1) ? 0 : -1);
1843                        return SUCCESS;
1844                    } else {
1845                        zendi_convert_scalar_to_number(op1, op1_copy, result);
1846                        zendi_convert_scalar_to_number(op2, op2_copy, result);
1847                        converted = 1;
1848                    }
1849                } else if (Z_TYPE_P(op1)==IS_ARRAY) {
1850                    ZVAL_LONG(result, 1);
1851                    return SUCCESS;
1852                } else if (Z_TYPE_P(op2)==IS_ARRAY) {
1853                    ZVAL_LONG(result, -1);
1854                    return SUCCESS;
1855                } else if (Z_TYPE_P(op1)==IS_OBJECT) {
1856                    ZVAL_LONG(result, 1);
1857                    return SUCCESS;
1858                } else if (Z_TYPE_P(op2)==IS_OBJECT) {
1859                    ZVAL_LONG(result, -1);
1860                    return SUCCESS;
1861                } else {
1862                    ZVAL_LONG(result, 0);
1863                    return FAILURE;
1864                }
1865        }
1866    }
1867}
1868/* }}} */
1869
1870static int hash_zval_identical_function(zval *z1, zval *z2) /* {{{ */
1871{
1872    zval result;
1873
1874    /* is_identical_function() returns 1 in case of identity and 0 in case
1875     * of a difference;
1876     * whereas this comparison function is expected to return 0 on identity,
1877     * and non zero otherwise.
1878     */
1879    ZVAL_DEREF(z1);
1880    ZVAL_DEREF(z2);
1881    if (is_identical_function(&result, z1, z2)==FAILURE) {
1882        return 1;
1883    }
1884    return Z_TYPE(result) != IS_TRUE;
1885}
1886/* }}} */
1887
1888ZEND_API int ZEND_FASTCALL is_identical_function(zval *result, zval *op1, zval *op2) /* {{{ */
1889{
1890    if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
1891        ZVAL_FALSE(result);
1892        return SUCCESS;
1893    }
1894    switch (Z_TYPE_P(op1)) {
1895        case IS_NULL:
1896        case IS_FALSE:
1897        case IS_TRUE:
1898            ZVAL_TRUE(result);
1899            break;
1900        case IS_LONG:
1901            ZVAL_BOOL(result, Z_LVAL_P(op1) == Z_LVAL_P(op2));
1902            break;
1903        case IS_RESOURCE:
1904            ZVAL_BOOL(result, Z_RES_P(op1) == Z_RES_P(op2));
1905            break;
1906        case IS_DOUBLE:
1907            ZVAL_BOOL(result, Z_DVAL_P(op1) == Z_DVAL_P(op2));
1908            break;
1909        case IS_STRING:
1910            if (Z_STR_P(op1) == Z_STR_P(op2)) {
1911                ZVAL_TRUE(result);
1912            } else {
1913                ZVAL_BOOL(result, (Z_STRLEN_P(op1) == Z_STRLEN_P(op2))
1914                    && (!memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1))));
1915            }
1916            break;
1917        case IS_ARRAY:
1918            ZVAL_BOOL(result, Z_ARRVAL_P(op1) == Z_ARRVAL_P(op2) ||
1919                zend_hash_compare(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2), (compare_func_t) hash_zval_identical_function, 1)==0);
1920            break;
1921        case IS_OBJECT:
1922            if (Z_OBJ_HT_P(op1) == Z_OBJ_HT_P(op2)) {
1923                ZVAL_BOOL(result, Z_OBJ_P(op1) == Z_OBJ_P(op2));
1924            } else {
1925                ZVAL_FALSE(result);
1926            }
1927            break;
1928        default:
1929            ZVAL_FALSE(result);
1930            return FAILURE;
1931    }
1932    return SUCCESS;
1933}
1934/* }}} */
1935
1936ZEND_API int ZEND_FASTCALL is_not_identical_function(zval *result, zval *op1, zval *op2) /* {{{ */
1937{
1938    if (is_identical_function(result, op1, op2) == FAILURE) {
1939        return FAILURE;
1940    }
1941    ZVAL_BOOL(result, Z_TYPE_P(result) != IS_TRUE);
1942    return SUCCESS;
1943}
1944/* }}} */
1945
1946ZEND_API int ZEND_FASTCALL is_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
1947{
1948    if (compare_function(result, op1, op2) == FAILURE) {
1949        return FAILURE;
1950    }
1951    ZVAL_BOOL(result, (Z_LVAL_P(result) == 0));
1952    return SUCCESS;
1953}
1954/* }}} */
1955
1956ZEND_API int ZEND_FASTCALL is_not_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
1957{
1958    if (compare_function(result, op1, op2) == FAILURE) {
1959        return FAILURE;
1960    }
1961    ZVAL_BOOL(result, (Z_LVAL_P(result) != 0));
1962    return SUCCESS;
1963}
1964/* }}} */
1965
1966ZEND_API int ZEND_FASTCALL is_smaller_function(zval *result, zval *op1, zval *op2) /* {{{ */
1967{
1968    if (compare_function(result, op1, op2) == FAILURE) {
1969        return FAILURE;
1970    }
1971    ZVAL_BOOL(result, (Z_LVAL_P(result) < 0));
1972    return SUCCESS;
1973}
1974/* }}} */
1975
1976ZEND_API int ZEND_FASTCALL is_smaller_or_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
1977{
1978    if (compare_function(result, op1, op2) == FAILURE) {
1979        return FAILURE;
1980    }
1981    ZVAL_BOOL(result, (Z_LVAL_P(result) <= 0));
1982    return SUCCESS;
1983}
1984/* }}} */
1985
1986static zend_bool ZEND_FASTCALL instanceof_interface_only(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
1987{
1988    uint32_t i;
1989
1990    for (i = 0; i < instance_ce->num_interfaces; i++) {
1991        if (instanceof_interface_only(instance_ce->interfaces[i], ce)) {
1992            return 1;
1993        }
1994    }
1995    return 0;
1996}
1997/* }}} */
1998
1999static zend_always_inline zend_bool instanceof_class(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
2000{
2001    while (instance_ce) {
2002        if (instance_ce == ce) {
2003            return 1;
2004        }
2005        instance_ce = instance_ce->parent;
2006    }
2007    return 0;
2008}
2009/* }}} */
2010
2011static zend_bool ZEND_FASTCALL instanceof_interface(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
2012{
2013    uint32_t i;
2014
2015    for (i = 0; i < instance_ce->num_interfaces; i++) {
2016        if (instanceof_interface(instance_ce->interfaces[i], ce)) {
2017            return 1;
2018        }
2019    }
2020    return instanceof_class(instance_ce, ce);
2021}
2022/* }}} */
2023
2024ZEND_API zend_bool ZEND_FASTCALL instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool interfaces_only) /* {{{ */
2025{
2026    if (ce->ce_flags & ZEND_ACC_INTERFACE) {
2027        if (!interfaces_only) {
2028            if (instanceof_interface_only(instance_ce, ce)) {
2029                return 1;
2030            }
2031        } else {
2032            return instanceof_interface(instance_ce, ce);
2033        }
2034    }
2035    if (!interfaces_only) {
2036        return instanceof_class(instance_ce, ce);
2037    }
2038    return 0;
2039}
2040/* }}} */
2041
2042ZEND_API zend_bool ZEND_FASTCALL instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
2043{
2044    if (ce->ce_flags & ZEND_ACC_INTERFACE) {
2045        return instanceof_interface(instance_ce, ce);
2046    } else {
2047        return instanceof_class(instance_ce, ce);
2048    }
2049}
2050/* }}} */
2051
2052#define LOWER_CASE 1
2053#define UPPER_CASE 2
2054#define NUMERIC 3
2055
2056static void ZEND_FASTCALL increment_string(zval *str) /* {{{ */
2057{
2058    int carry=0;
2059    size_t pos=Z_STRLEN_P(str)-1;
2060    char *s;
2061    zend_string *t;
2062    int last=0; /* Shut up the compiler warning */
2063    int ch;
2064
2065    if (Z_STRLEN_P(str) == 0) {
2066        zend_string_release(Z_STR_P(str));
2067        Z_STR_P(str) = zend_string_init("1", sizeof("1")-1, 0);
2068        Z_TYPE_INFO_P(str) = IS_STRING_EX;
2069        return;
2070    }
2071
2072    if (!Z_REFCOUNTED_P(str)) {
2073        Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
2074        Z_TYPE_INFO_P(str) = IS_STRING_EX;
2075    } else if (Z_REFCOUNT_P(str) > 1) {
2076        Z_DELREF_P(str);
2077        Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
2078    } else {
2079        zend_string_forget_hash_val(Z_STR_P(str));
2080    }
2081    s = Z_STRVAL_P(str);
2082
2083    do {
2084        ch = s[pos];
2085        if (ch >= 'a' && ch <= 'z') {
2086            if (ch == 'z') {
2087                s[pos] = 'a';
2088                carry=1;
2089            } else {
2090                s[pos]++;
2091                carry=0;
2092            }
2093            last=LOWER_CASE;
2094        } else if (ch >= 'A' && ch <= 'Z') {
2095            if (ch == 'Z') {
2096                s[pos] = 'A';
2097                carry=1;
2098            } else {
2099                s[pos]++;
2100                carry=0;
2101            }
2102            last=UPPER_CASE;
2103        } else if (ch >= '0' && ch <= '9') {
2104            if (ch == '9') {
2105                s[pos] = '0';
2106                carry=1;
2107            } else {
2108                s[pos]++;
2109                carry=0;
2110            }
2111            last = NUMERIC;
2112        } else {
2113            carry=0;
2114            break;
2115        }
2116        if (carry == 0) {
2117            break;
2118        }
2119    } while (pos-- > 0);
2120
2121    if (carry) {
2122        t = zend_string_alloc(Z_STRLEN_P(str)+1, 0);
2123        memcpy(t->val + 1, Z_STRVAL_P(str), Z_STRLEN_P(str));
2124        t->val[Z_STRLEN_P(str) + 1] = '\0';
2125        switch (last) {
2126            case NUMERIC:
2127                t->val[0] = '1';
2128                break;
2129            case UPPER_CASE:
2130                t->val[0] = 'A';
2131                break;
2132            case LOWER_CASE:
2133                t->val[0] = 'a';
2134                break;
2135        }
2136        zend_string_free(Z_STR_P(str));
2137        ZVAL_NEW_STR(str, t);
2138    }
2139}
2140/* }}} */
2141
2142ZEND_API int ZEND_FASTCALL increment_function(zval *op1) /* {{{ */
2143{
2144try_again:
2145    switch (Z_TYPE_P(op1)) {
2146        case IS_LONG:
2147            fast_long_increment_function(op1);
2148            break;
2149        case IS_DOUBLE:
2150            Z_DVAL_P(op1) = Z_DVAL_P(op1) + 1;
2151            break;
2152        case IS_NULL:
2153            ZVAL_LONG(op1, 1);
2154            break;
2155        case IS_STRING: {
2156                zend_long lval;
2157                double dval;
2158
2159                switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
2160                    case IS_LONG:
2161                        zend_string_release(Z_STR_P(op1));
2162                        if (lval == ZEND_LONG_MAX) {
2163                            /* switch to double */
2164                            double d = (double)lval;
2165                            ZVAL_DOUBLE(op1, d+1);
2166                        } else {
2167                            ZVAL_LONG(op1, lval+1);
2168                        }
2169                        break;
2170                    case IS_DOUBLE:
2171                        zend_string_release(Z_STR_P(op1));
2172                        ZVAL_DOUBLE(op1, dval+1);
2173                        break;
2174                    default:
2175                        /* Perl style string increment */
2176                        increment_string(op1);
2177                        break;
2178                }
2179            }
2180            break;
2181        case IS_OBJECT:
2182            if (Z_OBJ_HANDLER_P(op1, get)
2183               && Z_OBJ_HANDLER_P(op1, set)) {
2184                /* proxy object */
2185                zval rv;
2186                zval *val;
2187
2188                val = Z_OBJ_HANDLER_P(op1, get)(op1, &rv);
2189                Z_ADDREF_P(val);
2190                increment_function(val);
2191                Z_OBJ_HANDLER_P(op1, set)(op1, val);
2192                zval_ptr_dtor(val);
2193            } else if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2194                zval op2;
2195                int res;
2196
2197                ZVAL_LONG(&op2, 1);
2198                res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_ADD, op1, op1, &op2);
2199                zval_ptr_dtor(&op2);
2200
2201                return res;
2202            }
2203            return FAILURE;
2204        case IS_REFERENCE:
2205            op1 = Z_REFVAL_P(op1);
2206            goto try_again;
2207        default:
2208            return FAILURE;
2209    }
2210    return SUCCESS;
2211}
2212/* }}} */
2213
2214ZEND_API int ZEND_FASTCALL decrement_function(zval *op1) /* {{{ */
2215{
2216    zend_long lval;
2217    double dval;
2218
2219try_again:
2220    switch (Z_TYPE_P(op1)) {
2221        case IS_LONG:
2222            fast_long_decrement_function(op1);
2223            break;
2224        case IS_DOUBLE:
2225            Z_DVAL_P(op1) = Z_DVAL_P(op1) - 1;
2226            break;
2227        case IS_STRING:     /* Like perl we only support string increment */
2228            if (Z_STRLEN_P(op1) == 0) { /* consider as 0 */
2229                zend_string_release(Z_STR_P(op1));
2230                ZVAL_LONG(op1, -1);
2231                break;
2232            }
2233            switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
2234                case IS_LONG:
2235                    zend_string_release(Z_STR_P(op1));
2236                    if (lval == ZEND_LONG_MIN) {
2237                        double d = (double)lval;
2238                        ZVAL_DOUBLE(op1, d-1);
2239                    } else {
2240                        ZVAL_LONG(op1, lval-1);
2241                    }
2242                    break;
2243                case IS_DOUBLE:
2244                    zend_string_release(Z_STR_P(op1));
2245                    ZVAL_DOUBLE(op1, dval - 1);
2246                    break;
2247            }
2248            break;
2249        case IS_OBJECT:
2250            if (Z_OBJ_HANDLER_P(op1, get)
2251               && Z_OBJ_HANDLER_P(op1, set)) {
2252                /* proxy object */
2253                zval rv;
2254                zval *val;
2255
2256                val = Z_OBJ_HANDLER_P(op1, get)(op1, &rv);
2257                Z_ADDREF_P(val);
2258                decrement_function(val);
2259                Z_OBJ_HANDLER_P(op1, set)(op1, val);
2260                zval_ptr_dtor(val);
2261            } else if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2262                zval op2;
2263                int res;
2264
2265                ZVAL_LONG(&op2, 1);
2266                res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_SUB, op1, op1, &op2);
2267                zval_ptr_dtor(&op2);
2268
2269                return res;
2270            }
2271            return FAILURE;
2272        case IS_REFERENCE:
2273            op1 = Z_REFVAL_P(op1);
2274            goto try_again;
2275        default:
2276            return FAILURE;
2277    }
2278
2279    return SUCCESS;
2280}
2281/* }}} */
2282
2283ZEND_API int ZEND_FASTCALL zend_is_true(zval *op) /* {{{ */
2284{
2285    return i_zend_is_true(op);
2286}
2287/* }}} */
2288
2289ZEND_API int ZEND_FASTCALL zend_object_is_true(zval *op) /* {{{ */
2290{
2291    if (Z_OBJ_HT_P(op)->cast_object) {
2292        zval tmp;
2293        if (Z_OBJ_HT_P(op)->cast_object(op, &tmp, _IS_BOOL) == SUCCESS) {
2294            return Z_TYPE(tmp) == IS_TRUE;
2295        }
2296        zend_error(E_RECOVERABLE_ERROR, "Object of class %s could not be converted to boolean", Z_OBJ_P(op)->ce->name->val);
2297    } else if (Z_OBJ_HT_P(op)->get) {
2298        int result;
2299        zval rv;
2300        zval *tmp = Z_OBJ_HT_P(op)->get(op, &rv);
2301
2302        if (Z_TYPE_P(tmp) != IS_OBJECT) {
2303            /* for safety - avoid loop */
2304            result = i_zend_is_true(tmp);
2305            zval_ptr_dtor(tmp);
2306            return result;
2307        }
2308    }
2309    return 1;
2310}
2311/* }}} */
2312
2313#ifdef ZEND_USE_TOLOWER_L
2314ZEND_API void zend_update_current_locale(void) /* {{{ */
2315{
2316    current_locale = _get_current_locale();
2317}
2318/* }}} */
2319#endif
2320
2321ZEND_API char* ZEND_FASTCALL zend_str_tolower_copy(char *dest, const char *source, size_t length) /* {{{ */
2322{
2323    register unsigned char *str = (unsigned char*)source;
2324    register unsigned char *result = (unsigned char*)dest;
2325    register unsigned char *end = str + length;
2326
2327    while (str < end) {
2328        *result++ = zend_tolower_ascii(*str++);
2329    }
2330    *result = '\0';
2331
2332    return dest;
2333}
2334/* }}} */
2335
2336ZEND_API char* ZEND_FASTCALL zend_str_tolower_dup(const char *source, size_t length) /* {{{ */
2337{
2338    return zend_str_tolower_copy((char *)emalloc(length+1), source, length);
2339}
2340/* }}} */
2341
2342ZEND_API void ZEND_FASTCALL zend_str_tolower(char *str, size_t length) /* {{{ */
2343{
2344    register unsigned char *p = (unsigned char*)str;
2345    register unsigned char *end = p + length;
2346
2347    while (p < end) {
2348        *p = zend_tolower_ascii(*p);
2349        p++;
2350    }
2351}
2352/* }}} */
2353
2354ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower(zend_string *str) /* {{{ */
2355{
2356    register unsigned char *p = (unsigned char*)str->val;
2357    register unsigned char *end = p + str->len;
2358
2359    while (p < end) {
2360        if (*p != zend_tolower_ascii(*p)) {
2361            zend_string *res = zend_string_alloc(str->len, 0);
2362            register unsigned char *r;
2363
2364            if (p != (unsigned char*)str->val) {
2365                memcpy(res->val, str->val, p - (unsigned char*)str->val);
2366            }
2367            r = p + (res->val - str->val);
2368            while (p < end) {
2369                *r = zend_tolower_ascii(*p);
2370                p++;
2371                r++;
2372            }
2373            *r = '\0';
2374            return res;
2375        }
2376        p++;
2377    }
2378    return zend_string_copy(str);
2379}
2380/* }}} */
2381
2382ZEND_API int ZEND_FASTCALL zend_binary_strcmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
2383{
2384    int retval;
2385
2386    if (s1 == s2) {
2387        return 0;
2388    }
2389    retval = memcmp(s1, s2, MIN(len1, len2));
2390    if (!retval) {
2391        return (int)(len1 - len2);
2392    } else {
2393        return retval;
2394    }
2395}
2396/* }}} */
2397
2398ZEND_API int ZEND_FASTCALL zend_binary_strncmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
2399{
2400    int retval;
2401
2402    if (s1 == s2) {
2403        return 0;
2404    }
2405    retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
2406    if (!retval) {
2407        return (int)(MIN(length, len1) - MIN(length, len2));
2408    } else {
2409        return retval;
2410    }
2411}
2412/* }}} */
2413
2414ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
2415{
2416    size_t len;
2417    int c1, c2;
2418
2419    if (s1 == s2) {
2420        return 0;
2421    }
2422
2423    len = MIN(len1, len2);
2424    while (len--) {
2425        c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2426        c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2427        if (c1 != c2) {
2428            return c1 - c2;
2429        }
2430    }
2431
2432    return (int)(len1 - len2);
2433}
2434/* }}} */
2435
2436ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
2437{
2438    size_t len;
2439    int c1, c2;
2440
2441    if (s1 == s2) {
2442        return 0;
2443    }
2444    len = MIN(length, MIN(len1, len2));
2445    while (len--) {
2446        c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2447        c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2448        if (c1 != c2) {
2449            return c1 - c2;
2450        }
2451    }
2452
2453    return (int)(MIN(length, len1) - MIN(length, len2));
2454}
2455/* }}} */
2456
2457ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
2458{
2459    size_t len;
2460    int c1, c2;
2461
2462    if (s1 == s2) {
2463        return 0;
2464    }
2465
2466    len = MIN(len1, len2);
2467    while (len--) {
2468        c1 = zend_tolower((int)*(unsigned char *)s1++);
2469        c2 = zend_tolower((int)*(unsigned char *)s2++);
2470        if (c1 != c2) {
2471            return c1 - c2;
2472        }
2473    }
2474
2475    return (int)(len1 - len2);
2476}
2477/* }}} */
2478
2479ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
2480{
2481    size_t len;
2482    int c1, c2;
2483
2484    if (s1 == s2) {
2485        return 0;
2486    }
2487    len = MIN(length, MIN(len1, len2));
2488    while (len--) {
2489        c1 = zend_tolower((int)*(unsigned char *)s1++);
2490        c2 = zend_tolower((int)*(unsigned char *)s2++);
2491        if (c1 != c2) {
2492            return c1 - c2;
2493        }
2494    }
2495
2496    return (int)(MIN(length, len1) - MIN(length, len2));
2497}
2498/* }}} */
2499
2500ZEND_API int ZEND_FASTCALL zend_binary_zval_strcmp(zval *s1, zval *s2) /* {{{ */
2501{
2502    return zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2503}
2504/* }}} */
2505
2506ZEND_API int ZEND_FASTCALL zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2507{
2508    return zend_binary_strncmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
2509}
2510/* }}} */
2511
2512ZEND_API int ZEND_FASTCALL zend_binary_zval_strcasecmp(zval *s1, zval *s2) /* {{{ */
2513{
2514    return zend_binary_strcasecmp_l(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2515}
2516/* }}} */
2517
2518ZEND_API int ZEND_FASTCALL zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2519{
2520    return zend_binary_strncasecmp_l(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
2521}
2522/* }}} */
2523
2524ZEND_API zend_long ZEND_FASTCALL zendi_smart_strcmp(zval *s1, zval *s2) /* {{{ */
2525{
2526    int ret1, ret2;
2527    int oflow1, oflow2;
2528    zend_long lval1 = 0, lval2 = 0;
2529    double dval1 = 0.0, dval2 = 0.0;
2530
2531    if ((ret1 = is_numeric_string_ex(Z_STRVAL_P(s1), Z_STRLEN_P(s1), &lval1, &dval1, 0, &oflow1)) &&
2532        (ret2 = is_numeric_string_ex(Z_STRVAL_P(s2), Z_STRLEN_P(s2), &lval2, &dval2, 0, &oflow2))) {
2533#if ZEND_ULONG_MAX == 0xFFFFFFFF
2534        if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
2535            ((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
2536            || (oflow1 == -1 && dval1 < -9007199254740991.))) {
2537#else
2538        if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
2539#endif
2540            /* both values are integers overflown to the same side, and the
2541             * double comparison may have resulted in crucial accuracy lost */
2542            goto string_cmp;
2543        }
2544        if ((ret1 == IS_DOUBLE) || (ret2 == IS_DOUBLE)) {
2545            if (ret1 != IS_DOUBLE) {
2546                if (oflow2) {
2547                    /* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
2548                    return -1 * oflow2;
2549                }
2550                dval1 = (double) lval1;
2551            } else if (ret2 != IS_DOUBLE) {
2552                if (oflow1) {
2553                    return oflow1;
2554                }
2555                dval2 = (double) lval2;
2556            } else if (dval1 == dval2 && !zend_finite(dval1)) {
2557                /* Both values overflowed and have the same sign,
2558                 * so a numeric comparison would be inaccurate */
2559                goto string_cmp;
2560            }
2561            dval1 = dval1 - dval2;
2562            return ZEND_NORMALIZE_BOOL(dval1);
2563        } else { /* they both have to be long's */
2564            return lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0);
2565        }
2566    } else {
2567        int strcmp_ret;
2568string_cmp:
2569        strcmp_ret = zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2570        return ZEND_NORMALIZE_BOOL(strcmp_ret);
2571    }
2572}
2573/* }}} */
2574
2575static int hash_zval_compare_function(zval *z1, zval *z2) /* {{{ */
2576{
2577    zval result;
2578
2579    if (compare_function(&result, z1, z2)==FAILURE) {
2580        return 1;
2581    }
2582    return Z_LVAL(result);
2583}
2584/* }}} */
2585
2586ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable *ht2) /* {{{ */
2587{
2588    return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0);
2589}
2590/* }}} */
2591
2592ZEND_API int ZEND_FASTCALL zend_compare_arrays(zval *a1, zval *a2) /* {{{ */
2593{
2594    return zend_compare_symbol_tables(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2));
2595}
2596/* }}} */
2597
2598ZEND_API int ZEND_FASTCALL zend_compare_objects(zval *o1, zval *o2) /* {{{ */
2599{
2600    if (Z_OBJ_P(o1) == Z_OBJ_P(o2)) {
2601        return 0;
2602    }
2603
2604    if (Z_OBJ_HT_P(o1)->compare_objects == NULL) {
2605        return 1;
2606    } else {
2607        return Z_OBJ_HT_P(o1)->compare_objects(o1, o2);
2608    }
2609}
2610/* }}} */
2611
2612ZEND_API void ZEND_FASTCALL zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) /* {{{ */
2613{
2614    zend_string *str;
2615
2616    str = zend_strpprintf(0, "%.*G", (int) EG(precision), (double)Z_DVAL_P(op));
2617    ZVAL_NEW_STR(op, str);
2618}
2619/* }}} */
2620
2621ZEND_API zend_string* ZEND_FASTCALL zend_long_to_str(zend_long num) /* {{{ */
2622{
2623    char buf[MAX_LENGTH_OF_LONG + 1];
2624    char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, num);
2625    return zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
2626}
2627/* }}} */
2628
2629ZEND_API zend_uchar ZEND_FASTCALL is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval) /* {{{ */ {
2630    return is_numeric_string_ex(str->val, str->len, lval, dval, -1, NULL);
2631}
2632/* }}} */
2633
2634ZEND_API zend_uchar ZEND_FASTCALL _is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors, int *oflow_info) /* {{{ */
2635{
2636    const char *ptr;
2637    int digits = 0, dp_or_e = 0;
2638    double local_dval = 0.0;
2639    zend_uchar type;
2640
2641    if (!length) {
2642        return 0;
2643    }
2644
2645    if (oflow_info != NULL) {
2646        *oflow_info = 0;
2647    }
2648
2649    /* Skip any whitespace
2650     * This is much faster than the isspace() function */
2651    while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r' || *str == '\v' || *str == '\f') {
2652        str++;
2653        length--;
2654    }
2655    ptr = str;
2656
2657    if (*ptr == '-' || *ptr == '+') {
2658        ptr++;
2659    }
2660
2661    if (ZEND_IS_DIGIT(*ptr)) {
2662        /* Skip any leading 0s */
2663        while (*ptr == '0') {
2664            ptr++;
2665        }
2666
2667        /* Count the number of digits. If a decimal point/exponent is found,
2668         * it's a double. Otherwise, if there's a dval or no need to check for
2669         * a full match, stop when there are too many digits for a long */
2670        for (type = IS_LONG; !(digits >= MAX_LENGTH_OF_LONG && (dval || allow_errors == 1)); digits++, ptr++) {
2671check_digits:
2672            if (ZEND_IS_DIGIT(*ptr)) {
2673                continue;
2674            } else if (*ptr == '.' && dp_or_e < 1) {
2675                goto process_double;
2676            } else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) {
2677                const char *e = ptr + 1;
2678
2679                if (*e == '-' || *e == '+') {
2680                    ptr = e++;
2681                }
2682                if (ZEND_IS_DIGIT(*e)) {
2683                    goto process_double;
2684                }
2685            }
2686
2687            break;
2688        }
2689
2690        if (digits >= MAX_LENGTH_OF_LONG) {
2691            if (oflow_info != NULL) {
2692                *oflow_info = *str == '-' ? -1 : 1;
2693            }
2694            dp_or_e = -1;
2695            goto process_double;
2696        }
2697    } else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) {
2698process_double:
2699        type = IS_DOUBLE;
2700
2701        /* If there's a dval, do the conversion; else continue checking
2702         * the digits if we need to check for a full match */
2703        if (dval) {
2704            local_dval = zend_strtod(str, &ptr);
2705        } else if (allow_errors != 1 && dp_or_e != -1) {
2706            dp_or_e = (*ptr++ == '.') ? 1 : 2;
2707            goto check_digits;
2708        }
2709    } else {
2710        return 0;
2711    }
2712
2713    if (ptr != str + length) {
2714        if (!allow_errors) {
2715            return 0;
2716        }
2717        if (allow_errors == -1) {
2718            zend_error(E_NOTICE, "A non well formed numeric value encountered");
2719        }
2720    }
2721
2722    if (type == IS_LONG) {
2723        if (digits == MAX_LENGTH_OF_LONG - 1) {
2724            int cmp = strcmp(&ptr[-digits], long_min_digits);
2725
2726            if (!(cmp < 0 || (cmp == 0 && *str == '-'))) {
2727                if (dval) {
2728                    *dval = zend_strtod(str, NULL);
2729                }
2730                if (oflow_info != NULL) {
2731                    *oflow_info = *str == '-' ? -1 : 1;
2732                }
2733
2734                return IS_DOUBLE;
2735            }
2736        }
2737
2738        if (lval) {
2739            *lval = ZEND_STRTOL(str, NULL, 10);
2740        }
2741
2742        return IS_LONG;
2743    } else {
2744        if (dval) {
2745            *dval = local_dval;
2746        }
2747
2748        return IS_DOUBLE;
2749    }
2750}
2751/* }}} */
2752
2753/*
2754 * String matching - Sunday algorithm
2755 * http://www.iti.fh-flensburg.de/lang/algorithmen/pattern/sundayen.htm
2756 */
2757static zend_always_inline void zend_memnstr_ex_pre(unsigned int td[], const char *needle, size_t needle_len, int reverse) /* {{{ */ {
2758    int i;
2759
2760    for (i = 0; i < 256; i++) {
2761        td[i] = needle_len + 1;
2762    }
2763
2764    if (reverse) {
2765        for (i = needle_len - 1; i >= 0; i--) {
2766            td[(unsigned char)needle[i]] = i + 1;
2767        }
2768    } else {
2769        for (i = 0; i < needle_len; i++) {
2770            td[(unsigned char)needle[i]] = (int)needle_len - i;
2771        }
2772    }
2773}
2774/* }}} */
2775
2776ZEND_API const char* ZEND_FASTCALL zend_memnstr_ex(const char *haystack, const char *needle, size_t needle_len, char *end) /* {{{ */
2777{
2778    unsigned int td[256];
2779    register size_t i;
2780    register const char *p;
2781
2782    if (needle_len == 0 || (end - haystack) == 0) {
2783        return NULL;
2784    }
2785
2786    zend_memnstr_ex_pre(td, needle, needle_len, 0);
2787
2788    p = haystack;
2789    end -= needle_len;
2790
2791    while (p <= end) {
2792        for (i = 0; i < needle_len; i++) {
2793            if (needle[i] != p[i]) {
2794                break;
2795            }
2796        }
2797        if (i == needle_len) {
2798            return p;
2799        }
2800        p += td[(unsigned char)(p[needle_len])];
2801    }
2802
2803    return NULL;
2804}
2805/* }}} */
2806
2807ZEND_API const char* ZEND_FASTCALL zend_memnrstr_ex(const char *haystack, const char *needle, size_t needle_len, char *end) /* {{{ */
2808{
2809    unsigned int td[256];
2810    register size_t i;
2811    register const char *p;
2812
2813    if (needle_len == 0 || (end - haystack) == 0) {
2814        return NULL;
2815    }
2816
2817    zend_memnstr_ex_pre(td, needle, needle_len, 1);
2818
2819    p = end;
2820    p -= needle_len;
2821
2822    while (p >= haystack) {
2823        for (i = 0; i < needle_len; i++) {
2824            if (needle[i] != p[i]) {
2825                break;
2826            }
2827        }
2828
2829        if (i == needle_len) {
2830            return (const char *)p;
2831        }
2832
2833        if (UNEXPECTED(p == haystack)) {
2834            return NULL;
2835        }
2836
2837        p -= td[(unsigned char)(p[-1])];
2838    }
2839
2840    return NULL;
2841}
2842/* }}} */
2843
2844#if !ZEND_DVAL_TO_LVAL_CAST_OK
2845# if SIZEOF_ZEND_LONG == 4
2846ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d)
2847{
2848    double  two_pow_32 = pow(2., 32.),
2849            dmod;
2850
2851    dmod = fmod(d, two_pow_32);
2852    if (dmod < 0) {
2853        /* we're going to make this number positive; call ceil()
2854         * to simulate rounding towards 0 of the negative number */
2855        dmod = ceil(dmod);// + two_pow_32;
2856    }
2857    return (zend_long)(zend_ulong)dmod;
2858}
2859#else
2860ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d)
2861{
2862    double  two_pow_64 = pow(2., 64.),
2863            dmod;
2864
2865    dmod = fmod(d, two_pow_64);
2866    if (dmod < 0) {
2867        /* no need to call ceil; original double must have had no
2868         * fractional part, hence dmod does not have one either */
2869        dmod += two_pow_64;
2870    }
2871    return (zend_long)(zend_ulong)dmod;
2872}
2873#endif
2874#endif
2875
2876/*
2877 * Local variables:
2878 * tab-width: 4
2879 * c-basic-offset: 4
2880 * indent-tabs-mode: t
2881 * End:
2882 */
2883