1/*
2   +----------------------------------------------------------------------+
3   | Zend Engine                                                          |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1998-2014 Zend Technologies Ltd. (http://www.zend.com) |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 2.00 of the Zend license,     |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.zend.com/license/2_00.txt.                                |
11   | If you did not receive a copy of the Zend license and are unable to  |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@zend.com so we can mail you a copy immediately.              |
14   +----------------------------------------------------------------------+
15   | Authors: Andi Gutmans <andi@zend.com>                                |
16   |          Zeev Suraski <zeev@zend.com>                                |
17   +----------------------------------------------------------------------+
18*/
19
20/* $Id$ */
21
22#include <ctype.h>
23
24#include "zend.h"
25#include "zend_operators.h"
26#include "zend_variables.h"
27#include "zend_globals.h"
28#include "zend_list.h"
29#include "zend_API.h"
30#include "zend_strtod.h"
31#include "zend_exceptions.h"
32#include "zend_closures.h"
33
34#if ZEND_USE_TOLOWER_L
35#include <locale.h>
36static _locale_t current_locale = NULL;
37/* this is true global! may lead to strange effects on ZTS, but so may setlocale() */
38#define zend_tolower(c) _tolower_l(c, current_locale)
39#else
40#define zend_tolower(c) tolower(c)
41#endif
42
43#define TYPE_PAIR(t1,t2) (((t1) << 4) | (t2))
44
45static const unsigned char tolower_map[256] = {
460x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
470x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
480x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
490x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
500x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
510x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x5b,0x5c,0x5d,0x5e,0x5f,
520x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
530x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
540x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
550x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
560xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
570xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
580xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
590xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
600xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
610xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
62};
63
64#define zend_tolower_ascii(c) (tolower_map[(unsigned char)(c)])
65
66/**
67 * Functions using locale lowercase:
68        zend_binary_strncasecmp_l
69        zend_binary_strcasecmp_l
70        zend_binary_zval_strcasecmp
71        zend_binary_zval_strncasecmp
72        string_compare_function_ex
73        string_case_compare_function
74 * Functions using ascii lowercase:
75        zend_str_tolower_copy
76        zend_str_tolower_dup
77        zend_str_tolower
78        zend_binary_strcasecmp
79        zend_binary_strncasecmp
80 */
81
82ZEND_API int zend_atoi(const char *str, int str_len) /* {{{ */
83{
84    int retval;
85
86    if (!str_len) {
87        str_len = 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) = erealloc(Z_STRVAL_P(result), res_len+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 = (char *) emalloc(length + 1);
1467
1468        memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1));
1469        memcpy(buf + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1470        buf[length] = 0;
1471        ZVAL_STRINGL(result, buf, length, 0);
1472    }
1473    if (use_copy1) {
1474        zval_dtor(op1);
1475    }
1476    if (use_copy2) {
1477        zval_dtor(op2);
1478    }
1479    return SUCCESS;
1480}
1481/* }}} */
1482
1483ZEND_API int string_compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool case_insensitive TSRMLS_DC) /* {{{ */
1484{
1485    zval op1_copy, op2_copy;
1486    int use_copy1 = 0, use_copy2 = 0;
1487
1488    if (Z_TYPE_P(op1) != IS_STRING) {
1489        zend_make_printable_zval(op1, &op1_copy, &use_copy1);
1490    }
1491    if (Z_TYPE_P(op2) != IS_STRING) {
1492        zend_make_printable_zval(op2, &op2_copy, &use_copy2);
1493    }
1494
1495    if (use_copy1) {
1496        op1 = &op1_copy;
1497    }
1498    if (use_copy2) {
1499        op2 = &op2_copy;
1500    }
1501
1502    if (case_insensitive) {
1503        ZVAL_LONG(result, zend_binary_zval_strcasecmp(op1, op2));
1504    } else {
1505        ZVAL_LONG(result, zend_binary_zval_strcmp(op1, op2));
1506    }
1507
1508    if (use_copy1) {
1509        zval_dtor(op1);
1510    }
1511    if (use_copy2) {
1512        zval_dtor(op2);
1513    }
1514    return SUCCESS;
1515}
1516/* }}} */
1517
1518ZEND_API int string_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1519{
1520    return string_compare_function_ex(result, op1, op2, 0 TSRMLS_CC);
1521}
1522/* }}} */
1523
1524ZEND_API int string_case_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1525{
1526    return string_compare_function_ex(result, op1, op2, 1 TSRMLS_CC);
1527}
1528/* }}} */
1529
1530#if HAVE_STRCOLL
1531ZEND_API int string_locale_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1532{
1533    zval op1_copy, op2_copy;
1534    int use_copy1 = 0, use_copy2 = 0;
1535
1536    if (Z_TYPE_P(op1) != IS_STRING) {
1537        zend_make_printable_zval(op1, &op1_copy, &use_copy1);
1538    }
1539    if (Z_TYPE_P(op2) != IS_STRING) {
1540        zend_make_printable_zval(op2, &op2_copy, &use_copy2);
1541    }
1542
1543    if (use_copy1) {
1544        op1 = &op1_copy;
1545    }
1546    if (use_copy2) {
1547        op2 = &op2_copy;
1548    }
1549
1550    ZVAL_LONG(result, strcoll(Z_STRVAL_P(op1), Z_STRVAL_P(op2)));
1551
1552    if (use_copy1) {
1553        zval_dtor(op1);
1554    }
1555    if (use_copy2) {
1556        zval_dtor(op2);
1557    }
1558    return SUCCESS;
1559}
1560/* }}} */
1561#endif
1562
1563ZEND_API int numeric_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1564{
1565    zval op1_copy, op2_copy;
1566
1567    op1_copy = *op1;
1568    zval_copy_ctor(&op1_copy);
1569
1570    op2_copy = *op2;
1571    zval_copy_ctor(&op2_copy);
1572
1573    convert_to_double(&op1_copy);
1574    convert_to_double(&op2_copy);
1575
1576    ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL(op1_copy)-Z_DVAL(op2_copy)));
1577
1578    return SUCCESS;
1579}
1580/* }}} */
1581
1582static inline void zend_free_obj_get_result(zval *op TSRMLS_DC) /* {{{ */
1583{
1584    if (Z_REFCOUNT_P(op) == 0) {
1585        GC_REMOVE_ZVAL_FROM_BUFFER(op);
1586        zval_dtor(op);
1587        FREE_ZVAL(op);
1588    } else {
1589        zval_ptr_dtor(&op);
1590    }
1591}
1592/* }}} */
1593
1594ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1595{
1596    int ret;
1597    int converted = 0;
1598    zval op1_copy, op2_copy;
1599    zval *op_free;
1600
1601    while (1) {
1602        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
1603            case TYPE_PAIR(IS_LONG, IS_LONG):
1604                ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0));
1605                return SUCCESS;
1606
1607            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1608                Z_DVAL_P(result) = Z_DVAL_P(op1) - (double)Z_LVAL_P(op2);
1609                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1610                return SUCCESS;
1611
1612            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1613                Z_DVAL_P(result) = (double)Z_LVAL_P(op1) - Z_DVAL_P(op2);
1614                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1615                return SUCCESS;
1616
1617            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1618                if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
1619                    ZVAL_LONG(result, 0);
1620                } else {
1621                    Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2);
1622                    ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1623                }
1624                return SUCCESS;
1625
1626            case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
1627                zend_compare_arrays(result, op1, op2 TSRMLS_CC);
1628                return SUCCESS;
1629
1630            case TYPE_PAIR(IS_NULL, IS_NULL):
1631                ZVAL_LONG(result, 0);
1632                return SUCCESS;
1633
1634            case TYPE_PAIR(IS_NULL, IS_BOOL):
1635                ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0);
1636                return SUCCESS;
1637
1638            case TYPE_PAIR(IS_BOOL, IS_NULL):
1639                ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0);
1640                return SUCCESS;
1641
1642            case TYPE_PAIR(IS_BOOL, IS_BOOL):
1643                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1644                return SUCCESS;
1645
1646            case TYPE_PAIR(IS_STRING, IS_STRING):
1647                zendi_smart_strcmp(result, op1, op2);
1648                return SUCCESS;
1649
1650            case TYPE_PAIR(IS_NULL, IS_STRING):
1651                ZVAL_LONG(result, zend_binary_strcmp("", 0, Z_STRVAL_P(op2), Z_STRLEN_P(op2)));
1652                return SUCCESS;
1653
1654            case TYPE_PAIR(IS_STRING, IS_NULL):
1655                ZVAL_LONG(result, zend_binary_strcmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), "", 0));
1656                return SUCCESS;
1657
1658            case TYPE_PAIR(IS_OBJECT, IS_NULL):
1659                ZVAL_LONG(result, 1);
1660                return SUCCESS;
1661
1662            case TYPE_PAIR(IS_NULL, IS_OBJECT):
1663                ZVAL_LONG(result, -1);
1664                return SUCCESS;
1665
1666            default:
1667                if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, compare)) {
1668                    return Z_OBJ_HANDLER_P(op1, compare)(result, op1, op2 TSRMLS_CC);
1669                } else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, compare)) {
1670                    return Z_OBJ_HANDLER_P(op2, compare)(result, op1, op2 TSRMLS_CC);
1671                }
1672
1673                if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) == IS_OBJECT) {
1674                    if (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2)) {
1675                        /* object handles are identical, apparently this is the same object */
1676                        ZVAL_LONG(result, 0);
1677                        return SUCCESS;
1678                    }
1679                    if (Z_OBJ_HANDLER_P(op1, compare_objects) == Z_OBJ_HANDLER_P(op2, compare_objects)) {
1680                        ZVAL_LONG(result, Z_OBJ_HANDLER_P(op1, compare_objects)(op1, op2 TSRMLS_CC));
1681                        return SUCCESS;
1682                    }
1683                }
1684                if (Z_TYPE_P(op1) == IS_OBJECT) {
1685                    if (Z_OBJ_HT_P(op1)->get) {
1686                        op_free = Z_OBJ_HT_P(op1)->get(op1 TSRMLS_CC);
1687                        ret = compare_function(result, op_free, op2 TSRMLS_CC);
1688                        zend_free_obj_get_result(op_free TSRMLS_CC);
1689                        return ret;
1690                    } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) {
1691                        ALLOC_INIT_ZVAL(op_free);
1692                        if (Z_OBJ_HT_P(op1)->cast_object(op1, op_free, Z_TYPE_P(op2) TSRMLS_CC) == FAILURE) {
1693                            ZVAL_LONG(result, 1);
1694                            zend_free_obj_get_result(op_free TSRMLS_CC);
1695                            return SUCCESS;
1696                        }
1697                        ret = compare_function(result, op_free, op2 TSRMLS_CC);
1698                        zend_free_obj_get_result(op_free TSRMLS_CC);
1699                        return ret;
1700                    }
1701                }
1702                if (Z_TYPE_P(op2) == IS_OBJECT) {
1703                    if (Z_OBJ_HT_P(op2)->get) {
1704                        op_free = Z_OBJ_HT_P(op2)->get(op2 TSRMLS_CC);
1705                        ret = compare_function(result, op1, op_free TSRMLS_CC);
1706                        zend_free_obj_get_result(op_free TSRMLS_CC);
1707                        return ret;
1708                    } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) {
1709                        ALLOC_INIT_ZVAL(op_free);
1710                        if (Z_OBJ_HT_P(op2)->cast_object(op2, op_free, Z_TYPE_P(op1) TSRMLS_CC) == FAILURE) {
1711                            ZVAL_LONG(result, -1);
1712                            zend_free_obj_get_result(op_free TSRMLS_CC);
1713                            return SUCCESS;
1714                        }
1715                        ret = compare_function(result, op1, op_free TSRMLS_CC);
1716                        zend_free_obj_get_result(op_free TSRMLS_CC);
1717                        return ret;
1718                    } else if (Z_TYPE_P(op1) == IS_OBJECT) {
1719                        ZVAL_LONG(result, 1);
1720                        return SUCCESS;
1721                    }
1722                }
1723                if (!converted) {
1724                    if (Z_TYPE_P(op1) == IS_NULL) {
1725                        zendi_convert_to_boolean(op2, op2_copy, result);
1726                        ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0);
1727                        return SUCCESS;
1728                    } else if (Z_TYPE_P(op2) == IS_NULL) {
1729                        zendi_convert_to_boolean(op1, op1_copy, result);
1730                        ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0);
1731                        return SUCCESS;
1732                    } else if (Z_TYPE_P(op1) == IS_BOOL) {
1733                        zendi_convert_to_boolean(op2, op2_copy, result);
1734                        ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1735                        return SUCCESS;
1736                    } else if (Z_TYPE_P(op2) == IS_BOOL) {
1737                        zendi_convert_to_boolean(op1, op1_copy, result);
1738                        ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1739                        return SUCCESS;
1740                    } else {
1741                        zendi_convert_scalar_to_number(op1, op1_copy, result);
1742                        zendi_convert_scalar_to_number(op2, op2_copy, result);
1743                        converted = 1;
1744                    }
1745                } else if (Z_TYPE_P(op1)==IS_ARRAY) {
1746                    ZVAL_LONG(result, 1);
1747                    return SUCCESS;
1748                } else if (Z_TYPE_P(op2)==IS_ARRAY) {
1749                    ZVAL_LONG(result, -1);
1750                    return SUCCESS;
1751                } else if (Z_TYPE_P(op1)==IS_OBJECT) {
1752                    ZVAL_LONG(result, 1);
1753                    return SUCCESS;
1754                } else if (Z_TYPE_P(op2)==IS_OBJECT) {
1755                    ZVAL_LONG(result, -1);
1756                    return SUCCESS;
1757                } else {
1758                    ZVAL_LONG(result, 0);
1759                    return FAILURE;
1760                }
1761        }
1762    }
1763}
1764/* }}} */
1765
1766static int hash_zval_identical_function(const zval **z1, const zval **z2) /* {{{ */
1767{
1768    zval result;
1769    TSRMLS_FETCH();
1770
1771    /* is_identical_function() returns 1 in case of identity and 0 in case
1772     * of a difference;
1773     * whereas this comparison function is expected to return 0 on identity,
1774     * and non zero otherwise.
1775     */
1776    if (is_identical_function(&result, (zval *) *z1, (zval *) *z2 TSRMLS_CC)==FAILURE) {
1777        return 1;
1778    }
1779    return !Z_LVAL(result);
1780}
1781/* }}} */
1782
1783ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1784{
1785    Z_TYPE_P(result) = IS_BOOL;
1786    if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
1787        Z_LVAL_P(result) = 0;
1788        return SUCCESS;
1789    }
1790    switch (Z_TYPE_P(op1)) {
1791        case IS_NULL:
1792            Z_LVAL_P(result) = 1;
1793            break;
1794        case IS_BOOL:
1795        case IS_LONG:
1796        case IS_RESOURCE:
1797            Z_LVAL_P(result) = (Z_LVAL_P(op1) == Z_LVAL_P(op2));
1798            break;
1799        case IS_DOUBLE:
1800            Z_LVAL_P(result) = (Z_DVAL_P(op1) == Z_DVAL_P(op2));
1801            break;
1802        case IS_STRING:
1803            Z_LVAL_P(result) = ((Z_STRLEN_P(op1) == Z_STRLEN_P(op2))
1804                && (!memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1))));
1805            break;
1806        case IS_ARRAY:
1807            Z_LVAL_P(result) = (Z_ARRVAL_P(op1) == Z_ARRVAL_P(op2) ||
1808                zend_hash_compare(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2), (compare_func_t) hash_zval_identical_function, 1 TSRMLS_CC)==0);
1809            break;
1810        case IS_OBJECT:
1811            if (Z_OBJ_HT_P(op1) == Z_OBJ_HT_P(op2)) {
1812                Z_LVAL_P(result) = (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2));
1813            } else {
1814                Z_LVAL_P(result) = 0;
1815            }
1816            break;
1817        default:
1818            Z_LVAL_P(result) = 0;
1819            return FAILURE;
1820    }
1821    return SUCCESS;
1822}
1823/* }}} */
1824
1825ZEND_API int is_not_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1826{
1827    if (is_identical_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1828        return FAILURE;
1829    }
1830    Z_LVAL_P(result) = !Z_LVAL_P(result);
1831    return SUCCESS;
1832}
1833/* }}} */
1834
1835ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1836{
1837    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1838        return FAILURE;
1839    }
1840    ZVAL_BOOL(result, (Z_LVAL_P(result) == 0));
1841    return SUCCESS;
1842}
1843/* }}} */
1844
1845ZEND_API int is_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1846{
1847    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1848        return FAILURE;
1849    }
1850    ZVAL_BOOL(result, (Z_LVAL_P(result) != 0));
1851    return SUCCESS;
1852}
1853/* }}} */
1854
1855ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1856{
1857    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1858        return FAILURE;
1859    }
1860    ZVAL_BOOL(result, (Z_LVAL_P(result) < 0));
1861    return SUCCESS;
1862}
1863/* }}} */
1864
1865ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1866{
1867    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1868        return FAILURE;
1869    }
1870    ZVAL_BOOL(result, (Z_LVAL_P(result) <= 0));
1871    return SUCCESS;
1872}
1873/* }}} */
1874
1875ZEND_API zend_bool instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool interfaces_only TSRMLS_DC) /* {{{ */
1876{
1877    zend_uint i;
1878
1879    for (i=0; i<instance_ce->num_interfaces; i++) {
1880        if (instanceof_function(instance_ce->interfaces[i], ce TSRMLS_CC)) {
1881            return 1;
1882        }
1883    }
1884    if (!interfaces_only) {
1885        while (instance_ce) {
1886            if (instance_ce == ce) {
1887                return 1;
1888            }
1889            instance_ce = instance_ce->parent;
1890        }
1891    }
1892
1893    return 0;
1894}
1895/* }}} */
1896
1897ZEND_API zend_bool instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce TSRMLS_DC) /* {{{ */
1898{
1899    return instanceof_function_ex(instance_ce, ce, 0 TSRMLS_CC);
1900}
1901/* }}} */
1902
1903#define LOWER_CASE 1
1904#define UPPER_CASE 2
1905#define NUMERIC 3
1906
1907static void increment_string(zval *str) /* {{{ */
1908{
1909    int carry=0;
1910    int pos=Z_STRLEN_P(str)-1;
1911    char *s=Z_STRVAL_P(str);
1912    char *t;
1913    int last=0; /* Shut up the compiler warning */
1914    int ch;
1915
1916    if (Z_STRLEN_P(str) == 0) {
1917        str_efree(Z_STRVAL_P(str));
1918        Z_STRVAL_P(str) = estrndup("1", sizeof("1")-1);
1919        Z_STRLEN_P(str) = 1;
1920        return;
1921    }
1922
1923    if (IS_INTERNED(s)) {
1924        Z_STRVAL_P(str) = s = estrndup(s, Z_STRLEN_P(str));
1925    }
1926
1927    while (pos >= 0) {
1928        ch = s[pos];
1929        if (ch >= 'a' && ch <= 'z') {
1930            if (ch == 'z') {
1931                s[pos] = 'a';
1932                carry=1;
1933            } else {
1934                s[pos]++;
1935                carry=0;
1936            }
1937            last=LOWER_CASE;
1938        } else if (ch >= 'A' && ch <= 'Z') {
1939            if (ch == 'Z') {
1940                s[pos] = 'A';
1941                carry=1;
1942            } else {
1943                s[pos]++;
1944                carry=0;
1945            }
1946            last=UPPER_CASE;
1947        } else if (ch >= '0' && ch <= '9') {
1948            if (ch == '9') {
1949                s[pos] = '0';
1950                carry=1;
1951            } else {
1952                s[pos]++;
1953                carry=0;
1954            }
1955            last = NUMERIC;
1956        } else {
1957            carry=0;
1958            break;
1959        }
1960        if (carry == 0) {
1961            break;
1962        }
1963        pos--;
1964    }
1965
1966    if (carry) {
1967        t = (char *) emalloc(Z_STRLEN_P(str)+1+1);
1968        memcpy(t+1, Z_STRVAL_P(str), Z_STRLEN_P(str));
1969        Z_STRLEN_P(str)++;
1970        t[Z_STRLEN_P(str)] = '\0';
1971        switch (last) {
1972            case NUMERIC:
1973                t[0] = '1';
1974                break;
1975            case UPPER_CASE:
1976                t[0] = 'A';
1977                break;
1978            case LOWER_CASE:
1979                t[0] = 'a';
1980                break;
1981        }
1982        str_efree(Z_STRVAL_P(str));
1983        Z_STRVAL_P(str) = t;
1984    }
1985}
1986/* }}} */
1987
1988ZEND_API int increment_function(zval *op1) /* {{{ */
1989{
1990    switch (Z_TYPE_P(op1)) {
1991        case IS_LONG:
1992            if (Z_LVAL_P(op1) == LONG_MAX) {
1993                /* switch to double */
1994                double d = (double)Z_LVAL_P(op1);
1995                ZVAL_DOUBLE(op1, d+1);
1996            } else {
1997            Z_LVAL_P(op1)++;
1998            }
1999            break;
2000        case IS_DOUBLE:
2001            Z_DVAL_P(op1) = Z_DVAL_P(op1) + 1;
2002            break;
2003        case IS_NULL:
2004            ZVAL_LONG(op1, 1);
2005            break;
2006        case IS_STRING: {
2007                long lval;
2008                double dval;
2009
2010                switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
2011                    case IS_LONG:
2012                        str_efree(Z_STRVAL_P(op1));
2013                        if (lval == LONG_MAX) {
2014                            /* switch to double */
2015                            double d = (double)lval;
2016                            ZVAL_DOUBLE(op1, d+1);
2017                        } else {
2018                            ZVAL_LONG(op1, lval+1);
2019                        }
2020                        break;
2021                    case IS_DOUBLE:
2022                        str_efree(Z_STRVAL_P(op1));
2023                        ZVAL_DOUBLE(op1, dval+1);
2024                        break;
2025                    default:
2026                        /* Perl style string increment */
2027                        increment_string(op1);
2028                        break;
2029                }
2030            }
2031            break;
2032        case IS_OBJECT:
2033            if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2034                zval *op2;
2035                int res;
2036                TSRMLS_FETCH();
2037
2038                MAKE_STD_ZVAL(op2);
2039                ZVAL_LONG(op2, 1);
2040                res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_ADD, op1, op1, op2 TSRMLS_CC);
2041                zval_ptr_dtor(&op2);
2042
2043                return res;
2044            }
2045            return FAILURE;
2046        default:
2047            return FAILURE;
2048    }
2049    return SUCCESS;
2050}
2051/* }}} */
2052
2053ZEND_API int decrement_function(zval *op1) /* {{{ */
2054{
2055    long lval;
2056    double dval;
2057
2058    switch (Z_TYPE_P(op1)) {
2059        case IS_LONG:
2060            if (Z_LVAL_P(op1) == LONG_MIN) {
2061                double d = (double)Z_LVAL_P(op1);
2062                ZVAL_DOUBLE(op1, d-1);
2063            } else {
2064            Z_LVAL_P(op1)--;
2065            }
2066            break;
2067        case IS_DOUBLE:
2068            Z_DVAL_P(op1) = Z_DVAL_P(op1) - 1;
2069            break;
2070        case IS_STRING:     /* Like perl we only support string increment */
2071            if (Z_STRLEN_P(op1) == 0) { /* consider as 0 */
2072                str_efree(Z_STRVAL_P(op1));
2073                ZVAL_LONG(op1, -1);
2074                break;
2075            }
2076            switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
2077                case IS_LONG:
2078                    str_efree(Z_STRVAL_P(op1));
2079                    if (lval == LONG_MIN) {
2080                        double d = (double)lval;
2081                        ZVAL_DOUBLE(op1, d-1);
2082                    } else {
2083                        ZVAL_LONG(op1, lval-1);
2084                    }
2085                    break;
2086                case IS_DOUBLE:
2087                    str_efree(Z_STRVAL_P(op1));
2088                    ZVAL_DOUBLE(op1, dval - 1);
2089                    break;
2090            }
2091            break;
2092        case IS_OBJECT:
2093            if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2094                zval *op2;
2095                int res;
2096                TSRMLS_FETCH();
2097
2098                MAKE_STD_ZVAL(op2);
2099                ZVAL_LONG(op2, 1);
2100                res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_SUB, op1, op1, op2 TSRMLS_CC);
2101                zval_ptr_dtor(&op2);
2102
2103                return res;
2104            }
2105            return FAILURE;
2106        default:
2107            return FAILURE;
2108    }
2109
2110    return SUCCESS;
2111}
2112/* }}} */
2113
2114ZEND_API int zval_is_true(zval *op) /* {{{ */
2115{
2116    convert_to_boolean(op);
2117    return (Z_LVAL_P(op) ? 1 : 0);
2118}
2119/* }}} */
2120
2121#ifdef ZEND_USE_TOLOWER_L
2122ZEND_API void zend_update_current_locale(void) /* {{{ */
2123{
2124    current_locale = _get_current_locale();
2125}
2126/* }}} */
2127#endif
2128
2129ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, unsigned int length) /* {{{ */
2130{
2131    register unsigned char *str = (unsigned char*)source;
2132    register unsigned char *result = (unsigned char*)dest;
2133    register unsigned char *end = str + length;
2134
2135    while (str < end) {
2136        *result++ = zend_tolower_ascii(*str++);
2137    }
2138    *result = '\0';
2139
2140    return dest;
2141}
2142/* }}} */
2143
2144ZEND_API char *zend_str_tolower_dup(const char *source, unsigned int length) /* {{{ */
2145{
2146    return zend_str_tolower_copy((char *)emalloc(length+1), source, length);
2147}
2148/* }}} */
2149
2150ZEND_API void zend_str_tolower(char *str, unsigned int length) /* {{{ */
2151{
2152    register unsigned char *p = (unsigned char*)str;
2153    register unsigned char *end = p + length;
2154
2155    while (p < end) {
2156        *p = zend_tolower_ascii(*p);
2157        p++;
2158    }
2159}
2160/* }}} */
2161
2162ZEND_API int zend_binary_strcmp(const char *s1, uint len1, const char *s2, uint len2) /* {{{ */
2163{
2164    int retval;
2165
2166    if (s1 == s2) {
2167        return 0;
2168    }
2169    retval = memcmp(s1, s2, MIN(len1, len2));
2170    if (!retval) {
2171        return (len1 - len2);
2172    } else {
2173        return retval;
2174    }
2175}
2176/* }}} */
2177
2178ZEND_API int zend_binary_strncmp(const char *s1, uint len1, const char *s2, uint len2, uint length) /* {{{ */
2179{
2180    int retval;
2181
2182    if (s1 == s2) {
2183        return 0;
2184    }
2185    retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
2186    if (!retval) {
2187        return (MIN(length, len1) - MIN(length, len2));
2188    } else {
2189        return retval;
2190    }
2191}
2192/* }}} */
2193
2194ZEND_API int zend_binary_strcasecmp(const char *s1, uint len1, const char *s2, uint len2) /* {{{ */
2195{
2196    int len;
2197    int c1, c2;
2198
2199    if (s1 == s2) {
2200        return 0;
2201    }
2202
2203    len = MIN(len1, len2);
2204    while (len--) {
2205        c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2206        c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2207        if (c1 != c2) {
2208            return c1 - c2;
2209        }
2210    }
2211
2212    return len1 - len2;
2213}
2214/* }}} */
2215
2216ZEND_API int zend_binary_strncasecmp(const char *s1, uint len1, const char *s2, uint len2, uint length) /* {{{ */
2217{
2218    int len;
2219    int c1, c2;
2220
2221    if (s1 == s2) {
2222        return 0;
2223    }
2224    len = MIN(length, MIN(len1, len2));
2225    while (len--) {
2226        c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2227        c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2228        if (c1 != c2) {
2229            return c1 - c2;
2230        }
2231    }
2232
2233    return MIN(length, len1) - MIN(length, len2);
2234}
2235/* }}} */
2236
2237ZEND_API int zend_binary_strcasecmp_l(const char *s1, uint len1, const char *s2, uint len2) /* {{{ */
2238{
2239    int len;
2240    int c1, c2;
2241
2242    if (s1 == s2) {
2243        return 0;
2244    }
2245
2246    len = MIN(len1, len2);
2247    while (len--) {
2248        c1 = zend_tolower((int)*(unsigned char *)s1++);
2249        c2 = zend_tolower((int)*(unsigned char *)s2++);
2250        if (c1 != c2) {
2251            return c1 - c2;
2252        }
2253    }
2254
2255    return len1 - len2;
2256}
2257/* }}} */
2258
2259ZEND_API int zend_binary_strncasecmp_l(const char *s1, uint len1, const char *s2, uint len2, uint length) /* {{{ */
2260{
2261    int len;
2262    int c1, c2;
2263
2264    if (s1 == s2) {
2265        return 0;
2266    }
2267    len = MIN(length, MIN(len1, len2));
2268    while (len--) {
2269        c1 = zend_tolower((int)*(unsigned char *)s1++);
2270        c2 = zend_tolower((int)*(unsigned char *)s2++);
2271        if (c1 != c2) {
2272            return c1 - c2;
2273        }
2274    }
2275
2276    return MIN(length, len1) - MIN(length, len2);
2277}
2278/* }}} */
2279
2280ZEND_API int zend_binary_zval_strcmp(zval *s1, zval *s2) /* {{{ */
2281{
2282    return zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2283}
2284/* }}} */
2285
2286ZEND_API int zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2287{
2288    return zend_binary_strncmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
2289}
2290/* }}} */
2291
2292ZEND_API int zend_binary_zval_strcasecmp(zval *s1, zval *s2) /* {{{ */
2293{
2294    return zend_binary_strcasecmp_l(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2295}
2296/* }}} */
2297
2298ZEND_API int zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2299{
2300    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));
2301}
2302/* }}} */
2303
2304ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2) /* {{{ */
2305{
2306    int ret1, ret2;
2307    int oflow1, oflow2;
2308    long lval1 = 0, lval2 = 0;
2309    double dval1 = 0.0, dval2 = 0.0;
2310
2311    if ((ret1=is_numeric_string_ex(Z_STRVAL_P(s1), Z_STRLEN_P(s1), &lval1, &dval1, 0, &oflow1)) &&
2312        (ret2=is_numeric_string_ex(Z_STRVAL_P(s2), Z_STRLEN_P(s2), &lval2, &dval2, 0, &oflow2))) {
2313#if ULONG_MAX == 0xFFFFFFFF
2314        if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
2315            ((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
2316            || (oflow1 == -1 && dval1 < -9007199254740991.))) {
2317#else
2318        if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
2319#endif
2320            /* both values are integers overflown to the same side, and the
2321             * double comparison may have resulted in crucial accuracy lost */
2322            goto string_cmp;
2323        }
2324        if ((ret1==IS_DOUBLE) || (ret2==IS_DOUBLE)) {
2325            if (ret1!=IS_DOUBLE) {
2326                if (oflow2) {
2327                    /* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
2328                    ZVAL_LONG(result, -1 * oflow2);
2329                    return;
2330                }
2331                dval1 = (double) lval1;
2332            } else if (ret2!=IS_DOUBLE) {
2333                if (oflow1) {
2334                    ZVAL_LONG(result, oflow1);
2335                    return;
2336                }
2337                dval2 = (double) lval2;
2338            } else if (dval1 == dval2 && !zend_finite(dval1)) {
2339                /* Both values overflowed and have the same sign,
2340                 * so a numeric comparison would be inaccurate */
2341                goto string_cmp;
2342            }
2343            Z_DVAL_P(result) = dval1 - dval2;
2344            ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
2345        } else { /* they both have to be long's */
2346            ZVAL_LONG(result, lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0));
2347        }
2348    } else {
2349string_cmp:
2350        Z_LVAL_P(result) = zend_binary_zval_strcmp(s1, s2);
2351        ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(result)));
2352    }
2353}
2354/* }}} */
2355
2356static int hash_zval_compare_function(const zval **z1, const zval **z2 TSRMLS_DC) /* {{{ */
2357{
2358    zval result;
2359
2360    if (compare_function(&result, (zval *) *z1, (zval *) *z2 TSRMLS_CC)==FAILURE) {
2361        return 1;
2362    }
2363    return Z_LVAL(result);
2364}
2365/* }}} */
2366
2367ZEND_API int zend_compare_symbol_tables_i(HashTable *ht1, HashTable *ht2 TSRMLS_DC) /* {{{ */
2368{
2369    return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0 TSRMLS_CC);
2370}
2371/* }}} */
2372
2373ZEND_API void zend_compare_symbol_tables(zval *result, HashTable *ht1, HashTable *ht2 TSRMLS_DC) /* {{{ */
2374{
2375    ZVAL_LONG(result, ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0 TSRMLS_CC));
2376}
2377/* }}} */
2378
2379ZEND_API void zend_compare_arrays(zval *result, zval *a1, zval *a2 TSRMLS_DC) /* {{{ */
2380{
2381    zend_compare_symbol_tables(result, Z_ARRVAL_P(a1), Z_ARRVAL_P(a2) TSRMLS_CC);
2382}
2383/* }}} */
2384
2385ZEND_API void zend_compare_objects(zval *result, zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
2386{
2387    Z_TYPE_P(result) = IS_LONG;
2388
2389    if (Z_OBJ_HANDLE_P(o1) == Z_OBJ_HANDLE_P(o2)) {
2390        Z_LVAL_P(result) = 0;
2391        return;
2392    }
2393
2394    if (Z_OBJ_HT_P(o1)->compare_objects == NULL) {
2395        Z_LVAL_P(result) = 1;
2396    } else {
2397        Z_LVAL_P(result) = Z_OBJ_HT_P(o1)->compare_objects(o1, o2 TSRMLS_CC);
2398    }
2399}
2400/* }}} */
2401
2402ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) /* {{{ */
2403{
2404    TSRMLS_FETCH();
2405
2406    Z_STRLEN_P(op) = zend_spprintf(&Z_STRVAL_P(op), 0, "%.*G", (int) EG(precision), (double)Z_DVAL_P(op));
2407}
2408/* }}} */
2409
2410/*
2411 * Local variables:
2412 * tab-width: 4
2413 * c-basic-offset: 4
2414 * indent-tabs-mode: t
2415 * End:
2416 */
2417