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