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