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