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