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