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