1/*
2   +----------------------------------------------------------------------+
3   | Zend Engine                                                          |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1998-2015 Zend Technologies Ltd. (http://www.zend.com) |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 2.00 of the Zend license,     |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.zend.com/license/2_00.txt.                                |
11   | If you did not receive a copy of the Zend license and are unable to  |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@zend.com so we can mail you a copy immediately.              |
14   +----------------------------------------------------------------------+
15   | Authors: Andi Gutmans <andi@zend.com>                                |
16   |          Zeev Suraski <zeev@zend.com>                                |
17   +----------------------------------------------------------------------+
18*/
19
20/* $Id$ */
21
22#include <ctype.h>
23
24#include "zend.h"
25#include "zend_operators.h"
26#include "zend_variables.h"
27#include "zend_globals.h"
28#include "zend_list.h"
29#include "zend_API.h"
30#include "zend_strtod.h"
31#include "zend_exceptions.h"
32#include "zend_closures.h"
33
34#if ZEND_USE_TOLOWER_L
35#include <locale.h>
36static _locale_t current_locale = NULL;
37/* this is true global! may lead to strange effects on ZTS, but so may setlocale() */
38#define zend_tolower(c) _tolower_l(c, current_locale)
39#else
40#define zend_tolower(c) tolower(c)
41#endif
42
43#define TYPE_PAIR(t1,t2) (((t1) << 4) | (t2))
44
45static const unsigned char tolower_map[256] = {
460x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
470x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
480x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
490x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
500x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
510x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x5b,0x5c,0x5d,0x5e,0x5f,
520x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
530x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
540x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
550x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
560xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
570xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
580xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
590xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
600xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
610xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
62};
63
64#define zend_tolower_ascii(c) (tolower_map[(unsigned char)(c)])
65
66/**
67 * Functions using locale lowercase:
68        zend_binary_strncasecmp_l
69        zend_binary_strcasecmp_l
70        zend_binary_zval_strcasecmp
71        zend_binary_zval_strncasecmp
72        string_compare_function_ex
73        string_case_compare_function
74 * Functions using ascii lowercase:
75        zend_str_tolower_copy
76        zend_str_tolower_dup
77        zend_str_tolower
78        zend_binary_strcasecmp
79        zend_binary_strncasecmp
80 */
81
82ZEND_API int zend_atoi(const char *str, int str_len) /* {{{ */
83{
84    int retval;
85
86    if (!str_len) {
87        str_len = strlen(str);
88    }
89    retval = 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 long zend_atol(const char *str, int str_len) /* {{{ */
111{
112    long retval;
113
114    if (!str_len) {
115        str_len = strlen(str);
116    }
117    retval = strtol(str, NULL, 0);
118    if (str_len>0) {
119        switch (str[str_len-1]) {
120            case 'g':
121            case 'G':
122                retval *= 1024;
123                /* break intentionally missing */
124            case 'm':
125            case 'M':
126                retval *= 1024;
127                /* break intentionally missing */
128            case 'k':
129            case 'K':
130                retval *= 1024;
131                break;
132        }
133    }
134    return retval;
135}
136/* }}} */
137
138ZEND_API double zend_string_to_double(const char *number, zend_uint length) /* {{{ */
139{
140    double divisor = 10.0;
141    double result = 0.0;
142    double exponent;
143    const char *end = number+length;
144    const char *digit = number;
145
146    if (!length) {
147        return result;
148    }
149
150    while (digit < end) {
151        if ((*digit <= '9' && *digit >= '0')) {
152            result *= 10;
153            result += *digit - '0';
154        } else if (*digit == '.') {
155            digit++;
156            break;
157        } else if (toupper(*digit) == 'E') {
158            exponent = (double) atoi(digit+1);
159            result *= pow(10.0, exponent);
160            return result;
161        } else {
162            return result;
163        }
164        digit++;
165    }
166
167    while (digit < end) {
168        if ((*digit <= '9' && *digit >= '0')) {
169            result += (*digit - '0') / divisor;
170            divisor *= 10;
171        } else if (toupper(*digit) == 'E') {
172            exponent = (double) atoi(digit+1);
173            result *= pow(10.0, exponent);
174            return result;
175        } else {
176            return result;
177        }
178        digit++;
179    }
180    return result;
181}
182/* }}} */
183
184ZEND_API void convert_scalar_to_number(zval *op TSRMLS_DC) /* {{{ */
185{
186    switch (Z_TYPE_P(op)) {
187        case IS_STRING:
188            {
189                char *strval;
190
191                strval = Z_STRVAL_P(op);
192                if ((Z_TYPE_P(op)=is_numeric_string(strval, Z_STRLEN_P(op), &Z_LVAL_P(op), &Z_DVAL_P(op), 1)) == 0) {
193                    ZVAL_LONG(op, 0);
194                }
195                str_efree(strval);
196                break;
197            }
198        case IS_BOOL:
199            Z_TYPE_P(op) = IS_LONG;
200            break;
201        case IS_RESOURCE:
202            zend_list_delete(Z_LVAL_P(op));
203            Z_TYPE_P(op) = IS_LONG;
204            break;
205        case IS_OBJECT:
206            convert_to_long_base(op, 10);
207            break;
208        case IS_NULL:
209            ZVAL_LONG(op, 0);
210            break;
211    }
212}
213/* }}} */
214
215/* {{{ zendi_convert_scalar_to_number */
216#define zendi_convert_scalar_to_number(op, holder, result)          \
217    if (op==result) {                                               \
218        if (Z_TYPE_P(op) != IS_LONG) {                              \
219            convert_scalar_to_number(op TSRMLS_CC);                 \
220        }                                                           \
221    } else {                                                        \
222        switch (Z_TYPE_P(op)) {                                     \
223            case IS_STRING:                                         \
224                {                                                   \
225                    if ((Z_TYPE(holder)=is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &Z_LVAL(holder), &Z_DVAL(holder), 1)) == 0) { \
226                        ZVAL_LONG(&(holder), 0);                            \
227                    }                                                       \
228                    (op) = &(holder);                                       \
229                    break;                                                  \
230                }                                                           \
231            case IS_BOOL:                                                   \
232            case IS_RESOURCE:                                               \
233                ZVAL_LONG(&(holder), Z_LVAL_P(op));                         \
234                (op) = &(holder);                                           \
235                break;                                                      \
236            case IS_NULL:                                                   \
237                ZVAL_LONG(&(holder), 0);                                    \
238                (op) = &(holder);                                           \
239                break;                                                      \
240            case IS_OBJECT:                                                 \
241                (holder) = (*(op));                                         \
242                zval_copy_ctor(&(holder));                                  \
243                convert_to_long_base(&(holder), 10);                        \
244                if (Z_TYPE(holder) == IS_LONG) {                            \
245                    (op) = &(holder);                                       \
246                }                                                           \
247                break;                                                      \
248        }                                                                   \
249    }
250
251/* }}} */
252
253/* {{{ zendi_convert_to_long */
254#define zendi_convert_to_long(op, holder, result)                   \
255    if (op == result) {                                             \
256        convert_to_long(op);                                        \
257    } else if (Z_TYPE_P(op) != IS_LONG) {                           \
258        switch (Z_TYPE_P(op)) {                                     \
259            case IS_NULL:                                           \
260                Z_LVAL(holder) = 0;                                 \
261                break;                                              \
262            case IS_DOUBLE:                                         \
263                Z_LVAL(holder) = zend_dval_to_lval(Z_DVAL_P(op));   \
264                break;                                              \
265            case IS_STRING:                                         \
266                Z_LVAL(holder) = strtol(Z_STRVAL_P(op), NULL, 10);  \
267                break;                                              \
268            case IS_ARRAY:                                          \
269                Z_LVAL(holder) = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);  \
270                break;                                              \
271            case IS_OBJECT:                                         \
272                (holder) = (*(op));                                 \
273                zval_copy_ctor(&(holder));                          \
274                convert_to_long_base(&(holder), 10);                \
275                break;                                              \
276            case IS_BOOL:                                           \
277            case IS_RESOURCE:                                       \
278                Z_LVAL(holder) = Z_LVAL_P(op);                      \
279                break;                                              \
280            default:                                                \
281                zend_error(E_WARNING, "Cannot convert to ordinal value");   \
282                Z_LVAL(holder) = 0;                                 \
283                break;                                              \
284        }                                                           \
285        Z_TYPE(holder) = IS_LONG;                                   \
286        (op) = &(holder);                                           \
287    }
288
289/* }}} */
290
291/* {{{ zendi_convert_to_boolean */
292#define zendi_convert_to_boolean(op, holder, result)                \
293    if (op==result) {                                               \
294        convert_to_boolean(op);                                     \
295    } else if (Z_TYPE_P(op) != IS_BOOL) {                           \
296        switch (Z_TYPE_P(op)) {                                     \
297            case IS_NULL:                                           \
298                Z_LVAL(holder) = 0;                                 \
299                break;                                              \
300            case IS_RESOURCE:                                       \
301            case IS_LONG:                                           \
302                Z_LVAL(holder) = (Z_LVAL_P(op) ? 1 : 0);            \
303                break;                                              \
304            case IS_DOUBLE:                                         \
305                Z_LVAL(holder) = (Z_DVAL_P(op) ? 1 : 0);            \
306                break;                                              \
307            case IS_STRING:                                         \
308                if (Z_STRLEN_P(op) == 0                             \
309                    || (Z_STRLEN_P(op)==1 && Z_STRVAL_P(op)[0]=='0')) { \
310                    Z_LVAL(holder) = 0;                             \
311                } else {                                            \
312                    Z_LVAL(holder) = 1;                             \
313                }                                                   \
314                break;                                              \
315            case IS_ARRAY:                                          \
316                Z_LVAL(holder) = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);  \
317                break;                                              \
318            case IS_OBJECT:                                         \
319                (holder) = (*(op));                                 \
320                zval_copy_ctor(&(holder));                          \
321                convert_to_boolean(&(holder));                      \
322                break;                                              \
323            default:                                                \
324                Z_LVAL(holder) = 0;                                 \
325                break;                                              \
326        }                                                           \
327        Z_TYPE(holder) = IS_BOOL;                                   \
328        (op) = &(holder);                                           \
329    }
330
331/* }}} */
332
333/* {{{ convert_object_to_type */
334#define convert_object_to_type(op, ctype, conv_func)                                        \
335    if (Z_OBJ_HT_P(op)->cast_object) {                                                      \
336        zval dst;                                                                           \
337        if (Z_OBJ_HT_P(op)->cast_object(op, &dst, ctype TSRMLS_CC) == FAILURE) {            \
338            zend_error(E_RECOVERABLE_ERROR,                                                 \
339                "Object of class %s could not be converted to %s", Z_OBJCE_P(op)->name,     \
340            zend_get_type_by_const(ctype));                                                 \
341        } else {                                                                            \
342            zval_dtor(op);                                                                  \
343            Z_TYPE_P(op) = ctype;                                                           \
344            op->value = dst.value;                                                          \
345        }                                                                                   \
346    } else {                                                                                \
347        if (Z_OBJ_HT_P(op)->get) {                                                          \
348            zval *newop = Z_OBJ_HT_P(op)->get(op TSRMLS_CC);                                \
349            if (Z_TYPE_P(newop) != IS_OBJECT) {                                             \
350                /* for safety - avoid loop */                                               \
351                zval_dtor(op);                                                              \
352                *op = *newop;                                                               \
353                FREE_ZVAL(newop);                                                           \
354                conv_func(op);                                                              \
355            }                                                                               \
356        }                                                                                   \
357    }
358
359/* }}} */
360
361ZEND_API void convert_to_long(zval *op) /* {{{ */
362{
363    if (Z_TYPE_P(op) != IS_LONG) {
364        convert_to_long_base(op, 10);
365    }
366}
367/* }}} */
368
369ZEND_API void convert_to_long_base(zval *op, int base) /* {{{ */
370{
371    long tmp;
372
373    switch (Z_TYPE_P(op)) {
374        case IS_NULL:
375            Z_LVAL_P(op) = 0;
376            break;
377        case IS_RESOURCE: {
378                TSRMLS_FETCH();
379
380                zend_list_delete(Z_LVAL_P(op));
381            }
382            /* break missing intentionally */
383        case IS_BOOL:
384        case IS_LONG:
385            break;
386        case IS_DOUBLE:
387            Z_LVAL_P(op) = zend_dval_to_lval(Z_DVAL_P(op));
388            break;
389        case IS_STRING:
390            {
391                char *strval = Z_STRVAL_P(op);
392
393                Z_LVAL_P(op) = strtol(strval, NULL, base);
394                str_efree(strval);
395            }
396            break;
397        case IS_ARRAY:
398            tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
399            zval_dtor(op);
400            Z_LVAL_P(op) = tmp;
401            break;
402        case IS_OBJECT:
403            {
404                int retval = 1;
405                TSRMLS_FETCH();
406
407                convert_object_to_type(op, IS_LONG, convert_to_long);
408
409                if (Z_TYPE_P(op) == IS_LONG) {
410                    return;
411                }
412                zend_error(E_NOTICE, "Object of class %s could not be converted to int", Z_OBJCE_P(op)->name);
413
414                zval_dtor(op);
415                ZVAL_LONG(op, retval);
416                return;
417            }
418        default:
419            zend_error(E_WARNING, "Cannot convert to ordinal value");
420            zval_dtor(op);
421            Z_LVAL_P(op) = 0;
422            break;
423    }
424
425    Z_TYPE_P(op) = IS_LONG;
426}
427/* }}} */
428
429ZEND_API void convert_to_double(zval *op) /* {{{ */
430{
431    double tmp;
432
433    switch (Z_TYPE_P(op)) {
434        case IS_NULL:
435            Z_DVAL_P(op) = 0.0;
436            break;
437        case IS_RESOURCE: {
438                TSRMLS_FETCH();
439
440                zend_list_delete(Z_LVAL_P(op));
441            }
442            /* break missing intentionally */
443        case IS_BOOL:
444        case IS_LONG:
445            Z_DVAL_P(op) = (double) Z_LVAL_P(op);
446            break;
447        case IS_DOUBLE:
448            break;
449        case IS_STRING:
450            {
451                char *strval = Z_STRVAL_P(op);
452
453                Z_DVAL_P(op) = zend_strtod(strval, NULL);
454                str_efree(strval);
455            }
456            break;
457        case IS_ARRAY:
458            tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
459            zval_dtor(op);
460            Z_DVAL_P(op) = tmp;
461            break;
462        case IS_OBJECT:
463            {
464                double retval = 1.0;
465                TSRMLS_FETCH();
466
467                convert_object_to_type(op, IS_DOUBLE, convert_to_double);
468
469                if (Z_TYPE_P(op) == IS_DOUBLE) {
470                    return;
471                }
472                zend_error(E_NOTICE, "Object of class %s could not be converted to double", Z_OBJCE_P(op)->name);
473
474                zval_dtor(op);
475                ZVAL_DOUBLE(op, retval);
476                break;
477            }
478        default:
479            zend_error(E_WARNING, "Cannot convert to real value (type=%d)", Z_TYPE_P(op));
480            zval_dtor(op);
481            Z_DVAL_P(op) = 0;
482            break;
483    }
484    Z_TYPE_P(op) = IS_DOUBLE;
485}
486/* }}} */
487
488ZEND_API void convert_to_null(zval *op) /* {{{ */
489{
490    if (Z_TYPE_P(op) == IS_OBJECT) {
491        if (Z_OBJ_HT_P(op)->cast_object) {
492            zval *org;
493            TSRMLS_FETCH();
494
495            ALLOC_ZVAL(org);
496            *org = *op;
497            if (Z_OBJ_HT_P(op)->cast_object(org, op, IS_NULL TSRMLS_CC) == SUCCESS) {
498                zval_dtor(org);
499                return;
500            }
501            *op = *org;
502            FREE_ZVAL(org);
503        }
504    }
505
506    zval_dtor(op);
507    Z_TYPE_P(op) = IS_NULL;
508}
509/* }}} */
510
511ZEND_API void convert_to_boolean(zval *op) /* {{{ */
512{
513    int tmp;
514
515    switch (Z_TYPE_P(op)) {
516        case IS_BOOL:
517            break;
518        case IS_NULL:
519            Z_LVAL_P(op) = 0;
520            break;
521        case IS_RESOURCE: {
522                TSRMLS_FETCH();
523
524                zend_list_delete(Z_LVAL_P(op));
525            }
526            /* break missing intentionally */
527        case IS_LONG:
528            Z_LVAL_P(op) = (Z_LVAL_P(op) ? 1 : 0);
529            break;
530        case IS_DOUBLE:
531            Z_LVAL_P(op) = (Z_DVAL_P(op) ? 1 : 0);
532            break;
533        case IS_STRING:
534            {
535                char *strval = Z_STRVAL_P(op);
536
537                if (Z_STRLEN_P(op) == 0
538                    || (Z_STRLEN_P(op)==1 && Z_STRVAL_P(op)[0]=='0')) {
539                    Z_LVAL_P(op) = 0;
540                } else {
541                    Z_LVAL_P(op) = 1;
542                }
543                str_efree(strval);
544            }
545            break;
546        case IS_ARRAY:
547            tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
548            zval_dtor(op);
549            Z_LVAL_P(op) = tmp;
550            break;
551        case IS_OBJECT:
552            {
553                zend_bool retval = 1;
554                TSRMLS_FETCH();
555
556                convert_object_to_type(op, IS_BOOL, convert_to_boolean);
557
558                if (Z_TYPE_P(op) == IS_BOOL) {
559                    return;
560                }
561
562                zval_dtor(op);
563                ZVAL_BOOL(op, retval);
564                break;
565            }
566        default:
567            zval_dtor(op);
568            Z_LVAL_P(op) = 0;
569            break;
570    }
571    Z_TYPE_P(op) = IS_BOOL;
572}
573/* }}} */
574
575ZEND_API void _convert_to_cstring(zval *op ZEND_FILE_LINE_DC) /* {{{ */
576{
577    double dval;
578    switch (Z_TYPE_P(op)) {
579        case IS_DOUBLE: {
580            TSRMLS_FETCH();
581            dval = Z_DVAL_P(op);
582            Z_STRLEN_P(op) = zend_spprintf(&Z_STRVAL_P(op), 0, "%.*H", (int) EG(precision), dval);
583            /* %H already handles removing trailing zeros from the fractional part, yay */
584            break;
585        }
586        default:
587            _convert_to_string(op ZEND_FILE_LINE_CC);
588    }
589    Z_TYPE_P(op) = IS_STRING;
590}
591/* }}} */
592
593ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC) /* {{{ */
594{
595    long lval;
596    double dval;
597
598    switch (Z_TYPE_P(op)) {
599        case IS_NULL:
600            Z_STRVAL_P(op) = STR_EMPTY_ALLOC();
601            Z_STRLEN_P(op) = 0;
602            break;
603        case IS_STRING:
604            break;
605        case IS_BOOL:
606            if (Z_LVAL_P(op)) {
607                Z_STRVAL_P(op) = estrndup_rel("1", 1);
608                Z_STRLEN_P(op) = 1;
609            } else {
610                Z_STRVAL_P(op) = STR_EMPTY_ALLOC();
611                Z_STRLEN_P(op) = 0;
612            }
613            break;
614        case IS_RESOURCE: {
615            long tmp = Z_LVAL_P(op);
616            TSRMLS_FETCH();
617
618            zend_list_delete(Z_LVAL_P(op));
619            Z_STRLEN_P(op) = zend_spprintf(&Z_STRVAL_P(op), 0, "Resource id #%ld", tmp);
620            break;
621        }
622        case IS_LONG:
623            lval = Z_LVAL_P(op);
624
625            Z_STRLEN_P(op) = zend_spprintf(&Z_STRVAL_P(op), 0, "%ld", lval);
626            break;
627        case IS_DOUBLE: {
628            TSRMLS_FETCH();
629            dval = Z_DVAL_P(op);
630            Z_STRLEN_P(op) = zend_spprintf(&Z_STRVAL_P(op), 0, "%.*G", (int) EG(precision), dval);
631            /* %G already handles removing trailing zeros from the fractional part, yay */
632            break;
633        }
634        case IS_ARRAY:
635            zend_error(E_NOTICE, "Array to string conversion");
636            zval_dtor(op);
637            Z_STRVAL_P(op) = estrndup_rel("Array", sizeof("Array")-1);
638            Z_STRLEN_P(op) = sizeof("Array")-1;
639            break;
640        case IS_OBJECT: {
641            TSRMLS_FETCH();
642
643            convert_object_to_type(op, IS_STRING, convert_to_string);
644
645            if (Z_TYPE_P(op) == IS_STRING) {
646                return;
647            }
648
649            zend_error(E_NOTICE, "Object of class %s to string conversion", Z_OBJCE_P(op)->name);
650            zval_dtor(op);
651            Z_STRVAL_P(op) = estrndup_rel("Object", sizeof("Object")-1);
652            Z_STRLEN_P(op) = sizeof("Object")-1;
653            break;
654        }
655        default:
656            zval_dtor(op);
657            ZVAL_BOOL(op, 0);
658            break;
659    }
660    Z_TYPE_P(op) = IS_STRING;
661}
662/* }}} */
663
664static void convert_scalar_to_array(zval *op, int type TSRMLS_DC) /* {{{ */
665{
666    zval *entry;
667
668    ALLOC_ZVAL(entry);
669    *entry = *op;
670    INIT_PZVAL(entry);
671
672    switch (type) {
673        case IS_ARRAY:
674            ALLOC_HASHTABLE(Z_ARRVAL_P(op));
675            zend_hash_init(Z_ARRVAL_P(op), 0, NULL, ZVAL_PTR_DTOR, 0);
676            zend_hash_index_update(Z_ARRVAL_P(op), 0, (void *) &entry, sizeof(zval *), NULL);
677            Z_TYPE_P(op) = IS_ARRAY;
678            break;
679        case IS_OBJECT:
680            object_init(op);
681            zend_hash_update(Z_OBJPROP_P(op), "scalar", sizeof("scalar"), (void *) &entry, sizeof(zval *), NULL);
682            break;
683    }
684}
685/* }}} */
686
687ZEND_API void convert_to_array(zval *op) /* {{{ */
688{
689    TSRMLS_FETCH();
690
691    switch (Z_TYPE_P(op)) {
692        case IS_ARRAY:
693            break;
694/* OBJECTS_OPTIMIZE */
695        case IS_OBJECT:
696            {
697                zval *tmp;
698                HashTable *ht;
699
700                ALLOC_HASHTABLE(ht);
701                zend_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0);
702                if (Z_OBJCE_P(op) == zend_ce_closure) {
703                    convert_scalar_to_array(op, IS_ARRAY TSRMLS_CC);
704                    if (Z_TYPE_P(op) == IS_ARRAY) {
705                        zend_hash_destroy(ht);
706                        FREE_HASHTABLE(ht);
707                        return;
708                    }
709                } else if (Z_OBJ_HT_P(op)->get_properties) {
710                    HashTable *obj_ht = Z_OBJ_HT_P(op)->get_properties(op TSRMLS_CC);
711                    if (obj_ht) {
712                        zend_hash_copy(ht, obj_ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
713                    }
714                } else {
715                    convert_object_to_type(op, IS_ARRAY, convert_to_array);
716
717                    if (Z_TYPE_P(op) == IS_ARRAY) {
718                        zend_hash_destroy(ht);
719                        FREE_HASHTABLE(ht);
720                        return;
721                    }
722                }
723                zval_dtor(op);
724                Z_TYPE_P(op) = IS_ARRAY;
725                Z_ARRVAL_P(op) = ht;
726            }
727            break;
728        case IS_NULL:
729            ALLOC_HASHTABLE(Z_ARRVAL_P(op));
730            zend_hash_init(Z_ARRVAL_P(op), 0, NULL, ZVAL_PTR_DTOR, 0);
731            Z_TYPE_P(op) = IS_ARRAY;
732            break;
733        default:
734            convert_scalar_to_array(op, IS_ARRAY TSRMLS_CC);
735            break;
736    }
737}
738/* }}} */
739
740ZEND_API void convert_to_object(zval *op) /* {{{ */
741{
742    TSRMLS_FETCH();
743
744    switch (Z_TYPE_P(op)) {
745        case IS_ARRAY:
746            {
747                object_and_properties_init(op, zend_standard_class_def, Z_ARRVAL_P(op));
748                break;
749            }
750        case IS_OBJECT:
751            break;
752        case IS_NULL:
753            object_init(op);
754            break;
755        default:
756            convert_scalar_to_array(op, IS_OBJECT TSRMLS_CC);
757            break;
758    }
759}
760/* }}} */
761
762ZEND_API void multi_convert_to_long_ex(int argc, ...) /* {{{ */
763{
764    zval **arg;
765    va_list ap;
766
767    va_start(ap, argc);
768
769    while (argc--) {
770        arg = va_arg(ap, zval **);
771        convert_to_long_ex(arg);
772    }
773
774    va_end(ap);
775}
776/* }}} */
777
778ZEND_API void multi_convert_to_double_ex(int argc, ...) /* {{{ */
779{
780    zval **arg;
781    va_list ap;
782
783    va_start(ap, argc);
784
785    while (argc--) {
786        arg = va_arg(ap, zval **);
787        convert_to_double_ex(arg);
788    }
789
790    va_end(ap);
791}
792/* }}} */
793
794ZEND_API void multi_convert_to_string_ex(int argc, ...) /* {{{ */
795{
796    zval **arg;
797    va_list ap;
798
799    va_start(ap, argc);
800
801    while (argc--) {
802        arg = va_arg(ap, zval **);
803        convert_to_string_ex(arg);
804    }
805
806    va_end(ap);
807}
808/* }}} */
809
810ZEND_API int add_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
811{
812    zval op1_copy, op2_copy;
813    int converted = 0;
814
815    while (1) {
816        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
817            case TYPE_PAIR(IS_LONG, IS_LONG): {
818                long lval = Z_LVAL_P(op1) + Z_LVAL_P(op2);
819
820                /* check for overflow by comparing sign bits */
821                if ((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK)
822                    && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (lval & LONG_SIGN_MASK)) {
823
824                    ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2));
825                } else {
826                    ZVAL_LONG(result, lval);
827                }
828                return SUCCESS;
829            }
830
831            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
832                ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
833                return SUCCESS;
834
835            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
836                ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
837                return SUCCESS;
838
839            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
840                ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
841                return SUCCESS;
842
843            case TYPE_PAIR(IS_ARRAY, IS_ARRAY): {
844                zval *tmp;
845
846                if ((result == op1) && (result == op2)) {
847                    /* $a += $a */
848                    return SUCCESS;
849                }
850                if (result != op1) {
851                    *result = *op1;
852                    zval_copy_ctor(result);
853                }
854                zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), (void (*)(void *pData)) zval_add_ref, (void *) &tmp, sizeof(zval *), 0);
855                return SUCCESS;
856            }
857
858            default:
859                if (!converted) {
860                    ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_ADD);
861
862                    zendi_convert_scalar_to_number(op1, op1_copy, result);
863                    zendi_convert_scalar_to_number(op2, op2_copy, result);
864                    converted = 1;
865                } else {
866                    zend_error(E_ERROR, "Unsupported operand types");
867                    return FAILURE; /* unknown datatype */
868                }
869        }
870    }
871}
872/* }}} */
873
874ZEND_API int sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
875{
876    zval op1_copy, op2_copy;
877    int converted = 0;
878
879    while (1) {
880        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
881            case TYPE_PAIR(IS_LONG, IS_LONG): {
882                long lval = Z_LVAL_P(op1) - Z_LVAL_P(op2);
883
884                /* check for overflow by comparing sign bits */
885                if ((Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(op2) & LONG_SIGN_MASK)
886                    && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (lval & LONG_SIGN_MASK)) {
887
888                    ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2));
889                } else {
890                    ZVAL_LONG(result, lval);
891                }
892                return SUCCESS;
893
894            }
895            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
896                ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) - Z_DVAL_P(op2));
897                return SUCCESS;
898
899            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
900                ZVAL_DOUBLE(result, Z_DVAL_P(op1) - ((double)Z_LVAL_P(op2)));
901                return SUCCESS;
902
903            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
904                ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2));
905                return SUCCESS;
906
907            default:
908                if (!converted) {
909                    ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB);
910
911                    zendi_convert_scalar_to_number(op1, op1_copy, result);
912                    zendi_convert_scalar_to_number(op2, op2_copy, result);
913                    converted = 1;
914                } else {
915                    zend_error(E_ERROR, "Unsupported operand types");
916                    return FAILURE; /* unknown datatype */
917                }
918        }
919    }
920}
921/* }}} */
922
923ZEND_API int mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
924{
925    zval op1_copy, op2_copy;
926    int converted = 0;
927
928    while (1) {
929        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
930            case TYPE_PAIR(IS_LONG, IS_LONG): {
931                long overflow;
932
933                ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1),Z_LVAL_P(op2), Z_LVAL_P(result),Z_DVAL_P(result),overflow);
934                Z_TYPE_P(result) = overflow ? IS_DOUBLE : IS_LONG;
935                return SUCCESS;
936
937            }
938            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
939                ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2));
940                return SUCCESS;
941
942            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
943                ZVAL_DOUBLE(result, Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2)));
944                return SUCCESS;
945
946            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
947                ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2));
948                return SUCCESS;
949
950            default:
951                if (!converted) {
952                    ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MUL);
953
954                    zendi_convert_scalar_to_number(op1, op1_copy, result);
955                    zendi_convert_scalar_to_number(op2, op2_copy, result);
956                    converted = 1;
957                } else {
958                    zend_error(E_ERROR, "Unsupported operand types");
959                    return FAILURE; /* unknown datatype */
960                }
961        }
962    }
963}
964/* }}} */
965
966ZEND_API int pow_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
967{
968    zval op1_copy, op2_copy;
969    int converted = 0;
970
971    while (1) {
972        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
973            case TYPE_PAIR(IS_LONG, IS_LONG):
974                if (Z_LVAL_P(op2) >= 0) {
975                    long l1 = 1, l2 = Z_LVAL_P(op1), i = Z_LVAL_P(op2);
976
977                    if (i == 0) {
978                        ZVAL_LONG(result, 1L);
979                        return SUCCESS;
980                    } else if (l2 == 0) {
981                        ZVAL_LONG(result, 0);
982                        return SUCCESS;
983                    }
984
985                    while (i >= 1) {
986                        long overflow;
987                        double dval = 0.0;
988
989                        if (i % 2) {
990                            --i;
991                            ZEND_SIGNED_MULTIPLY_LONG(l1, l2, l1, dval, overflow);
992                            if (overflow) {
993                                ZVAL_DOUBLE(result, dval * pow(l2, i));
994                                return SUCCESS;
995                            }
996                        } else {
997                            i /= 2;
998                            ZEND_SIGNED_MULTIPLY_LONG(l2, l2, l2, dval, overflow);
999                            if (overflow) {
1000                                ZVAL_DOUBLE(result, (double)l1 * pow(dval, i));
1001                                return SUCCESS;
1002                            }
1003                        }
1004                    }
1005                    /* i == 0 */
1006                    ZVAL_LONG(result, l1);
1007                } else {
1008                    ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), (double)Z_LVAL_P(op2)));
1009                }
1010                return SUCCESS;
1011
1012            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1013                ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), Z_DVAL_P(op2)));
1014                return SUCCESS;
1015
1016            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1017                ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), (double)Z_LVAL_P(op2)));
1018                return SUCCESS;
1019
1020            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1021                ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), Z_DVAL_P(op2)));
1022                return SUCCESS;
1023
1024            default:
1025                if (!converted) {
1026                    ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_POW);
1027
1028                    if (Z_TYPE_P(op1) == IS_ARRAY) {
1029                        ZVAL_LONG(result, 0);
1030                        return SUCCESS;
1031                    } else {
1032                        zendi_convert_scalar_to_number(op1, op1_copy, result);
1033                    }
1034                    if (Z_TYPE_P(op2) == IS_ARRAY) {
1035                        ZVAL_LONG(result, 1L);
1036                        return SUCCESS;
1037                    } else {
1038                        zendi_convert_scalar_to_number(op2, op2_copy, result);
1039                    }
1040                    converted = 1;
1041                } else {
1042                    zend_error(E_ERROR, "Unsupported operand types");
1043                    return FAILURE;
1044                }
1045        }
1046    }
1047}
1048/* }}} */
1049
1050ZEND_API int div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1051{
1052    zval op1_copy, op2_copy;
1053    int converted = 0;
1054
1055    while (1) {
1056        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
1057            case TYPE_PAIR(IS_LONG, IS_LONG):
1058                if (Z_LVAL_P(op2) == 0) {
1059                    zend_error(E_WARNING, "Division by zero");
1060                    ZVAL_BOOL(result, 0);
1061                    return FAILURE;         /* division by zero */
1062                } else if (Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == LONG_MIN) {
1063                    /* Prevent overflow error/crash */
1064                    ZVAL_DOUBLE(result, (double) LONG_MIN / -1);
1065                    return SUCCESS;
1066                }
1067                if (Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0) { /* integer */
1068                    ZVAL_LONG(result, Z_LVAL_P(op1) / Z_LVAL_P(op2));
1069                } else {
1070                    ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1)) / Z_LVAL_P(op2));
1071                }
1072                return SUCCESS;
1073
1074            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1075                if (Z_LVAL_P(op2) == 0) {
1076                    zend_error(E_WARNING, "Division by zero");
1077                    ZVAL_BOOL(result, 0);
1078                    return FAILURE;         /* division by zero */
1079                }
1080                ZVAL_DOUBLE(result, Z_DVAL_P(op1) / (double)Z_LVAL_P(op2));
1081                return SUCCESS;
1082
1083            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1084                if (Z_DVAL_P(op2) == 0) {
1085                    zend_error(E_WARNING, "Division by zero");
1086                    ZVAL_BOOL(result, 0);
1087                    return FAILURE;         /* division by zero */
1088                }
1089                ZVAL_DOUBLE(result, (double)Z_LVAL_P(op1) / Z_DVAL_P(op2));
1090                return SUCCESS;
1091
1092            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1093                if (Z_DVAL_P(op2) == 0) {
1094                    zend_error(E_WARNING, "Division by zero");
1095                    ZVAL_BOOL(result, 0);
1096                    return FAILURE;         /* division by zero */
1097                }
1098                ZVAL_DOUBLE(result, Z_DVAL_P(op1) / Z_DVAL_P(op2));
1099                return SUCCESS;
1100
1101            default:
1102                if (!converted) {
1103                    ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV);
1104
1105                    zendi_convert_scalar_to_number(op1, op1_copy, result);
1106                    zendi_convert_scalar_to_number(op2, op2_copy, result);
1107                    converted = 1;
1108                } else {
1109                    zend_error(E_ERROR, "Unsupported operand types");
1110                    return FAILURE; /* unknown datatype */
1111                }
1112        }
1113    }
1114}
1115/* }}} */
1116
1117ZEND_API int mod_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1118{
1119    zval op1_copy, op2_copy;
1120    long op1_lval;
1121
1122    if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
1123        ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MOD);
1124
1125        zendi_convert_to_long(op1, op1_copy, result);
1126        op1_lval = Z_LVAL_P(op1);
1127        zendi_convert_to_long(op2, op2_copy, result);
1128    } else {
1129        op1_lval = Z_LVAL_P(op1);
1130    }
1131
1132    if (Z_LVAL_P(op2) == 0) {
1133        zend_error(E_WARNING, "Division by zero");
1134        ZVAL_BOOL(result, 0);
1135        return FAILURE;         /* modulus by zero */
1136    }
1137
1138    if (Z_LVAL_P(op2) == -1) {
1139        /* Prevent overflow error/crash if op1==LONG_MIN */
1140        ZVAL_LONG(result, 0);
1141        return SUCCESS;
1142    }
1143
1144    ZVAL_LONG(result, op1_lval % Z_LVAL_P(op2));
1145    return SUCCESS;
1146}
1147/* }}} */
1148
1149ZEND_API int boolean_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1150{
1151    zval op1_copy, op2_copy;
1152    long op1_lval;
1153
1154    if (Z_TYPE_P(op1) != IS_BOOL || Z_TYPE_P(op2) != IS_BOOL) {
1155        ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BOOL_XOR);
1156
1157        zendi_convert_to_boolean(op1, op1_copy, result);
1158        op1_lval = Z_LVAL_P(op1);
1159        zendi_convert_to_boolean(op2, op2_copy, result);
1160    } else {
1161        op1_lval = Z_LVAL_P(op1);
1162    }
1163
1164    ZVAL_BOOL(result, op1_lval ^ Z_LVAL_P(op2));
1165    return SUCCESS;
1166}
1167/* }}} */
1168
1169ZEND_API int boolean_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */
1170{
1171    zval op1_copy;
1172
1173    if (Z_TYPE_P(op1) != IS_BOOL) {
1174        ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BOOL_NOT);
1175
1176        zendi_convert_to_boolean(op1, op1_copy, result);
1177    }
1178
1179    ZVAL_BOOL(result, !Z_LVAL_P(op1));
1180    return SUCCESS;
1181}
1182/* }}} */
1183
1184ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */
1185{
1186
1187    switch (Z_TYPE_P(op1)) {
1188        case IS_LONG:
1189            ZVAL_LONG(result, ~Z_LVAL_P(op1));
1190            return SUCCESS;
1191        case IS_DOUBLE:
1192            ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1)));
1193            return SUCCESS;
1194        case IS_STRING: {
1195            int i;
1196            zval op1_copy = *op1;
1197
1198            Z_TYPE_P(result) = IS_STRING;
1199            Z_STRVAL_P(result) = estrndup(Z_STRVAL(op1_copy), Z_STRLEN(op1_copy));
1200            Z_STRLEN_P(result) = Z_STRLEN(op1_copy);
1201            for (i = 0; i < Z_STRLEN(op1_copy); i++) {
1202                Z_STRVAL_P(result)[i] = ~Z_STRVAL(op1_copy)[i];
1203            }
1204            return SUCCESS;
1205        }
1206        default:
1207            ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BW_NOT);
1208
1209            zend_error(E_ERROR, "Unsupported operand types");
1210            return FAILURE;
1211    }
1212}
1213/* }}} */
1214
1215ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1216{
1217    zval op1_copy, op2_copy;
1218    long op1_lval;
1219
1220    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1221        zval *longer, *shorter;
1222        char *result_str;
1223        int i, result_len;
1224
1225        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1226            longer = op1;
1227            shorter = op2;
1228        } else {
1229            longer = op2;
1230            shorter = op1;
1231        }
1232
1233        Z_TYPE_P(result) = IS_STRING;
1234        result_len = Z_STRLEN_P(longer);
1235        result_str = estrndup(Z_STRVAL_P(longer), Z_STRLEN_P(longer));
1236        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1237            result_str[i] |= Z_STRVAL_P(shorter)[i];
1238        }
1239        if (result==op1) {
1240            str_efree(Z_STRVAL_P(result));
1241        }
1242        Z_STRVAL_P(result) = result_str;
1243        Z_STRLEN_P(result) = result_len;
1244        return SUCCESS;
1245    }
1246
1247    if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
1248        ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_OR);
1249
1250        zendi_convert_to_long(op1, op1_copy, result);
1251        op1_lval = Z_LVAL_P(op1);
1252        zendi_convert_to_long(op2, op2_copy, result);
1253    } else {
1254        op1_lval = Z_LVAL_P(op1);
1255    }
1256
1257    ZVAL_LONG(result, op1_lval | Z_LVAL_P(op2));
1258    return SUCCESS;
1259}
1260/* }}} */
1261
1262ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1263{
1264    zval op1_copy, op2_copy;
1265    long op1_lval;
1266
1267    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1268        zval *longer, *shorter;
1269        char *result_str;
1270        int i, result_len;
1271
1272        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1273            longer = op1;
1274            shorter = op2;
1275        } else {
1276            longer = op2;
1277            shorter = op1;
1278        }
1279
1280        Z_TYPE_P(result) = IS_STRING;
1281        result_len = Z_STRLEN_P(shorter);
1282        result_str = estrndup(Z_STRVAL_P(shorter), Z_STRLEN_P(shorter));
1283        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1284            result_str[i] &= Z_STRVAL_P(longer)[i];
1285        }
1286        if (result==op1) {
1287            str_efree(Z_STRVAL_P(result));
1288        }
1289        Z_STRVAL_P(result) = result_str;
1290        Z_STRLEN_P(result) = result_len;
1291        return SUCCESS;
1292    }
1293
1294    if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
1295        ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_AND);
1296
1297        zendi_convert_to_long(op1, op1_copy, result);
1298        op1_lval = Z_LVAL_P(op1);
1299        zendi_convert_to_long(op2, op2_copy, result);
1300    } else {
1301        op1_lval = Z_LVAL_P(op1);
1302    }
1303
1304    ZVAL_LONG(result, op1_lval & Z_LVAL_P(op2));
1305    return SUCCESS;
1306}
1307/* }}} */
1308
1309ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1310{
1311    zval op1_copy, op2_copy;
1312    long op1_lval;
1313
1314    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1315        zval *longer, *shorter;
1316        char *result_str;
1317        int i, result_len;
1318
1319        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1320            longer = op1;
1321            shorter = op2;
1322        } else {
1323            longer = op2;
1324            shorter = op1;
1325        }
1326
1327        Z_TYPE_P(result) = IS_STRING;
1328        result_len = Z_STRLEN_P(shorter);
1329        result_str = estrndup(Z_STRVAL_P(shorter), Z_STRLEN_P(shorter));
1330        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1331            result_str[i] ^= Z_STRVAL_P(longer)[i];
1332        }
1333        if (result==op1) {
1334            str_efree(Z_STRVAL_P(result));
1335        }
1336        Z_STRVAL_P(result) = result_str;
1337        Z_STRLEN_P(result) = result_len;
1338        return SUCCESS;
1339    }
1340
1341    if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
1342        ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_XOR);
1343
1344        zendi_convert_to_long(op1, op1_copy, result);
1345        op1_lval = Z_LVAL_P(op1);
1346        zendi_convert_to_long(op2, op2_copy, result);
1347    } else {
1348        op1_lval = Z_LVAL_P(op1);
1349    }
1350
1351    ZVAL_LONG(result, op1_lval ^ Z_LVAL_P(op2));
1352    return SUCCESS;
1353}
1354/* }}} */
1355
1356ZEND_API int shift_left_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1357{
1358    zval op1_copy, op2_copy;
1359    long op1_lval;
1360
1361    if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
1362        ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SL);
1363
1364        zendi_convert_to_long(op1, op1_copy, result);
1365        op1_lval = Z_LVAL_P(op1);
1366        zendi_convert_to_long(op2, op2_copy, result);
1367    } else {
1368        op1_lval = Z_LVAL_P(op1);
1369    }
1370
1371    ZVAL_LONG(result, op1_lval << Z_LVAL_P(op2));
1372    return SUCCESS;
1373}
1374/* }}} */
1375
1376ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1377{
1378    zval op1_copy, op2_copy;
1379    long op1_lval;
1380
1381    if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
1382        ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SR);
1383
1384        zendi_convert_to_long(op1, op1_copy, result);
1385        op1_lval = Z_LVAL_P(op1);
1386        zendi_convert_to_long(op2, op2_copy, result);
1387    } else {
1388        op1_lval = Z_LVAL_P(op1);
1389    }
1390
1391    ZVAL_LONG(result, op1_lval >> Z_LVAL_P(op2));
1392    return SUCCESS;
1393}
1394/* }}} */
1395
1396/* must support result==op1 */
1397ZEND_API int add_char_to_string(zval *result, const zval *op1, const zval *op2) /* {{{ */
1398{
1399    int length = Z_STRLEN_P(op1) + 1;
1400    char *buf = str_erealloc(Z_STRVAL_P(op1), length + 1);
1401
1402    buf[length - 1] = (char) Z_LVAL_P(op2);
1403    buf[length] = 0;
1404    ZVAL_STRINGL(result, buf, length, 0);
1405    return SUCCESS;
1406}
1407/* }}} */
1408
1409/* must support result==op1 */
1410ZEND_API int add_string_to_string(zval *result, const zval *op1, const zval *op2) /* {{{ */
1411{
1412    int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
1413    char *buf = str_erealloc(Z_STRVAL_P(op1), length + 1);
1414
1415    memcpy(buf + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1416    buf[length] = 0;
1417    ZVAL_STRINGL(result, buf, length, 0);
1418    return SUCCESS;
1419}
1420/* }}} */
1421
1422ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1423{
1424    zval op1_copy, op2_copy;
1425    int use_copy1 = 0, use_copy2 = 0;
1426
1427    if (Z_TYPE_P(op1) != IS_STRING || Z_TYPE_P(op2) != IS_STRING) {
1428        ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT);
1429
1430        if (Z_TYPE_P(op1) != IS_STRING) {
1431            zend_make_printable_zval(op1, &op1_copy, &use_copy1);
1432        }
1433        if (Z_TYPE_P(op2) != IS_STRING) {
1434            zend_make_printable_zval(op2, &op2_copy, &use_copy2);
1435        }
1436    }
1437
1438    if (use_copy1) {
1439        /* We have created a converted copy of op1. Therefore, op1 won't become the result so
1440         * we have to free it.
1441         */
1442        if (result == op1) {
1443            zval_dtor(op1);
1444        }
1445        op1 = &op1_copy;
1446    }
1447    if (use_copy2) {
1448        op2 = &op2_copy;
1449    }
1450    if (result==op1 && !IS_INTERNED(Z_STRVAL_P(op1))) { /* special case, perform operations on result */
1451        uint res_len = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
1452
1453        if (Z_STRLEN_P(result) < 0 || (int) (Z_STRLEN_P(op1) + Z_STRLEN_P(op2)) < 0) {
1454            efree(Z_STRVAL_P(result));
1455            ZVAL_EMPTY_STRING(result);
1456            zend_error(E_ERROR, "String size overflow");
1457        }
1458
1459        Z_STRVAL_P(result) = safe_erealloc(Z_STRVAL_P(result), res_len, 1, 1);
1460
1461        memcpy(Z_STRVAL_P(result)+Z_STRLEN_P(result), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1462        Z_STRVAL_P(result)[res_len]=0;
1463        Z_STRLEN_P(result) = res_len;
1464    } else {
1465        int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
1466        char *buf;
1467
1468        if (Z_STRLEN_P(op1) < 0 || Z_STRLEN_P(op2) < 0 || (int) (Z_STRLEN_P(op1) + Z_STRLEN_P(op2)) < 0) {
1469            zend_error(E_ERROR, "String size overflow");
1470        }
1471        buf = (char *) safe_emalloc(length, 1, 1);
1472
1473        memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1));
1474        memcpy(buf + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1475        buf[length] = 0;
1476        ZVAL_STRINGL(result, buf, length, 0);
1477    }
1478    if (use_copy1) {
1479        zval_dtor(op1);
1480    }
1481    if (use_copy2) {
1482        zval_dtor(op2);
1483    }
1484    return SUCCESS;
1485}
1486/* }}} */
1487
1488ZEND_API int string_compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool case_insensitive TSRMLS_DC) /* {{{ */
1489{
1490    zval op1_copy, op2_copy;
1491    int use_copy1 = 0, use_copy2 = 0;
1492
1493    if (Z_TYPE_P(op1) != IS_STRING) {
1494        zend_make_printable_zval(op1, &op1_copy, &use_copy1);
1495    }
1496    if (Z_TYPE_P(op2) != IS_STRING) {
1497        zend_make_printable_zval(op2, &op2_copy, &use_copy2);
1498    }
1499
1500    if (use_copy1) {
1501        op1 = &op1_copy;
1502    }
1503    if (use_copy2) {
1504        op2 = &op2_copy;
1505    }
1506
1507    if (case_insensitive) {
1508        ZVAL_LONG(result, zend_binary_zval_strcasecmp(op1, op2));
1509    } else {
1510        ZVAL_LONG(result, zend_binary_zval_strcmp(op1, op2));
1511    }
1512
1513    if (use_copy1) {
1514        zval_dtor(op1);
1515    }
1516    if (use_copy2) {
1517        zval_dtor(op2);
1518    }
1519    return SUCCESS;
1520}
1521/* }}} */
1522
1523ZEND_API int string_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1524{
1525    return string_compare_function_ex(result, op1, op2, 0 TSRMLS_CC);
1526}
1527/* }}} */
1528
1529ZEND_API int string_case_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1530{
1531    return string_compare_function_ex(result, op1, op2, 1 TSRMLS_CC);
1532}
1533/* }}} */
1534
1535#if HAVE_STRCOLL
1536ZEND_API int string_locale_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1537{
1538    zval op1_copy, op2_copy;
1539    int use_copy1 = 0, use_copy2 = 0;
1540
1541    if (Z_TYPE_P(op1) != IS_STRING) {
1542        zend_make_printable_zval(op1, &op1_copy, &use_copy1);
1543    }
1544    if (Z_TYPE_P(op2) != IS_STRING) {
1545        zend_make_printable_zval(op2, &op2_copy, &use_copy2);
1546    }
1547
1548    if (use_copy1) {
1549        op1 = &op1_copy;
1550    }
1551    if (use_copy2) {
1552        op2 = &op2_copy;
1553    }
1554
1555    ZVAL_LONG(result, strcoll(Z_STRVAL_P(op1), Z_STRVAL_P(op2)));
1556
1557    if (use_copy1) {
1558        zval_dtor(op1);
1559    }
1560    if (use_copy2) {
1561        zval_dtor(op2);
1562    }
1563    return SUCCESS;
1564}
1565/* }}} */
1566#endif
1567
1568ZEND_API int numeric_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1569{
1570    zval op1_copy, op2_copy;
1571
1572    op1_copy = *op1;
1573    zval_copy_ctor(&op1_copy);
1574
1575    op2_copy = *op2;
1576    zval_copy_ctor(&op2_copy);
1577
1578    convert_to_double(&op1_copy);
1579    convert_to_double(&op2_copy);
1580
1581    ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL(op1_copy)-Z_DVAL(op2_copy)));
1582
1583    return SUCCESS;
1584}
1585/* }}} */
1586
1587static inline void zend_free_obj_get_result(zval *op TSRMLS_DC) /* {{{ */
1588{
1589    if (Z_REFCOUNT_P(op) == 0) {
1590        GC_REMOVE_ZVAL_FROM_BUFFER(op);
1591        zval_dtor(op);
1592        FREE_ZVAL(op);
1593    } else {
1594        zval_ptr_dtor(&op);
1595    }
1596}
1597/* }}} */
1598
1599ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1600{
1601    int ret;
1602    int converted = 0;
1603    zval op1_copy, op2_copy;
1604    zval *op_free;
1605
1606    while (1) {
1607        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
1608            case TYPE_PAIR(IS_LONG, IS_LONG):
1609                ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0));
1610                return SUCCESS;
1611
1612            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1613                Z_DVAL_P(result) = Z_DVAL_P(op1) - (double)Z_LVAL_P(op2);
1614                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1615                return SUCCESS;
1616
1617            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1618                Z_DVAL_P(result) = (double)Z_LVAL_P(op1) - Z_DVAL_P(op2);
1619                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1620                return SUCCESS;
1621
1622            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1623                if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
1624                    ZVAL_LONG(result, 0);
1625                } else {
1626                    Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2);
1627                    ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1628                }
1629                return SUCCESS;
1630
1631            case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
1632                zend_compare_arrays(result, op1, op2 TSRMLS_CC);
1633                return SUCCESS;
1634
1635            case TYPE_PAIR(IS_NULL, IS_NULL):
1636                ZVAL_LONG(result, 0);
1637                return SUCCESS;
1638
1639            case TYPE_PAIR(IS_NULL, IS_BOOL):
1640                ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0);
1641                return SUCCESS;
1642
1643            case TYPE_PAIR(IS_BOOL, IS_NULL):
1644                ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0);
1645                return SUCCESS;
1646
1647            case TYPE_PAIR(IS_BOOL, IS_BOOL):
1648                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1649                return SUCCESS;
1650
1651            case TYPE_PAIR(IS_STRING, IS_STRING):
1652                zendi_smart_strcmp(result, op1, op2);
1653                return SUCCESS;
1654
1655            case TYPE_PAIR(IS_NULL, IS_STRING):
1656                ZVAL_LONG(result, zend_binary_strcmp("", 0, Z_STRVAL_P(op2), Z_STRLEN_P(op2)));
1657                return SUCCESS;
1658
1659            case TYPE_PAIR(IS_STRING, IS_NULL):
1660                ZVAL_LONG(result, zend_binary_strcmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), "", 0));
1661                return SUCCESS;
1662
1663            case TYPE_PAIR(IS_OBJECT, IS_NULL):
1664                ZVAL_LONG(result, 1);
1665                return SUCCESS;
1666
1667            case TYPE_PAIR(IS_NULL, IS_OBJECT):
1668                ZVAL_LONG(result, -1);
1669                return SUCCESS;
1670
1671            default:
1672                if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, compare)) {
1673                    return Z_OBJ_HANDLER_P(op1, compare)(result, op1, op2 TSRMLS_CC);
1674                } else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, compare)) {
1675                    return Z_OBJ_HANDLER_P(op2, compare)(result, op1, op2 TSRMLS_CC);
1676                }
1677
1678                if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) == IS_OBJECT) {
1679                    if (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2)) {
1680                        /* object handles are identical, apparently this is the same object */
1681                        ZVAL_LONG(result, 0);
1682                        return SUCCESS;
1683                    }
1684                    if (Z_OBJ_HANDLER_P(op1, compare_objects) == Z_OBJ_HANDLER_P(op2, compare_objects)) {
1685                        ZVAL_LONG(result, Z_OBJ_HANDLER_P(op1, compare_objects)(op1, op2 TSRMLS_CC));
1686                        return SUCCESS;
1687                    }
1688                }
1689                if (Z_TYPE_P(op1) == IS_OBJECT) {
1690                    if (Z_OBJ_HT_P(op1)->get) {
1691                        op_free = Z_OBJ_HT_P(op1)->get(op1 TSRMLS_CC);
1692                        ret = compare_function(result, op_free, op2 TSRMLS_CC);
1693                        zend_free_obj_get_result(op_free TSRMLS_CC);
1694                        return ret;
1695                    } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) {
1696                        ALLOC_INIT_ZVAL(op_free);
1697                        if (Z_OBJ_HT_P(op1)->cast_object(op1, op_free, Z_TYPE_P(op2) TSRMLS_CC) == FAILURE) {
1698                            ZVAL_LONG(result, 1);
1699                            zend_free_obj_get_result(op_free TSRMLS_CC);
1700                            return SUCCESS;
1701                        }
1702                        ret = compare_function(result, op_free, op2 TSRMLS_CC);
1703                        zend_free_obj_get_result(op_free TSRMLS_CC);
1704                        return ret;
1705                    }
1706                }
1707                if (Z_TYPE_P(op2) == IS_OBJECT) {
1708                    if (Z_OBJ_HT_P(op2)->get) {
1709                        op_free = Z_OBJ_HT_P(op2)->get(op2 TSRMLS_CC);
1710                        ret = compare_function(result, op1, op_free TSRMLS_CC);
1711                        zend_free_obj_get_result(op_free TSRMLS_CC);
1712                        return ret;
1713                    } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) {
1714                        ALLOC_INIT_ZVAL(op_free);
1715                        if (Z_OBJ_HT_P(op2)->cast_object(op2, op_free, Z_TYPE_P(op1) TSRMLS_CC) == FAILURE) {
1716                            ZVAL_LONG(result, -1);
1717                            zend_free_obj_get_result(op_free TSRMLS_CC);
1718                            return SUCCESS;
1719                        }
1720                        ret = compare_function(result, op1, op_free TSRMLS_CC);
1721                        zend_free_obj_get_result(op_free TSRMLS_CC);
1722                        return ret;
1723                    } else if (Z_TYPE_P(op1) == IS_OBJECT) {
1724                        ZVAL_LONG(result, 1);
1725                        return SUCCESS;
1726                    }
1727                }
1728                if (!converted) {
1729                    if (Z_TYPE_P(op1) == IS_NULL) {
1730                        zendi_convert_to_boolean(op2, op2_copy, result);
1731                        ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0);
1732                        return SUCCESS;
1733                    } else if (Z_TYPE_P(op2) == IS_NULL) {
1734                        zendi_convert_to_boolean(op1, op1_copy, result);
1735                        ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0);
1736                        return SUCCESS;
1737                    } else if (Z_TYPE_P(op1) == IS_BOOL) {
1738                        zendi_convert_to_boolean(op2, op2_copy, result);
1739                        ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1740                        return SUCCESS;
1741                    } else if (Z_TYPE_P(op2) == IS_BOOL) {
1742                        zendi_convert_to_boolean(op1, op1_copy, result);
1743                        ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1744                        return SUCCESS;
1745                    } else {
1746                        zendi_convert_scalar_to_number(op1, op1_copy, result);
1747                        zendi_convert_scalar_to_number(op2, op2_copy, result);
1748                        converted = 1;
1749                    }
1750                } else if (Z_TYPE_P(op1)==IS_ARRAY) {
1751                    ZVAL_LONG(result, 1);
1752                    return SUCCESS;
1753                } else if (Z_TYPE_P(op2)==IS_ARRAY) {
1754                    ZVAL_LONG(result, -1);
1755                    return SUCCESS;
1756                } else if (Z_TYPE_P(op1)==IS_OBJECT) {
1757                    ZVAL_LONG(result, 1);
1758                    return SUCCESS;
1759                } else if (Z_TYPE_P(op2)==IS_OBJECT) {
1760                    ZVAL_LONG(result, -1);
1761                    return SUCCESS;
1762                } else {
1763                    ZVAL_LONG(result, 0);
1764                    return FAILURE;
1765                }
1766        }
1767    }
1768}
1769/* }}} */
1770
1771static int hash_zval_identical_function(const zval **z1, const zval **z2) /* {{{ */
1772{
1773    zval result;
1774    TSRMLS_FETCH();
1775
1776    /* is_identical_function() returns 1 in case of identity and 0 in case
1777     * of a difference;
1778     * whereas this comparison function is expected to return 0 on identity,
1779     * and non zero otherwise.
1780     */
1781    if (is_identical_function(&result, (zval *) *z1, (zval *) *z2 TSRMLS_CC)==FAILURE) {
1782        return 1;
1783    }
1784    return !Z_LVAL(result);
1785}
1786/* }}} */
1787
1788ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1789{
1790    Z_TYPE_P(result) = IS_BOOL;
1791    if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
1792        Z_LVAL_P(result) = 0;
1793        return SUCCESS;
1794    }
1795    switch (Z_TYPE_P(op1)) {
1796        case IS_NULL:
1797            Z_LVAL_P(result) = 1;
1798            break;
1799        case IS_BOOL:
1800        case IS_LONG:
1801        case IS_RESOURCE:
1802            Z_LVAL_P(result) = (Z_LVAL_P(op1) == Z_LVAL_P(op2));
1803            break;
1804        case IS_DOUBLE:
1805            Z_LVAL_P(result) = (Z_DVAL_P(op1) == Z_DVAL_P(op2));
1806            break;
1807        case IS_STRING:
1808            Z_LVAL_P(result) = ((Z_STRLEN_P(op1) == Z_STRLEN_P(op2))
1809                && (!memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1))));
1810            break;
1811        case IS_ARRAY:
1812            Z_LVAL_P(result) = (Z_ARRVAL_P(op1) == Z_ARRVAL_P(op2) ||
1813                zend_hash_compare(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2), (compare_func_t) hash_zval_identical_function, 1 TSRMLS_CC)==0);
1814            break;
1815        case IS_OBJECT:
1816            if (Z_OBJ_HT_P(op1) == Z_OBJ_HT_P(op2)) {
1817                Z_LVAL_P(result) = (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2));
1818            } else {
1819                Z_LVAL_P(result) = 0;
1820            }
1821            break;
1822        default:
1823            Z_LVAL_P(result) = 0;
1824            return FAILURE;
1825    }
1826    return SUCCESS;
1827}
1828/* }}} */
1829
1830ZEND_API int is_not_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1831{
1832    if (is_identical_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1833        return FAILURE;
1834    }
1835    Z_LVAL_P(result) = !Z_LVAL_P(result);
1836    return SUCCESS;
1837}
1838/* }}} */
1839
1840ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1841{
1842    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1843        return FAILURE;
1844    }
1845    ZVAL_BOOL(result, (Z_LVAL_P(result) == 0));
1846    return SUCCESS;
1847}
1848/* }}} */
1849
1850ZEND_API int is_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1851{
1852    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1853        return FAILURE;
1854    }
1855    ZVAL_BOOL(result, (Z_LVAL_P(result) != 0));
1856    return SUCCESS;
1857}
1858/* }}} */
1859
1860ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1861{
1862    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1863        return FAILURE;
1864    }
1865    ZVAL_BOOL(result, (Z_LVAL_P(result) < 0));
1866    return SUCCESS;
1867}
1868/* }}} */
1869
1870ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1871{
1872    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1873        return FAILURE;
1874    }
1875    ZVAL_BOOL(result, (Z_LVAL_P(result) <= 0));
1876    return SUCCESS;
1877}
1878/* }}} */
1879
1880ZEND_API zend_bool instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool interfaces_only TSRMLS_DC) /* {{{ */
1881{
1882    zend_uint i;
1883
1884    for (i=0; i<instance_ce->num_interfaces; i++) {
1885        if (instanceof_function(instance_ce->interfaces[i], ce TSRMLS_CC)) {
1886            return 1;
1887        }
1888    }
1889    if (!interfaces_only) {
1890        while (instance_ce) {
1891            if (instance_ce == ce) {
1892                return 1;
1893            }
1894            instance_ce = instance_ce->parent;
1895        }
1896    }
1897
1898    return 0;
1899}
1900/* }}} */
1901
1902ZEND_API zend_bool instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce TSRMLS_DC) /* {{{ */
1903{
1904    return instanceof_function_ex(instance_ce, ce, 0 TSRMLS_CC);
1905}
1906/* }}} */
1907
1908#define LOWER_CASE 1
1909#define UPPER_CASE 2
1910#define NUMERIC 3
1911
1912static void increment_string(zval *str) /* {{{ */
1913{
1914    int carry=0;
1915    int pos=Z_STRLEN_P(str)-1;
1916    char *s=Z_STRVAL_P(str);
1917    char *t;
1918    int last=0; /* Shut up the compiler warning */
1919    int ch;
1920
1921    if (Z_STRLEN_P(str) == 0) {
1922        str_efree(Z_STRVAL_P(str));
1923        Z_STRVAL_P(str) = estrndup("1", sizeof("1")-1);
1924        Z_STRLEN_P(str) = 1;
1925        return;
1926    }
1927
1928    if (IS_INTERNED(s)) {
1929        Z_STRVAL_P(str) = s = estrndup(s, Z_STRLEN_P(str));
1930    }
1931
1932    while (pos >= 0) {
1933        ch = s[pos];
1934        if (ch >= 'a' && ch <= 'z') {
1935            if (ch == 'z') {
1936                s[pos] = 'a';
1937                carry=1;
1938            } else {
1939                s[pos]++;
1940                carry=0;
1941            }
1942            last=LOWER_CASE;
1943        } else if (ch >= 'A' && ch <= 'Z') {
1944            if (ch == 'Z') {
1945                s[pos] = 'A';
1946                carry=1;
1947            } else {
1948                s[pos]++;
1949                carry=0;
1950            }
1951            last=UPPER_CASE;
1952        } else if (ch >= '0' && ch <= '9') {
1953            if (ch == '9') {
1954                s[pos] = '0';
1955                carry=1;
1956            } else {
1957                s[pos]++;
1958                carry=0;
1959            }
1960            last = NUMERIC;
1961        } else {
1962            carry=0;
1963            break;
1964        }
1965        if (carry == 0) {
1966            break;
1967        }
1968        pos--;
1969    }
1970
1971    if (carry) {
1972        t = (char *) emalloc(Z_STRLEN_P(str)+1+1);
1973        memcpy(t+1, Z_STRVAL_P(str), Z_STRLEN_P(str));
1974        Z_STRLEN_P(str)++;
1975        t[Z_STRLEN_P(str)] = '\0';
1976        switch (last) {
1977            case NUMERIC:
1978                t[0] = '1';
1979                break;
1980            case UPPER_CASE:
1981                t[0] = 'A';
1982                break;
1983            case LOWER_CASE:
1984                t[0] = 'a';
1985                break;
1986        }
1987        str_efree(Z_STRVAL_P(str));
1988        Z_STRVAL_P(str) = t;
1989    }
1990}
1991/* }}} */
1992
1993ZEND_API int increment_function(zval *op1) /* {{{ */
1994{
1995    switch (Z_TYPE_P(op1)) {
1996        case IS_LONG:
1997            if (Z_LVAL_P(op1) == LONG_MAX) {
1998                /* switch to double */
1999                double d = (double)Z_LVAL_P(op1);
2000                ZVAL_DOUBLE(op1, d+1);
2001            } else {
2002            Z_LVAL_P(op1)++;
2003            }
2004            break;
2005        case IS_DOUBLE:
2006            Z_DVAL_P(op1) = Z_DVAL_P(op1) + 1;
2007            break;
2008        case IS_NULL:
2009            ZVAL_LONG(op1, 1);
2010            break;
2011        case IS_STRING: {
2012                long lval;
2013                double dval;
2014
2015                switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
2016                    case IS_LONG:
2017                        str_efree(Z_STRVAL_P(op1));
2018                        if (lval == LONG_MAX) {
2019                            /* switch to double */
2020                            double d = (double)lval;
2021                            ZVAL_DOUBLE(op1, d+1);
2022                        } else {
2023                            ZVAL_LONG(op1, lval+1);
2024                        }
2025                        break;
2026                    case IS_DOUBLE:
2027                        str_efree(Z_STRVAL_P(op1));
2028                        ZVAL_DOUBLE(op1, dval+1);
2029                        break;
2030                    default:
2031                        /* Perl style string increment */
2032                        increment_string(op1);
2033                        break;
2034                }
2035            }
2036            break;
2037        case IS_OBJECT:
2038            if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2039                zval *op2;
2040                int res;
2041                TSRMLS_FETCH();
2042
2043                MAKE_STD_ZVAL(op2);
2044                ZVAL_LONG(op2, 1);
2045                res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_ADD, op1, op1, op2 TSRMLS_CC);
2046                zval_ptr_dtor(&op2);
2047
2048                return res;
2049            }
2050            return FAILURE;
2051        default:
2052            return FAILURE;
2053    }
2054    return SUCCESS;
2055}
2056/* }}} */
2057
2058ZEND_API int decrement_function(zval *op1) /* {{{ */
2059{
2060    long lval;
2061    double dval;
2062
2063    switch (Z_TYPE_P(op1)) {
2064        case IS_LONG:
2065            if (Z_LVAL_P(op1) == LONG_MIN) {
2066                double d = (double)Z_LVAL_P(op1);
2067                ZVAL_DOUBLE(op1, d-1);
2068            } else {
2069            Z_LVAL_P(op1)--;
2070            }
2071            break;
2072        case IS_DOUBLE:
2073            Z_DVAL_P(op1) = Z_DVAL_P(op1) - 1;
2074            break;
2075        case IS_STRING:     /* Like perl we only support string increment */
2076            if (Z_STRLEN_P(op1) == 0) { /* consider as 0 */
2077                str_efree(Z_STRVAL_P(op1));
2078                ZVAL_LONG(op1, -1);
2079                break;
2080            }
2081            switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
2082                case IS_LONG:
2083                    str_efree(Z_STRVAL_P(op1));
2084                    if (lval == LONG_MIN) {
2085                        double d = (double)lval;
2086                        ZVAL_DOUBLE(op1, d-1);
2087                    } else {
2088                        ZVAL_LONG(op1, lval-1);
2089                    }
2090                    break;
2091                case IS_DOUBLE:
2092                    str_efree(Z_STRVAL_P(op1));
2093                    ZVAL_DOUBLE(op1, dval - 1);
2094                    break;
2095            }
2096            break;
2097        case IS_OBJECT:
2098            if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2099                zval *op2;
2100                int res;
2101                TSRMLS_FETCH();
2102
2103                MAKE_STD_ZVAL(op2);
2104                ZVAL_LONG(op2, 1);
2105                res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_SUB, op1, op1, op2 TSRMLS_CC);
2106                zval_ptr_dtor(&op2);
2107
2108                return res;
2109            }
2110            return FAILURE;
2111        default:
2112            return FAILURE;
2113    }
2114
2115    return SUCCESS;
2116}
2117/* }}} */
2118
2119ZEND_API int zval_is_true(zval *op) /* {{{ */
2120{
2121    convert_to_boolean(op);
2122    return (Z_LVAL_P(op) ? 1 : 0);
2123}
2124/* }}} */
2125
2126#ifdef ZEND_USE_TOLOWER_L
2127ZEND_API void zend_update_current_locale(void) /* {{{ */
2128{
2129    current_locale = _get_current_locale();
2130}
2131/* }}} */
2132#endif
2133
2134ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, unsigned int length) /* {{{ */
2135{
2136    register unsigned char *str = (unsigned char*)source;
2137    register unsigned char *result = (unsigned char*)dest;
2138    register unsigned char *end = str + length;
2139
2140    while (str < end) {
2141        *result++ = zend_tolower_ascii(*str++);
2142    }
2143    *result = '\0';
2144
2145    return dest;
2146}
2147/* }}} */
2148
2149ZEND_API char *zend_str_tolower_dup(const char *source, unsigned int length) /* {{{ */
2150{
2151    return zend_str_tolower_copy((char *)emalloc(length+1), source, length);
2152}
2153/* }}} */
2154
2155ZEND_API void zend_str_tolower(char *str, unsigned int length) /* {{{ */
2156{
2157    register unsigned char *p = (unsigned char*)str;
2158    register unsigned char *end = p + length;
2159
2160    while (p < end) {
2161        *p = zend_tolower_ascii(*p);
2162        p++;
2163    }
2164}
2165/* }}} */
2166
2167ZEND_API int zend_binary_strcmp(const char *s1, uint len1, const char *s2, uint len2) /* {{{ */
2168{
2169    int retval;
2170
2171    if (s1 == s2) {
2172        return 0;
2173    }
2174    retval = memcmp(s1, s2, MIN(len1, len2));
2175    if (!retval) {
2176        return (len1 - len2);
2177    } else {
2178        return retval;
2179    }
2180}
2181/* }}} */
2182
2183ZEND_API int zend_binary_strncmp(const char *s1, uint len1, const char *s2, uint len2, uint length) /* {{{ */
2184{
2185    int retval;
2186
2187    if (s1 == s2) {
2188        return 0;
2189    }
2190    retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
2191    if (!retval) {
2192        return (MIN(length, len1) - MIN(length, len2));
2193    } else {
2194        return retval;
2195    }
2196}
2197/* }}} */
2198
2199ZEND_API int zend_binary_strcasecmp(const char *s1, uint len1, const char *s2, uint len2) /* {{{ */
2200{
2201    int len;
2202    int c1, c2;
2203
2204    if (s1 == s2) {
2205        return 0;
2206    }
2207
2208    len = MIN(len1, len2);
2209    while (len--) {
2210        c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2211        c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2212        if (c1 != c2) {
2213            return c1 - c2;
2214        }
2215    }
2216
2217    return len1 - len2;
2218}
2219/* }}} */
2220
2221ZEND_API int zend_binary_strncasecmp(const char *s1, uint len1, const char *s2, uint len2, uint length) /* {{{ */
2222{
2223    int len;
2224    int c1, c2;
2225
2226    if (s1 == s2) {
2227        return 0;
2228    }
2229    len = MIN(length, MIN(len1, len2));
2230    while (len--) {
2231        c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2232        c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2233        if (c1 != c2) {
2234            return c1 - c2;
2235        }
2236    }
2237
2238    return MIN(length, len1) - MIN(length, len2);
2239}
2240/* }}} */
2241
2242ZEND_API int zend_binary_strcasecmp_l(const char *s1, uint len1, const char *s2, uint len2) /* {{{ */
2243{
2244    int len;
2245    int c1, c2;
2246
2247    if (s1 == s2) {
2248        return 0;
2249    }
2250
2251    len = MIN(len1, len2);
2252    while (len--) {
2253        c1 = zend_tolower((int)*(unsigned char *)s1++);
2254        c2 = zend_tolower((int)*(unsigned char *)s2++);
2255        if (c1 != c2) {
2256            return c1 - c2;
2257        }
2258    }
2259
2260    return len1 - len2;
2261}
2262/* }}} */
2263
2264ZEND_API int zend_binary_strncasecmp_l(const char *s1, uint len1, const char *s2, uint len2, uint length) /* {{{ */
2265{
2266    int len;
2267    int c1, c2;
2268
2269    if (s1 == s2) {
2270        return 0;
2271    }
2272    len = MIN(length, MIN(len1, len2));
2273    while (len--) {
2274        c1 = zend_tolower((int)*(unsigned char *)s1++);
2275        c2 = zend_tolower((int)*(unsigned char *)s2++);
2276        if (c1 != c2) {
2277            return c1 - c2;
2278        }
2279    }
2280
2281    return MIN(length, len1) - MIN(length, len2);
2282}
2283/* }}} */
2284
2285ZEND_API int zend_binary_zval_strcmp(zval *s1, zval *s2) /* {{{ */
2286{
2287    return zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2288}
2289/* }}} */
2290
2291ZEND_API int zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2292{
2293    return zend_binary_strncmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
2294}
2295/* }}} */
2296
2297ZEND_API int zend_binary_zval_strcasecmp(zval *s1, zval *s2) /* {{{ */
2298{
2299    return zend_binary_strcasecmp_l(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2300}
2301/* }}} */
2302
2303ZEND_API int zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2304{
2305    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));
2306}
2307/* }}} */
2308
2309ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2) /* {{{ */
2310{
2311    int ret1, ret2;
2312    int oflow1, oflow2;
2313    long lval1 = 0, lval2 = 0;
2314    double dval1 = 0.0, dval2 = 0.0;
2315
2316    if ((ret1=is_numeric_string_ex(Z_STRVAL_P(s1), Z_STRLEN_P(s1), &lval1, &dval1, 0, &oflow1)) &&
2317        (ret2=is_numeric_string_ex(Z_STRVAL_P(s2), Z_STRLEN_P(s2), &lval2, &dval2, 0, &oflow2))) {
2318#if ULONG_MAX == 0xFFFFFFFF
2319        if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
2320            ((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
2321            || (oflow1 == -1 && dval1 < -9007199254740991.))) {
2322#else
2323        if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
2324#endif
2325            /* both values are integers overflown to the same side, and the
2326             * double comparison may have resulted in crucial accuracy lost */
2327            goto string_cmp;
2328        }
2329        if ((ret1==IS_DOUBLE) || (ret2==IS_DOUBLE)) {
2330            if (ret1!=IS_DOUBLE) {
2331                if (oflow2) {
2332                    /* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
2333                    ZVAL_LONG(result, -1 * oflow2);
2334                    return;
2335                }
2336                dval1 = (double) lval1;
2337            } else if (ret2!=IS_DOUBLE) {
2338                if (oflow1) {
2339                    ZVAL_LONG(result, oflow1);
2340                    return;
2341                }
2342                dval2 = (double) lval2;
2343            } else if (dval1 == dval2 && !zend_finite(dval1)) {
2344                /* Both values overflowed and have the same sign,
2345                 * so a numeric comparison would be inaccurate */
2346                goto string_cmp;
2347            }
2348            Z_DVAL_P(result) = dval1 - dval2;
2349            ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
2350        } else { /* they both have to be long's */
2351            ZVAL_LONG(result, lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0));
2352        }
2353    } else {
2354string_cmp:
2355        Z_LVAL_P(result) = zend_binary_zval_strcmp(s1, s2);
2356        ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(result)));
2357    }
2358}
2359/* }}} */
2360
2361static int hash_zval_compare_function(const zval **z1, const zval **z2 TSRMLS_DC) /* {{{ */
2362{
2363    zval result;
2364
2365    if (compare_function(&result, (zval *) *z1, (zval *) *z2 TSRMLS_CC)==FAILURE) {
2366        return 1;
2367    }
2368    return Z_LVAL(result);
2369}
2370/* }}} */
2371
2372ZEND_API int zend_compare_symbol_tables_i(HashTable *ht1, HashTable *ht2 TSRMLS_DC) /* {{{ */
2373{
2374    return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0 TSRMLS_CC);
2375}
2376/* }}} */
2377
2378ZEND_API void zend_compare_symbol_tables(zval *result, HashTable *ht1, HashTable *ht2 TSRMLS_DC) /* {{{ */
2379{
2380    ZVAL_LONG(result, ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0 TSRMLS_CC));
2381}
2382/* }}} */
2383
2384ZEND_API void zend_compare_arrays(zval *result, zval *a1, zval *a2 TSRMLS_DC) /* {{{ */
2385{
2386    zend_compare_symbol_tables(result, Z_ARRVAL_P(a1), Z_ARRVAL_P(a2) TSRMLS_CC);
2387}
2388/* }}} */
2389
2390ZEND_API void zend_compare_objects(zval *result, zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
2391{
2392    Z_TYPE_P(result) = IS_LONG;
2393
2394    if (Z_OBJ_HANDLE_P(o1) == Z_OBJ_HANDLE_P(o2)) {
2395        Z_LVAL_P(result) = 0;
2396        return;
2397    }
2398
2399    if (Z_OBJ_HT_P(o1)->compare_objects == NULL) {
2400        Z_LVAL_P(result) = 1;
2401    } else {
2402        Z_LVAL_P(result) = Z_OBJ_HT_P(o1)->compare_objects(o1, o2 TSRMLS_CC);
2403    }
2404}
2405/* }}} */
2406
2407ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) /* {{{ */
2408{
2409    TSRMLS_FETCH();
2410
2411    Z_STRLEN_P(op) = zend_spprintf(&Z_STRVAL_P(op), 0, "%.*G", (int) EG(precision), (double)Z_DVAL_P(op));
2412}
2413/* }}} */
2414
2415/*
2416 * Local variables:
2417 * tab-width: 4
2418 * c-basic-offset: 4
2419 * indent-tabs-mode: t
2420 * End:
2421 */
2422