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_FALSE(result);
1078                    return FAILURE;         /* division by zero */
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                    ZVAL_FALSE(result);
1095                    return FAILURE;         /* division by zero */
1096                }
1097                ZVAL_DOUBLE(result, Z_DVAL_P(op1) / (double)Z_LVAL_P(op2));
1098                return SUCCESS;
1099
1100            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1101                if (Z_DVAL_P(op2) == 0) {
1102                    zend_error(E_WARNING, "Division by zero");
1103                    ZVAL_FALSE(result);
1104                    return FAILURE;         /* division by zero */
1105                }
1106                ZVAL_DOUBLE(result, (double)Z_LVAL_P(op1) / Z_DVAL_P(op2));
1107                return SUCCESS;
1108
1109            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1110                if (Z_DVAL_P(op2) == 0) {
1111                    zend_error(E_WARNING, "Division by zero");
1112                    ZVAL_FALSE(result);
1113                    return FAILURE;         /* division by zero */
1114                }
1115                ZVAL_DOUBLE(result, Z_DVAL_P(op1) / Z_DVAL_P(op2));
1116                return SUCCESS;
1117
1118            default:
1119                if (Z_ISREF_P(op1)) {
1120                    op1 = Z_REFVAL_P(op1);
1121                } else if (Z_ISREF_P(op2)) {
1122                    op2 = Z_REFVAL_P(op2);
1123                } else if (!converted) {
1124                    ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV, div_function);
1125
1126                    zendi_convert_scalar_to_number(op1, op1_copy, result);
1127                    zendi_convert_scalar_to_number(op2, op2_copy, result);
1128                    converted = 1;
1129                } else {
1130                    zend_error(E_EXCEPTION | E_ERROR, "Unsupported operand types");
1131                    return FAILURE; /* unknown datatype */
1132                }
1133        }
1134    }
1135}
1136/* }}} */
1137
1138ZEND_API int ZEND_FASTCALL mod_function(zval *result, zval *op1, zval *op2) /* {{{ */
1139{
1140    zend_long op1_lval, op2_lval;
1141
1142    convert_op1_op2_long(op1, op1_lval, op2, op2_lval, ZEND_MOD, mod_function);
1143
1144    if (op1 == result) {
1145        zval_dtor(result);
1146    }
1147
1148    if (op2_lval == 0) {
1149        zend_error(E_WARNING, "Division by zero");
1150        ZVAL_FALSE(result);
1151        return FAILURE;         /* modulus by zero */
1152    }
1153
1154    if (op2_lval == -1) {
1155        /* Prevent overflow error/crash if op1==LONG_MIN */
1156        ZVAL_LONG(result, 0);
1157        return SUCCESS;
1158    }
1159
1160    ZVAL_LONG(result, op1_lval % op2_lval);
1161    return SUCCESS;
1162}
1163/* }}} */
1164
1165ZEND_API int ZEND_FASTCALL boolean_xor_function(zval *result, zval *op1, zval *op2) /* {{{ */
1166{
1167    int op1_val, op2_val;
1168
1169    do {
1170        if (Z_TYPE_P(op1) == IS_FALSE) {
1171            op1_val = 0;
1172        } else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1173            op1_val = 1;
1174        } else {
1175            if (Z_ISREF_P(op1)) {
1176                op1 = Z_REFVAL_P(op1);
1177                if (Z_TYPE_P(op1) == IS_FALSE) {
1178                    op1_val = 0;
1179                    break;
1180                } else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1181                    op1_val = 1;
1182                    break;
1183                }
1184            }
1185            ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BOOL_XOR, boolean_xor_function);
1186            op1_val = zval_is_true(op1);
1187        }
1188    } while (0);
1189    do {
1190        if (Z_TYPE_P(op2) == IS_FALSE) {
1191            op2_val = 0;
1192        } else if (EXPECTED(Z_TYPE_P(op2) == IS_TRUE)) {
1193            op2_val = 1;
1194        } else {
1195            if (Z_ISREF_P(op2)) {
1196                op2 = Z_REFVAL_P(op2);
1197                if (Z_TYPE_P(op2) == IS_FALSE) {
1198                    op2_val = 0;
1199                    break;
1200                } else if (EXPECTED(Z_TYPE_P(op2) == IS_TRUE)) {
1201                    op2_val = 1;
1202                    break;
1203                }
1204            }
1205            ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BOOL_XOR);
1206            op2_val = zval_is_true(op2);
1207        }
1208    } while (0);
1209
1210    ZVAL_BOOL(result, op1_val ^ op2_val);
1211    return SUCCESS;
1212}
1213/* }}} */
1214
1215ZEND_API int ZEND_FASTCALL boolean_not_function(zval *result, zval *op1) /* {{{ */
1216{
1217    if (Z_TYPE_P(op1) < IS_TRUE) {
1218        ZVAL_TRUE(result);
1219    } else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1220        ZVAL_FALSE(result);
1221    } else {
1222        if (Z_ISREF_P(op1)) {
1223            op1 = Z_REFVAL_P(op1);
1224            if (Z_TYPE_P(op1) < IS_TRUE) {
1225                ZVAL_TRUE(result);
1226                return SUCCESS;
1227            } else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1228                ZVAL_FALSE(result);
1229                return SUCCESS;
1230            }
1231        }
1232        ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BOOL_NOT);
1233
1234        ZVAL_BOOL(result, !zval_is_true(op1));
1235    }
1236    return SUCCESS;
1237}
1238/* }}} */
1239
1240ZEND_API int ZEND_FASTCALL bitwise_not_function(zval *result, zval *op1) /* {{{ */
1241{
1242try_again:
1243    switch (Z_TYPE_P(op1)) {
1244        case IS_LONG:
1245            ZVAL_LONG(result, ~Z_LVAL_P(op1));
1246            return SUCCESS;
1247        case IS_DOUBLE:
1248            ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1)));
1249            return SUCCESS;
1250        case IS_STRING: {
1251            size_t i;
1252
1253            ZVAL_NEW_STR(result, zend_string_alloc(Z_STRLEN_P(op1), 0));
1254            for (i = 0; i < Z_STRLEN_P(op1); i++) {
1255                Z_STRVAL_P(result)[i] = ~Z_STRVAL_P(op1)[i];
1256            }
1257            Z_STRVAL_P(result)[i] = 0;
1258            return SUCCESS;
1259        }
1260        case IS_REFERENCE:
1261            op1 = Z_REFVAL_P(op1);
1262            goto try_again;
1263        default:
1264            ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BW_NOT);
1265
1266            zend_error(E_EXCEPTION | E_ERROR, "Unsupported operand types");
1267            return FAILURE;
1268    }
1269}
1270/* }}} */
1271
1272ZEND_API int ZEND_FASTCALL bitwise_or_function(zval *result, zval *op1, zval *op2) /* {{{ */
1273{
1274    zend_long op1_lval, op2_lval;
1275
1276    if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1277        ZVAL_LONG(result, Z_LVAL_P(op1) | Z_LVAL_P(op2));
1278        return SUCCESS;
1279    }
1280
1281    ZVAL_DEREF(op1);
1282    ZVAL_DEREF(op2);
1283
1284    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1285        zval *longer, *shorter;
1286        zend_string *str;
1287        size_t i;
1288
1289        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1290            longer = op1;
1291            shorter = op2;
1292        } else {
1293            longer = op2;
1294            shorter = op1;
1295        }
1296
1297        str = zend_string_alloc(Z_STRLEN_P(longer), 0);
1298        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1299            str->val[i] = Z_STRVAL_P(longer)[i] | Z_STRVAL_P(shorter)[i];
1300        }
1301        memcpy(str->val + i, Z_STRVAL_P(longer) + i, Z_STRLEN_P(longer) - i + 1);
1302        if (result==op1) {
1303            zend_string_release(Z_STR_P(result));
1304        }
1305        ZVAL_NEW_STR(result, str);
1306        return SUCCESS;
1307    }
1308
1309    if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1310        ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_OR, bitwise_or_function);
1311        op1_lval = _zval_get_long_func(op1);
1312    } else {
1313        op1_lval = Z_LVAL_P(op1);
1314    }
1315    if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1316        ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_OR);
1317        op2_lval = _zval_get_long_func(op2);
1318    } else {
1319        op2_lval = Z_LVAL_P(op2);
1320    }
1321
1322    if (op1 == result) {
1323        zval_dtor(result);
1324    }
1325    ZVAL_LONG(result, op1_lval | op2_lval);
1326    return SUCCESS;
1327}
1328/* }}} */
1329
1330ZEND_API int ZEND_FASTCALL bitwise_and_function(zval *result, zval *op1, zval *op2) /* {{{ */
1331{
1332    zend_long op1_lval, op2_lval;
1333
1334    if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1335        ZVAL_LONG(result, Z_LVAL_P(op1) & Z_LVAL_P(op2));
1336        return SUCCESS;
1337    }
1338
1339    ZVAL_DEREF(op1);
1340    ZVAL_DEREF(op2);
1341
1342    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1343        zval *longer, *shorter;
1344        zend_string *str;
1345        size_t i;
1346
1347        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1348            longer = op1;
1349            shorter = op2;
1350        } else {
1351            longer = op2;
1352            shorter = op1;
1353        }
1354
1355        str = zend_string_alloc(Z_STRLEN_P(shorter), 0);
1356        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1357            str->val[i] = Z_STRVAL_P(shorter)[i] & Z_STRVAL_P(longer)[i];
1358        }
1359        str->val[i] = 0;
1360        if (result==op1) {
1361            zend_string_release(Z_STR_P(result));
1362        }
1363        ZVAL_NEW_STR(result, str);
1364        return SUCCESS;
1365    }
1366
1367    if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1368        ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_AND, bitwise_or_function);
1369        op1_lval = _zval_get_long_func(op1);
1370    } else {
1371        op1_lval = Z_LVAL_P(op1);
1372    }
1373    if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1374        ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_AND);
1375        op2_lval = _zval_get_long_func(op2);
1376    } else {
1377        op2_lval = Z_LVAL_P(op2);
1378    }
1379
1380    if (op1 == result) {
1381        zval_dtor(result);
1382    }
1383    ZVAL_LONG(result, op1_lval & op2_lval);
1384    return SUCCESS;
1385}
1386/* }}} */
1387
1388ZEND_API int ZEND_FASTCALL bitwise_xor_function(zval *result, zval *op1, zval *op2) /* {{{ */
1389{
1390    zend_long op1_lval, op2_lval;
1391
1392    if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1393        ZVAL_LONG(result, Z_LVAL_P(op1) ^ Z_LVAL_P(op2));
1394        return SUCCESS;
1395    }
1396
1397    ZVAL_DEREF(op1);
1398    ZVAL_DEREF(op2);
1399
1400    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1401        zval *longer, *shorter;
1402        zend_string *str;
1403        size_t i;
1404
1405        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1406            longer = op1;
1407            shorter = op2;
1408        } else {
1409            longer = op2;
1410            shorter = op1;
1411        }
1412
1413        str = zend_string_alloc(Z_STRLEN_P(shorter), 0);
1414        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1415            str->val[i] = Z_STRVAL_P(shorter)[i] ^ Z_STRVAL_P(longer)[i];
1416        }
1417        str->val[i] = 0;
1418        if (result==op1) {
1419            zend_string_release(Z_STR_P(result));
1420        }
1421        ZVAL_NEW_STR(result, str);
1422        return SUCCESS;
1423    }
1424
1425    if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1426        ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_XOR, bitwise_or_function);
1427        op1_lval = _zval_get_long_func(op1);
1428    } else {
1429        op1_lval = Z_LVAL_P(op1);
1430    }
1431    if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1432        ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_XOR);
1433        op2_lval = _zval_get_long_func(op2);
1434    } else {
1435        op2_lval = Z_LVAL_P(op2);
1436    }
1437
1438    if (op1 == result) {
1439        zval_dtor(result);
1440    }
1441    ZVAL_LONG(result, op1_lval ^ op2_lval);
1442    return SUCCESS;
1443}
1444/* }}} */
1445
1446ZEND_API int ZEND_FASTCALL shift_left_function(zval *result, zval *op1, zval *op2) /* {{{ */
1447{
1448    zend_long op1_lval, op2_lval;
1449
1450    convert_op1_op2_long(op1, op1_lval, op2, op2_lval, ZEND_SL, shift_left_function);
1451
1452    if (op1 == result) {
1453        zval_dtor(result);
1454    }
1455
1456    /* prevent wrapping quirkiness on some processors where << 64 + x == << x */
1457    if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
1458        if (EXPECTED(op2_lval > 0)) {
1459            ZVAL_LONG(result, 0);
1460            return SUCCESS;
1461        } else {
1462            zend_error(E_WARNING, "Bit shift by negative number");
1463            ZVAL_FALSE(result);
1464            return FAILURE;
1465        }
1466    }
1467
1468    ZVAL_LONG(result, op1_lval << op2_lval);
1469    return SUCCESS;
1470}
1471/* }}} */
1472
1473ZEND_API int ZEND_FASTCALL shift_right_function(zval *result, zval *op1, zval *op2) /* {{{ */
1474{
1475    zend_long op1_lval, op2_lval;
1476
1477    convert_op1_op2_long(op1, op1_lval, op2, op2_lval, ZEND_SR, shift_right_function);
1478
1479    if (op1 == result) {
1480        zval_dtor(result);
1481    }
1482
1483    /* prevent wrapping quirkiness on some processors where >> 64 + x == >> x */
1484    if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
1485        if (EXPECTED(op2_lval > 0)) {
1486            ZVAL_LONG(result, (op1_lval < 0) ? -1 : 0);
1487            return SUCCESS;
1488        } else {
1489            zend_error(E_WARNING, "Bit shift by negative number");
1490            ZVAL_FALSE(result);
1491            return FAILURE;
1492        }
1493    }
1494
1495    ZVAL_LONG(result, op1_lval >> op2_lval);
1496    return SUCCESS;
1497}
1498/* }}} */
1499
1500ZEND_API int ZEND_FASTCALL concat_function(zval *result, zval *op1, zval *op2) /* {{{ */
1501{
1502    zval op1_copy, op2_copy;
1503    int use_copy1 = 0, use_copy2 = 0;
1504
1505    do {
1506        if (UNEXPECTED(Z_TYPE_P(op1) != IS_STRING)) {
1507            if (Z_ISREF_P(op1)) {
1508                op1 = Z_REFVAL_P(op1);
1509                if (Z_TYPE_P(op1) == IS_STRING) break;
1510            }
1511            ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT, concat_function);
1512            use_copy1 = zend_make_printable_zval(op1, &op1_copy);
1513            if (use_copy1) {
1514                /* We have created a converted copy of op1. Therefore, op1 won't become the result so
1515                 * we have to free it.
1516                 */
1517                if (result == op1) {
1518                    zval_dtor(op1);
1519                    if (UNEXPECTED(op1 == op2)) {
1520                        op2 = &op1_copy;
1521                    }
1522                }
1523                op1 = &op1_copy;
1524            }
1525        }
1526    } while (0);
1527    do {
1528        if (UNEXPECTED(Z_TYPE_P(op2) != IS_STRING)) {
1529            if (Z_ISREF_P(op2)) {
1530                op2 = Z_REFVAL_P(op2);
1531                if (Z_TYPE_P(op2) == IS_STRING) break;
1532            }
1533            ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_CONCAT);
1534            use_copy2 = zend_make_printable_zval(op2, &op2_copy);
1535            if (use_copy2) {
1536                op2 = &op2_copy;
1537            }
1538        }
1539    } while (0);
1540
1541    {
1542        size_t op1_len = Z_STRLEN_P(op1);
1543        size_t op2_len = Z_STRLEN_P(op2);
1544        size_t result_len = op1_len + op2_len;
1545        zend_string *result_str;
1546
1547        if (op1_len > SIZE_MAX - op2_len) {
1548            zend_error_noreturn(E_ERROR, "String size overflow");
1549        }
1550
1551        if (result == op1 && Z_REFCOUNTED_P(result)) {
1552            /* special case, perform operations on result */
1553            result_str = zend_string_extend(Z_STR_P(result), result_len, 0);
1554        } else {
1555            result_str = zend_string_alloc(result_len, 0);
1556            memcpy(result_str->val, Z_STRVAL_P(op1), op1_len);
1557        }
1558
1559        /* This has to happen first to account for the cases where result == op1 == op2 and
1560         * the realloc is done. In this case this line will also update Z_STRVAL_P(op2) to
1561         * point to the new string. The first op2_len bytes of result will still be the same. */
1562        ZVAL_NEW_STR(result, result_str);
1563
1564        memcpy(result_str->val + op1_len, Z_STRVAL_P(op2), op2_len);
1565        result_str->val[result_len] = '\0';
1566    }
1567
1568    if (UNEXPECTED(use_copy1)) {
1569        zval_dtor(op1);
1570    }
1571    if (UNEXPECTED(use_copy2)) {
1572        zval_dtor(op2);
1573    }
1574    return SUCCESS;
1575}
1576/* }}} */
1577
1578ZEND_API int string_compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool case_insensitive) /* {{{ */
1579{
1580    zend_string *str1 = zval_get_string(op1);
1581    zend_string *str2 = zval_get_string(op2);
1582
1583    if (case_insensitive) {
1584        ZVAL_LONG(result, zend_binary_strcasecmp_l(str1->val, str1->len, str2->val, str1->len));
1585    } else {
1586        ZVAL_LONG(result, zend_binary_strcmp(str1->val, str1->len, str2->val, str2->len));
1587    }
1588
1589    zend_string_release(str1);
1590    zend_string_release(str2);
1591    return SUCCESS;
1592}
1593/* }}} */
1594
1595ZEND_API int string_compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
1596{
1597    if (EXPECTED(Z_TYPE_P(op1) == IS_STRING) &&
1598        EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
1599        if (Z_STR_P(op1) == Z_STR_P(op2)) {
1600            ZVAL_LONG(result, 0);
1601        } else {
1602            ZVAL_LONG(result, zend_binary_strcmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2)));
1603        }
1604    } else {
1605        zend_string *str1 = zval_get_string(op1);
1606        zend_string *str2 = zval_get_string(op2);
1607
1608        ZVAL_LONG(result, zend_binary_strcmp(str1->val, str1->len, str2->val, str2->len));
1609
1610        zend_string_release(str1);
1611        zend_string_release(str2);
1612    }
1613    return SUCCESS;
1614}
1615/* }}} */
1616
1617ZEND_API int string_case_compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
1618{
1619    if (EXPECTED(Z_TYPE_P(op1) == IS_STRING) &&
1620        EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
1621        if (Z_STR_P(op1) == Z_STR_P(op2)) {
1622            ZVAL_LONG(result, 0);
1623        } else {
1624            ZVAL_LONG(result, zend_binary_strcasecmp_l(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2)));
1625        }
1626    } else {
1627        zend_string *str1 = zval_get_string(op1);
1628        zend_string *str2 = zval_get_string(op2);
1629
1630        ZVAL_LONG(result, zend_binary_strcasecmp_l(str1->val, str1->len, str2->val, str1->len));
1631
1632        zend_string_release(str1);
1633        zend_string_release(str2);
1634    }
1635    return SUCCESS;
1636}
1637/* }}} */
1638
1639#if HAVE_STRCOLL
1640ZEND_API int string_locale_compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
1641{
1642    zend_string *str1 = zval_get_string(op1);
1643    zend_string *str2 = zval_get_string(op2);
1644
1645    ZVAL_LONG(result, strcoll(str1->val, str2->val));
1646
1647    zend_string_release(str1);
1648    zend_string_release(str2);
1649    return SUCCESS;
1650}
1651/* }}} */
1652#endif
1653
1654ZEND_API int numeric_compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
1655{
1656    double d1, d2;
1657
1658    d1 = zval_get_double(op1);
1659    d2 = zval_get_double(op2);
1660
1661    ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(d1 - d2));
1662
1663    return SUCCESS;
1664}
1665/* }}} */
1666
1667static inline void zend_free_obj_get_result(zval *op) /* {{{ */
1668{
1669    if (Z_REFCOUNTED_P(op)) {
1670        if (Z_REFCOUNT_P(op) == 0) {
1671            zval_dtor(op);
1672        } else {
1673            zval_ptr_dtor(op);
1674        }
1675    }
1676}
1677/* }}} */
1678
1679ZEND_API int compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
1680{
1681    int ret;
1682    int converted = 0;
1683    zval op1_copy, op2_copy;
1684    zval *op_free, tmp_free;
1685
1686    while (1) {
1687        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
1688            case TYPE_PAIR(IS_LONG, IS_LONG):
1689                ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0));
1690                return SUCCESS;
1691
1692            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1693                Z_DVAL_P(result) = Z_DVAL_P(op1) - (double)Z_LVAL_P(op2);
1694                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1695                return SUCCESS;
1696
1697            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1698                Z_DVAL_P(result) = (double)Z_LVAL_P(op1) - Z_DVAL_P(op2);
1699                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1700                return SUCCESS;
1701
1702            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1703                if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
1704                    ZVAL_LONG(result, 0);
1705                } else {
1706                    Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2);
1707                    ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1708                }
1709                return SUCCESS;
1710
1711            case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
1712                ZVAL_LONG(result, zend_compare_arrays(op1, op2));
1713                return SUCCESS;
1714
1715            case TYPE_PAIR(IS_NULL, IS_NULL):
1716            case TYPE_PAIR(IS_NULL, IS_FALSE):
1717            case TYPE_PAIR(IS_FALSE, IS_NULL):
1718            case TYPE_PAIR(IS_FALSE, IS_FALSE):
1719            case TYPE_PAIR(IS_TRUE, IS_TRUE):
1720                ZVAL_LONG(result, 0);
1721                return SUCCESS;
1722
1723            case TYPE_PAIR(IS_NULL, IS_TRUE):
1724                ZVAL_LONG(result, -1);
1725                return SUCCESS;
1726
1727            case TYPE_PAIR(IS_TRUE, IS_NULL):
1728                ZVAL_LONG(result, 1);
1729                return SUCCESS;
1730
1731            case TYPE_PAIR(IS_STRING, IS_STRING):
1732                if (Z_STR_P(op1) == Z_STR_P(op2)) {
1733                    ZVAL_LONG(result, 0);
1734                    return SUCCESS;
1735                }
1736                ZVAL_LONG(result, zendi_smart_strcmp(op1, op2));
1737                return SUCCESS;
1738
1739            case TYPE_PAIR(IS_NULL, IS_STRING):
1740                ZVAL_LONG(result, Z_STRLEN_P(op2) == 0 ? 0 : -1);
1741                return SUCCESS;
1742
1743            case TYPE_PAIR(IS_STRING, IS_NULL):
1744                ZVAL_LONG(result, Z_STRLEN_P(op1) == 0 ? 0 : 1);
1745                return SUCCESS;
1746
1747            case TYPE_PAIR(IS_OBJECT, IS_NULL):
1748                ZVAL_LONG(result, 1);
1749                return SUCCESS;
1750
1751            case TYPE_PAIR(IS_NULL, IS_OBJECT):
1752                ZVAL_LONG(result, -1);
1753                return SUCCESS;
1754
1755            default:
1756                if (Z_ISREF_P(op1)) {
1757                    op1 = Z_REFVAL_P(op1);
1758                    continue;
1759                } else if (Z_ISREF_P(op2)) {
1760                    op2 = Z_REFVAL_P(op2);
1761                    continue;
1762                }
1763
1764                if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, compare)) {
1765                    return Z_OBJ_HANDLER_P(op1, compare)(result, op1, op2);
1766                } else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, compare)) {
1767                    return Z_OBJ_HANDLER_P(op2, compare)(result, op1, op2);
1768                }
1769
1770                if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) == IS_OBJECT) {
1771                    if (Z_OBJ_P(op1) == Z_OBJ_P(op2)) {
1772                        /* object handles are identical, apparently this is the same object */
1773                        ZVAL_LONG(result, 0);
1774                        return SUCCESS;
1775                    }
1776                    if (Z_OBJ_HANDLER_P(op1, compare_objects) == Z_OBJ_HANDLER_P(op2, compare_objects)) {
1777                        ZVAL_LONG(result, Z_OBJ_HANDLER_P(op1, compare_objects)(op1, op2));
1778                        return SUCCESS;
1779                    }
1780                }
1781                if (Z_TYPE_P(op1) == IS_OBJECT) {
1782                    if (Z_OBJ_HT_P(op1)->get) {
1783                        zval rv;
1784                        op_free = Z_OBJ_HT_P(op1)->get(op1, &rv);
1785                        ret = compare_function(result, op_free, op2);
1786                        zend_free_obj_get_result(op_free);
1787                        return ret;
1788                    } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) {
1789                        ZVAL_UNDEF(&tmp_free);
1790                        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) {
1791                            ZVAL_LONG(result, 1);
1792                            zend_free_obj_get_result(&tmp_free);
1793                            return SUCCESS;
1794                        }
1795                        ret = compare_function(result, &tmp_free, op2);
1796                        zend_free_obj_get_result(&tmp_free);
1797                        return ret;
1798                    }
1799                }
1800                if (Z_TYPE_P(op2) == IS_OBJECT) {
1801                    if (Z_OBJ_HT_P(op2)->get) {
1802                        zval rv;
1803                        op_free = Z_OBJ_HT_P(op2)->get(op2, &rv);
1804                        ret = compare_function(result, op1, op_free);
1805                        zend_free_obj_get_result(op_free);
1806                        return ret;
1807                    } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) {
1808                        ZVAL_UNDEF(&tmp_free);
1809                        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) {
1810                            ZVAL_LONG(result, -1);
1811                            zend_free_obj_get_result(&tmp_free);
1812                            return SUCCESS;
1813                        }
1814                        ret = compare_function(result, op1, &tmp_free);
1815                        zend_free_obj_get_result(&tmp_free);
1816                        return ret;
1817                    } else if (Z_TYPE_P(op1) == IS_OBJECT) {
1818                        ZVAL_LONG(result, 1);
1819                        return SUCCESS;
1820                    }
1821                }
1822                if (!converted) {
1823                    if (Z_TYPE_P(op1) == IS_NULL || Z_TYPE_P(op1) == IS_FALSE) {
1824                        ZVAL_LONG(result, zval_is_true(op2) ? -1 : 0);
1825                        return SUCCESS;
1826                    } else if (Z_TYPE_P(op2) == IS_NULL || Z_TYPE_P(op2) == IS_FALSE) {
1827                        ZVAL_LONG(result, zval_is_true(op1) ? 1 : 0);
1828                        return SUCCESS;
1829                    } else if (Z_TYPE_P(op1) == IS_TRUE) {
1830                        ZVAL_LONG(result, zval_is_true(op2) ? 0 : 1);
1831                        return SUCCESS;
1832                    } else if (Z_TYPE_P(op2) == IS_TRUE) {
1833                        ZVAL_LONG(result, zval_is_true(op1) ? 0 : -1);
1834                        return SUCCESS;
1835                    } else {
1836                        zendi_convert_scalar_to_number(op1, op1_copy, result);
1837                        zendi_convert_scalar_to_number(op2, op2_copy, result);
1838                        converted = 1;
1839                    }
1840                } else if (Z_TYPE_P(op1)==IS_ARRAY) {
1841                    ZVAL_LONG(result, 1);
1842                    return SUCCESS;
1843                } else if (Z_TYPE_P(op2)==IS_ARRAY) {
1844                    ZVAL_LONG(result, -1);
1845                    return SUCCESS;
1846                } else if (Z_TYPE_P(op1)==IS_OBJECT) {
1847                    ZVAL_LONG(result, 1);
1848                    return SUCCESS;
1849                } else if (Z_TYPE_P(op2)==IS_OBJECT) {
1850                    ZVAL_LONG(result, -1);
1851                    return SUCCESS;
1852                } else {
1853                    ZVAL_LONG(result, 0);
1854                    return FAILURE;
1855                }
1856        }
1857    }
1858}
1859/* }}} */
1860
1861static int hash_zval_identical_function(zval *z1, zval *z2) /* {{{ */
1862{
1863    zval result;
1864
1865    /* is_identical_function() returns 1 in case of identity and 0 in case
1866     * of a difference;
1867     * whereas this comparison function is expected to return 0 on identity,
1868     * and non zero otherwise.
1869     */
1870    ZVAL_DEREF(z1);
1871    ZVAL_DEREF(z2);
1872    if (is_identical_function(&result, z1, z2)==FAILURE) {
1873        return 1;
1874    }
1875    return Z_TYPE(result) != IS_TRUE;
1876}
1877/* }}} */
1878
1879ZEND_API int ZEND_FASTCALL is_identical_function(zval *result, zval *op1, zval *op2) /* {{{ */
1880{
1881    if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
1882        ZVAL_FALSE(result);
1883        return SUCCESS;
1884    }
1885    switch (Z_TYPE_P(op1)) {
1886        case IS_NULL:
1887        case IS_FALSE:
1888        case IS_TRUE:
1889            ZVAL_TRUE(result);
1890            break;
1891        case IS_LONG:
1892            ZVAL_BOOL(result, Z_LVAL_P(op1) == Z_LVAL_P(op2));
1893            break;
1894        case IS_RESOURCE:
1895            ZVAL_BOOL(result, Z_RES_P(op1) == Z_RES_P(op2));
1896            break;
1897        case IS_DOUBLE:
1898            ZVAL_BOOL(result, Z_DVAL_P(op1) == Z_DVAL_P(op2));
1899            break;
1900        case IS_STRING:
1901            if (Z_STR_P(op1) == Z_STR_P(op2)) {
1902                ZVAL_TRUE(result);
1903            } else {
1904                ZVAL_BOOL(result, (Z_STRLEN_P(op1) == Z_STRLEN_P(op2))
1905                    && (!memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1))));
1906            }
1907            break;
1908        case IS_ARRAY:
1909            ZVAL_BOOL(result, Z_ARRVAL_P(op1) == Z_ARRVAL_P(op2) ||
1910                zend_hash_compare(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2), (compare_func_t) hash_zval_identical_function, 1)==0);
1911            break;
1912        case IS_OBJECT:
1913            if (Z_OBJ_HT_P(op1) == Z_OBJ_HT_P(op2)) {
1914                ZVAL_BOOL(result, Z_OBJ_P(op1) == Z_OBJ_P(op2));
1915            } else {
1916                ZVAL_FALSE(result);
1917            }
1918            break;
1919        default:
1920            ZVAL_FALSE(result);
1921            return FAILURE;
1922    }
1923    return SUCCESS;
1924}
1925/* }}} */
1926
1927ZEND_API int ZEND_FASTCALL is_not_identical_function(zval *result, zval *op1, zval *op2) /* {{{ */
1928{
1929    if (is_identical_function(result, op1, op2) == FAILURE) {
1930        return FAILURE;
1931    }
1932    ZVAL_BOOL(result, Z_TYPE_P(result) != IS_TRUE);
1933    return SUCCESS;
1934}
1935/* }}} */
1936
1937ZEND_API int ZEND_FASTCALL is_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
1938{
1939    if (compare_function(result, op1, op2) == FAILURE) {
1940        return FAILURE;
1941    }
1942    ZVAL_BOOL(result, (Z_LVAL_P(result) == 0));
1943    return SUCCESS;
1944}
1945/* }}} */
1946
1947ZEND_API int ZEND_FASTCALL is_not_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
1948{
1949    if (compare_function(result, op1, op2) == FAILURE) {
1950        return FAILURE;
1951    }
1952    ZVAL_BOOL(result, (Z_LVAL_P(result) != 0));
1953    return SUCCESS;
1954}
1955/* }}} */
1956
1957ZEND_API int ZEND_FASTCALL is_smaller_function(zval *result, zval *op1, zval *op2) /* {{{ */
1958{
1959    if (compare_function(result, op1, op2) == FAILURE) {
1960        return FAILURE;
1961    }
1962    ZVAL_BOOL(result, (Z_LVAL_P(result) < 0));
1963    return SUCCESS;
1964}
1965/* }}} */
1966
1967ZEND_API int ZEND_FASTCALL is_smaller_or_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
1968{
1969    if (compare_function(result, op1, op2) == FAILURE) {
1970        return FAILURE;
1971    }
1972    ZVAL_BOOL(result, (Z_LVAL_P(result) <= 0));
1973    return SUCCESS;
1974}
1975/* }}} */
1976
1977static zend_bool ZEND_FASTCALL instanceof_interface_only(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
1978{
1979    uint32_t i;
1980
1981    for (i = 0; i < instance_ce->num_interfaces; i++) {
1982        if (instanceof_interface_only(instance_ce->interfaces[i], ce)) {
1983            return 1;
1984        }
1985    }
1986    return 0;
1987}
1988/* }}} */
1989
1990static zend_always_inline zend_bool instanceof_class(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
1991{
1992    while (instance_ce) {
1993        if (instance_ce == ce) {
1994            return 1;
1995        }
1996        instance_ce = instance_ce->parent;
1997    }
1998    return 0;
1999}
2000/* }}} */
2001
2002static zend_bool ZEND_FASTCALL instanceof_interface(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
2003{
2004    uint32_t i;
2005
2006    for (i = 0; i < instance_ce->num_interfaces; i++) {
2007        if (instanceof_interface(instance_ce->interfaces[i], ce)) {
2008            return 1;
2009        }
2010    }
2011    return instanceof_class(instance_ce, ce);
2012}
2013/* }}} */
2014
2015ZEND_API zend_bool ZEND_FASTCALL instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool interfaces_only) /* {{{ */
2016{
2017    if (ce->ce_flags & ZEND_ACC_INTERFACE) {
2018        if (!interfaces_only) {
2019            if (instanceof_interface_only(instance_ce, ce)) {
2020                return 1;
2021            }
2022        } else {
2023            return instanceof_interface(instance_ce, ce);
2024        }
2025    }
2026    if (!interfaces_only) {
2027        return instanceof_class(instance_ce, ce);
2028    }
2029    return 0;
2030}
2031/* }}} */
2032
2033ZEND_API zend_bool ZEND_FASTCALL instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
2034{
2035    if (ce->ce_flags & ZEND_ACC_INTERFACE) {
2036        return instanceof_interface(instance_ce, ce);
2037    } else {
2038        return instanceof_class(instance_ce, ce);
2039    }
2040}
2041/* }}} */
2042
2043#define LOWER_CASE 1
2044#define UPPER_CASE 2
2045#define NUMERIC 3
2046
2047static void ZEND_FASTCALL increment_string(zval *str) /* {{{ */
2048{
2049    int carry=0;
2050    size_t pos=Z_STRLEN_P(str)-1;
2051    char *s;
2052    zend_string *t;
2053    int last=0; /* Shut up the compiler warning */
2054    int ch;
2055
2056    if (Z_STRLEN_P(str) == 0) {
2057        zend_string_release(Z_STR_P(str));
2058        Z_STR_P(str) = zend_string_init("1", sizeof("1")-1, 0);
2059        Z_TYPE_INFO_P(str) = IS_STRING_EX;
2060        return;
2061    }
2062
2063    if (!Z_REFCOUNTED_P(str)) {
2064        Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
2065        Z_TYPE_INFO_P(str) = IS_STRING_EX;
2066    } else if (Z_REFCOUNT_P(str) > 1) {
2067        Z_DELREF_P(str);
2068        Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
2069    } else {
2070        zend_string_forget_hash_val(Z_STR_P(str));
2071    }
2072    s = Z_STRVAL_P(str);
2073
2074    do {
2075        ch = s[pos];
2076        if (ch >= 'a' && ch <= 'z') {
2077            if (ch == 'z') {
2078                s[pos] = 'a';
2079                carry=1;
2080            } else {
2081                s[pos]++;
2082                carry=0;
2083            }
2084            last=LOWER_CASE;
2085        } else 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=UPPER_CASE;
2094        } else if (ch >= '0' && ch <= '9') {
2095            if (ch == '9') {
2096                s[pos] = '0';
2097                carry=1;
2098            } else {
2099                s[pos]++;
2100                carry=0;
2101            }
2102            last = NUMERIC;
2103        } else {
2104            carry=0;
2105            break;
2106        }
2107        if (carry == 0) {
2108            break;
2109        }
2110    } while (pos-- > 0);
2111
2112    if (carry) {
2113        t = zend_string_alloc(Z_STRLEN_P(str)+1, 0);
2114        memcpy(t->val + 1, Z_STRVAL_P(str), Z_STRLEN_P(str));
2115        t->val[Z_STRLEN_P(str) + 1] = '\0';
2116        switch (last) {
2117            case NUMERIC:
2118                t->val[0] = '1';
2119                break;
2120            case UPPER_CASE:
2121                t->val[0] = 'A';
2122                break;
2123            case LOWER_CASE:
2124                t->val[0] = 'a';
2125                break;
2126        }
2127        zend_string_free(Z_STR_P(str));
2128        ZVAL_NEW_STR(str, t);
2129    }
2130}
2131/* }}} */
2132
2133ZEND_API int ZEND_FASTCALL increment_function(zval *op1) /* {{{ */
2134{
2135try_again:
2136    switch (Z_TYPE_P(op1)) {
2137        case IS_LONG:
2138            fast_long_increment_function(op1);
2139            break;
2140        case IS_DOUBLE:
2141            Z_DVAL_P(op1) = Z_DVAL_P(op1) + 1;
2142            break;
2143        case IS_NULL:
2144            ZVAL_LONG(op1, 1);
2145            break;
2146        case IS_STRING: {
2147                zend_long lval;
2148                double dval;
2149
2150                switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
2151                    case IS_LONG:
2152                        zend_string_release(Z_STR_P(op1));
2153                        if (lval == ZEND_LONG_MAX) {
2154                            /* switch to double */
2155                            double d = (double)lval;
2156                            ZVAL_DOUBLE(op1, d+1);
2157                        } else {
2158                            ZVAL_LONG(op1, lval+1);
2159                        }
2160                        break;
2161                    case IS_DOUBLE:
2162                        zend_string_release(Z_STR_P(op1));
2163                        ZVAL_DOUBLE(op1, dval+1);
2164                        break;
2165                    default:
2166                        /* Perl style string increment */
2167                        increment_string(op1);
2168                        break;
2169                }
2170            }
2171            break;
2172        case IS_OBJECT:
2173            if (Z_OBJ_HANDLER_P(op1, get)
2174               && Z_OBJ_HANDLER_P(op1, set)) {
2175                /* proxy object */
2176                zval rv;
2177                zval *val;
2178
2179                val = Z_OBJ_HANDLER_P(op1, get)(op1, &rv);
2180                Z_ADDREF_P(val);
2181                increment_function(val);
2182                Z_OBJ_HANDLER_P(op1, set)(op1, val);
2183                zval_ptr_dtor(val);
2184            } else if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2185                zval op2;
2186                int res;
2187
2188                ZVAL_LONG(&op2, 1);
2189                res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_ADD, op1, op1, &op2);
2190                zval_ptr_dtor(&op2);
2191
2192                return res;
2193            }
2194            return FAILURE;
2195        case IS_REFERENCE:
2196            op1 = Z_REFVAL_P(op1);
2197            goto try_again;
2198        default:
2199            return FAILURE;
2200    }
2201    return SUCCESS;
2202}
2203/* }}} */
2204
2205ZEND_API int ZEND_FASTCALL decrement_function(zval *op1) /* {{{ */
2206{
2207    zend_long lval;
2208    double dval;
2209
2210try_again:
2211    switch (Z_TYPE_P(op1)) {
2212        case IS_LONG:
2213            fast_long_decrement_function(op1);
2214            break;
2215        case IS_DOUBLE:
2216            Z_DVAL_P(op1) = Z_DVAL_P(op1) - 1;
2217            break;
2218        case IS_STRING:     /* Like perl we only support string increment */
2219            if (Z_STRLEN_P(op1) == 0) { /* consider as 0 */
2220                zend_string_release(Z_STR_P(op1));
2221                ZVAL_LONG(op1, -1);
2222                break;
2223            }
2224            switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
2225                case IS_LONG:
2226                    zend_string_release(Z_STR_P(op1));
2227                    if (lval == ZEND_LONG_MIN) {
2228                        double d = (double)lval;
2229                        ZVAL_DOUBLE(op1, d-1);
2230                    } else {
2231                        ZVAL_LONG(op1, lval-1);
2232                    }
2233                    break;
2234                case IS_DOUBLE:
2235                    zend_string_release(Z_STR_P(op1));
2236                    ZVAL_DOUBLE(op1, dval - 1);
2237                    break;
2238            }
2239            break;
2240        case IS_OBJECT:
2241            if (Z_OBJ_HANDLER_P(op1, get)
2242               && Z_OBJ_HANDLER_P(op1, set)) {
2243                /* proxy object */
2244                zval rv;
2245                zval *val;
2246
2247                val = Z_OBJ_HANDLER_P(op1, get)(op1, &rv);
2248                Z_ADDREF_P(val);
2249                decrement_function(val);
2250                Z_OBJ_HANDLER_P(op1, set)(op1, val);
2251                zval_ptr_dtor(val);
2252            } else if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2253                zval op2;
2254                int res;
2255
2256                ZVAL_LONG(&op2, 1);
2257                res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_SUB, op1, op1, &op2);
2258                zval_ptr_dtor(&op2);
2259
2260                return res;
2261            }
2262            return FAILURE;
2263        case IS_REFERENCE:
2264            op1 = Z_REFVAL_P(op1);
2265            goto try_again;
2266        default:
2267            return FAILURE;
2268    }
2269
2270    return SUCCESS;
2271}
2272/* }}} */
2273
2274ZEND_API int ZEND_FASTCALL zend_is_true(zval *op) /* {{{ */
2275{
2276    return i_zend_is_true(op);
2277}
2278/* }}} */
2279
2280ZEND_API int ZEND_FASTCALL zend_object_is_true(zval *op) /* {{{ */
2281{
2282    if (Z_OBJ_HT_P(op)->cast_object) {
2283        zval tmp;
2284        if (Z_OBJ_HT_P(op)->cast_object(op, &tmp, _IS_BOOL) == SUCCESS) {
2285            return Z_TYPE(tmp) == IS_TRUE;
2286        }
2287        zend_error(E_RECOVERABLE_ERROR, "Object of class %s could not be converted to boolean", Z_OBJ_P(op)->ce->name->val);
2288    } else if (Z_OBJ_HT_P(op)->get) {
2289        int result;
2290        zval rv;
2291        zval *tmp = Z_OBJ_HT_P(op)->get(op, &rv);
2292
2293        if (Z_TYPE_P(tmp) != IS_OBJECT) {
2294            /* for safety - avoid loop */
2295            result = i_zend_is_true(tmp);
2296            zval_ptr_dtor(tmp);
2297            return result;
2298        }
2299    }
2300    return 1;
2301}
2302/* }}} */
2303
2304#ifdef ZEND_USE_TOLOWER_L
2305ZEND_API void zend_update_current_locale(void) /* {{{ */
2306{
2307    current_locale = _get_current_locale();
2308}
2309/* }}} */
2310#endif
2311
2312ZEND_API char* ZEND_FASTCALL zend_str_tolower_copy(char *dest, const char *source, size_t length) /* {{{ */
2313{
2314    register unsigned char *str = (unsigned char*)source;
2315    register unsigned char *result = (unsigned char*)dest;
2316    register unsigned char *end = str + length;
2317
2318    while (str < end) {
2319        *result++ = zend_tolower_ascii(*str++);
2320    }
2321    *result = '\0';
2322
2323    return dest;
2324}
2325/* }}} */
2326
2327ZEND_API char* ZEND_FASTCALL zend_str_tolower_dup(const char *source, size_t length) /* {{{ */
2328{
2329    return zend_str_tolower_copy((char *)emalloc(length+1), source, length);
2330}
2331/* }}} */
2332
2333ZEND_API void ZEND_FASTCALL zend_str_tolower(char *str, size_t length) /* {{{ */
2334{
2335    register unsigned char *p = (unsigned char*)str;
2336    register unsigned char *end = p + length;
2337
2338    while (p < end) {
2339        *p = zend_tolower_ascii(*p);
2340        p++;
2341    }
2342}
2343/* }}} */
2344
2345ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower(zend_string *str) /* {{{ */
2346{
2347    register unsigned char *p = (unsigned char*)str->val;
2348    register unsigned char *end = p + str->len;
2349
2350    while (p < end) {
2351        if (*p != zend_tolower_ascii(*p)) {
2352            zend_string *res = zend_string_alloc(str->len, 0);
2353            register unsigned char *r;
2354
2355            if (p != (unsigned char*)str->val) {
2356                memcpy(res->val, str->val, p - (unsigned char*)str->val);
2357            }
2358            r = p + (res->val - str->val);
2359            while (p < end) {
2360                *r = zend_tolower_ascii(*p);
2361                p++;
2362                r++;
2363            }
2364            *r = '\0';
2365            return res;
2366        }
2367        p++;
2368    }
2369    return zend_string_copy(str);
2370}
2371/* }}} */
2372
2373ZEND_API int ZEND_FASTCALL zend_binary_strcmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
2374{
2375    int retval;
2376
2377    if (s1 == s2) {
2378        return 0;
2379    }
2380    retval = memcmp(s1, s2, MIN(len1, len2));
2381    if (!retval) {
2382        return (int)(len1 - len2);
2383    } else {
2384        return retval;
2385    }
2386}
2387/* }}} */
2388
2389ZEND_API int ZEND_FASTCALL zend_binary_strncmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
2390{
2391    int retval;
2392
2393    if (s1 == s2) {
2394        return 0;
2395    }
2396    retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
2397    if (!retval) {
2398        return (int)(MIN(length, len1) - MIN(length, len2));
2399    } else {
2400        return retval;
2401    }
2402}
2403/* }}} */
2404
2405ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
2406{
2407    size_t len;
2408    int c1, c2;
2409
2410    if (s1 == s2) {
2411        return 0;
2412    }
2413
2414    len = MIN(len1, len2);
2415    while (len--) {
2416        c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2417        c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2418        if (c1 != c2) {
2419            return c1 - c2;
2420        }
2421    }
2422
2423    return (int)(len1 - len2);
2424}
2425/* }}} */
2426
2427ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
2428{
2429    size_t len;
2430    int c1, c2;
2431
2432    if (s1 == s2) {
2433        return 0;
2434    }
2435    len = MIN(length, MIN(len1, len2));
2436    while (len--) {
2437        c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2438        c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2439        if (c1 != c2) {
2440            return c1 - c2;
2441        }
2442    }
2443
2444    return (int)(MIN(length, len1) - MIN(length, len2));
2445}
2446/* }}} */
2447
2448ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
2449{
2450    size_t len;
2451    int c1, c2;
2452
2453    if (s1 == s2) {
2454        return 0;
2455    }
2456
2457    len = MIN(len1, len2);
2458    while (len--) {
2459        c1 = zend_tolower((int)*(unsigned char *)s1++);
2460        c2 = zend_tolower((int)*(unsigned char *)s2++);
2461        if (c1 != c2) {
2462            return c1 - c2;
2463        }
2464    }
2465
2466    return (int)(len1 - len2);
2467}
2468/* }}} */
2469
2470ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
2471{
2472    size_t len;
2473    int c1, c2;
2474
2475    if (s1 == s2) {
2476        return 0;
2477    }
2478    len = MIN(length, MIN(len1, len2));
2479    while (len--) {
2480        c1 = zend_tolower((int)*(unsigned char *)s1++);
2481        c2 = zend_tolower((int)*(unsigned char *)s2++);
2482        if (c1 != c2) {
2483            return c1 - c2;
2484        }
2485    }
2486
2487    return (int)(MIN(length, len1) - MIN(length, len2));
2488}
2489/* }}} */
2490
2491ZEND_API int ZEND_FASTCALL zend_binary_zval_strcmp(zval *s1, zval *s2) /* {{{ */
2492{
2493    return zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2494}
2495/* }}} */
2496
2497ZEND_API int ZEND_FASTCALL zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2498{
2499    return zend_binary_strncmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
2500}
2501/* }}} */
2502
2503ZEND_API int ZEND_FASTCALL zend_binary_zval_strcasecmp(zval *s1, zval *s2) /* {{{ */
2504{
2505    return zend_binary_strcasecmp_l(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2506}
2507/* }}} */
2508
2509ZEND_API int ZEND_FASTCALL zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2510{
2511    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));
2512}
2513/* }}} */
2514
2515ZEND_API zend_long ZEND_FASTCALL zendi_smart_strcmp(zval *s1, zval *s2) /* {{{ */
2516{
2517    int ret1, ret2;
2518    int oflow1, oflow2;
2519    zend_long lval1 = 0, lval2 = 0;
2520    double dval1 = 0.0, dval2 = 0.0;
2521
2522    if ((ret1 = is_numeric_string_ex(Z_STRVAL_P(s1), Z_STRLEN_P(s1), &lval1, &dval1, 0, &oflow1)) &&
2523        (ret2 = is_numeric_string_ex(Z_STRVAL_P(s2), Z_STRLEN_P(s2), &lval2, &dval2, 0, &oflow2))) {
2524#if ZEND_ULONG_MAX == 0xFFFFFFFF
2525        if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
2526            ((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
2527            || (oflow1 == -1 && dval1 < -9007199254740991.))) {
2528#else
2529        if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
2530#endif
2531            /* both values are integers overflown to the same side, and the
2532             * double comparison may have resulted in crucial accuracy lost */
2533            goto string_cmp;
2534        }
2535        if ((ret1 == IS_DOUBLE) || (ret2 == IS_DOUBLE)) {
2536            if (ret1 != IS_DOUBLE) {
2537                if (oflow2) {
2538                    /* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
2539                    return -1 * oflow2;
2540                }
2541                dval1 = (double) lval1;
2542            } else if (ret2 != IS_DOUBLE) {
2543                if (oflow1) {
2544                    return oflow1;
2545                }
2546                dval2 = (double) lval2;
2547            } else if (dval1 == dval2 && !zend_finite(dval1)) {
2548                /* Both values overflowed and have the same sign,
2549                 * so a numeric comparison would be inaccurate */
2550                goto string_cmp;
2551            }
2552            dval1 = dval1 - dval2;
2553            return ZEND_NORMALIZE_BOOL(dval1);
2554        } else { /* they both have to be long's */
2555            return lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0);
2556        }
2557    } else {
2558        int strcmp_ret;
2559string_cmp:
2560        strcmp_ret = zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2561        return ZEND_NORMALIZE_BOOL(strcmp_ret);
2562    }
2563}
2564/* }}} */
2565
2566static int hash_zval_compare_function(zval *z1, zval *z2) /* {{{ */
2567{
2568    zval result;
2569
2570    if (compare_function(&result, z1, z2)==FAILURE) {
2571        return 1;
2572    }
2573    return Z_LVAL(result);
2574}
2575/* }}} */
2576
2577ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable *ht2) /* {{{ */
2578{
2579    return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0);
2580}
2581/* }}} */
2582
2583ZEND_API int ZEND_FASTCALL zend_compare_arrays(zval *a1, zval *a2) /* {{{ */
2584{
2585    return zend_compare_symbol_tables(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2));
2586}
2587/* }}} */
2588
2589ZEND_API int ZEND_FASTCALL zend_compare_objects(zval *o1, zval *o2) /* {{{ */
2590{
2591    if (Z_OBJ_P(o1) == Z_OBJ_P(o2)) {
2592        return 0;
2593    }
2594
2595    if (Z_OBJ_HT_P(o1)->compare_objects == NULL) {
2596        return 1;
2597    } else {
2598        return Z_OBJ_HT_P(o1)->compare_objects(o1, o2);
2599    }
2600}
2601/* }}} */
2602
2603ZEND_API void ZEND_FASTCALL zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) /* {{{ */
2604{
2605    zend_string *str;
2606
2607    str = zend_strpprintf(0, "%.*G", (int) EG(precision), (double)Z_DVAL_P(op));
2608    ZVAL_NEW_STR(op, str);
2609}
2610/* }}} */
2611
2612ZEND_API zend_string* ZEND_FASTCALL zend_long_to_str(zend_long num) /* {{{ */
2613{
2614    char buf[MAX_LENGTH_OF_LONG + 1];
2615    char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, num);
2616    return zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
2617}
2618/* }}} */
2619
2620ZEND_API zend_uchar ZEND_FASTCALL is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval) /* {{{ */ {
2621    return is_numeric_string_ex(str->val, str->len, lval, dval, -1, NULL);
2622}
2623/* }}} */
2624
2625ZEND_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) /* {{{ */
2626{
2627    const char *ptr;
2628    int digits = 0, dp_or_e = 0;
2629    double local_dval = 0.0;
2630    zend_uchar type;
2631
2632    if (!length) {
2633        return 0;
2634    }
2635
2636    if (oflow_info != NULL) {
2637        *oflow_info = 0;
2638    }
2639
2640    /* Skip any whitespace
2641     * This is much faster than the isspace() function */
2642    while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r' || *str == '\v' || *str == '\f') {
2643        str++;
2644        length--;
2645    }
2646    ptr = str;
2647
2648    if (*ptr == '-' || *ptr == '+') {
2649        ptr++;
2650    }
2651
2652    if (ZEND_IS_DIGIT(*ptr)) {
2653        /* Skip any leading 0s */
2654        while (*ptr == '0') {
2655            ptr++;
2656        }
2657
2658        /* Count the number of digits. If a decimal point/exponent is found,
2659         * it's a double. Otherwise, if there's a dval or no need to check for
2660         * a full match, stop when there are too many digits for a long */
2661        for (type = IS_LONG; !(digits >= MAX_LENGTH_OF_LONG && (dval || allow_errors == 1)); digits++, ptr++) {
2662check_digits:
2663            if (ZEND_IS_DIGIT(*ptr)) {
2664                continue;
2665            } else if (*ptr == '.' && dp_or_e < 1) {
2666                goto process_double;
2667            } else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) {
2668                const char *e = ptr + 1;
2669
2670                if (*e == '-' || *e == '+') {
2671                    ptr = e++;
2672                }
2673                if (ZEND_IS_DIGIT(*e)) {
2674                    goto process_double;
2675                }
2676            }
2677
2678            break;
2679        }
2680
2681        if (digits >= MAX_LENGTH_OF_LONG) {
2682            if (oflow_info != NULL) {
2683                *oflow_info = *str == '-' ? -1 : 1;
2684            }
2685            dp_or_e = -1;
2686            goto process_double;
2687        }
2688    } else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) {
2689process_double:
2690        type = IS_DOUBLE;
2691
2692        /* If there's a dval, do the conversion; else continue checking
2693         * the digits if we need to check for a full match */
2694        if (dval) {
2695            local_dval = zend_strtod(str, &ptr);
2696        } else if (allow_errors != 1 && dp_or_e != -1) {
2697            dp_or_e = (*ptr++ == '.') ? 1 : 2;
2698            goto check_digits;
2699        }
2700    } else {
2701        return 0;
2702    }
2703
2704    if (ptr != str + length) {
2705        if (!allow_errors) {
2706            return 0;
2707        }
2708        if (allow_errors == -1) {
2709            zend_error(E_NOTICE, "A non well formed numeric value encountered");
2710        }
2711    }
2712
2713    if (type == IS_LONG) {
2714        if (digits == MAX_LENGTH_OF_LONG - 1) {
2715            int cmp = strcmp(&ptr[-digits], long_min_digits);
2716
2717            if (!(cmp < 0 || (cmp == 0 && *str == '-'))) {
2718                if (dval) {
2719                    *dval = zend_strtod(str, NULL);
2720                }
2721                if (oflow_info != NULL) {
2722                    *oflow_info = *str == '-' ? -1 : 1;
2723                }
2724
2725                return IS_DOUBLE;
2726            }
2727        }
2728
2729        if (lval) {
2730            *lval = ZEND_STRTOL(str, NULL, 10);
2731        }
2732
2733        return IS_LONG;
2734    } else {
2735        if (dval) {
2736            *dval = local_dval;
2737        }
2738
2739        return IS_DOUBLE;
2740    }
2741}
2742/* }}} */
2743
2744/*
2745 * String matching - Sunday algorithm
2746 * http://www.iti.fh-flensburg.de/lang/algorithmen/pattern/sundayen.htm
2747 */
2748static zend_always_inline void zend_memnstr_ex_pre(unsigned int td[], const char *needle, size_t needle_len, int reverse) /* {{{ */ {
2749    int i;
2750
2751    for (i = 0; i < 256; i++) {
2752        td[i] = needle_len + 1;
2753    }
2754
2755    if (reverse) {
2756        for (i = needle_len - 1; i >= 0; i--) {
2757            td[(unsigned char)needle[i]] = i + 1;
2758        }
2759    } else {
2760        for (i = 0; i < needle_len; i++) {
2761            td[(unsigned char)needle[i]] = (int)needle_len - i;
2762        }
2763    }
2764}
2765/* }}} */
2766
2767ZEND_API const char* ZEND_FASTCALL zend_memnstr_ex(const char *haystack, const char *needle, size_t needle_len, char *end) /* {{{ */
2768{
2769    unsigned int td[256];
2770    register size_t i;
2771    register const char *p;
2772
2773    if (needle_len == 0 || (end - haystack) == 0) {
2774        return NULL;
2775    }
2776
2777    zend_memnstr_ex_pre(td, needle, needle_len, 0);
2778
2779    p = haystack;
2780    end -= needle_len;
2781
2782    while (p <= end) {
2783        for (i = 0; i < needle_len; i++) {
2784            if (needle[i] != p[i]) {
2785                break;
2786            }
2787        }
2788        if (i == needle_len) {
2789            return p;
2790        }
2791        p += td[(unsigned char)(p[needle_len])];
2792    }
2793
2794    return NULL;
2795}
2796/* }}} */
2797
2798ZEND_API const char* ZEND_FASTCALL zend_memnrstr_ex(const char *haystack, const char *needle, size_t needle_len, char *end) /* {{{ */
2799{
2800    unsigned int td[256];
2801    register size_t i;
2802    register const char *p;
2803
2804    if (needle_len == 0 || (end - haystack) == 0) {
2805        return NULL;
2806    }
2807
2808    zend_memnstr_ex_pre(td, needle, needle_len, 1);
2809
2810    p = end;
2811    p -= needle_len;
2812
2813    while (p >= haystack) {
2814        for (i = 0; i < needle_len; i++) {
2815            if (needle[i] != p[i]) {
2816                break;
2817            }
2818        }
2819
2820        if (i == needle_len) {
2821            return (const char *)p;
2822        }
2823
2824        if (UNEXPECTED(p == haystack)) {
2825            return NULL;
2826        }
2827
2828        p -= td[(unsigned char)(p[-1])];
2829    }
2830
2831    return NULL;
2832}
2833/* }}} */
2834
2835#if !ZEND_DVAL_TO_LVAL_CAST_OK
2836# if SIZEOF_ZEND_LONG == 4
2837ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d)
2838{
2839    double  two_pow_32 = pow(2., 32.),
2840            dmod;
2841
2842    dmod = fmod(d, two_pow_32);
2843    if (dmod < 0) {
2844        /* we're going to make this number positive; call ceil()
2845         * to simulate rounding towards 0 of the negative number */
2846        dmod = ceil(dmod);// + two_pow_32;
2847    }
2848    return (zend_long)(zend_ulong)dmod;
2849}
2850#else
2851ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d)
2852{
2853    double  two_pow_64 = pow(2., 64.),
2854            dmod;
2855
2856    dmod = fmod(d, two_pow_64);
2857    if (dmod < 0) {
2858        /* no need to call ceil; original double must have had no
2859         * fractional part, hence dmod does not have one either */
2860        dmod += two_pow_64;
2861    }
2862    return (zend_long)(zend_ulong)dmod;
2863}
2864#endif
2865#endif
2866
2867/*
2868 * Local variables:
2869 * tab-width: 4
2870 * c-basic-offset: 4
2871 * indent-tabs-mode: t
2872 * End:
2873 */
2874