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
45ZEND_API int zend_atoi(const char *str, int str_len) /* {{{ */
46{
47    int retval;
48
49    if (!str_len) {
50        str_len = strlen(str);
51    }
52    retval = strtol(str, NULL, 0);
53    if (str_len>0) {
54        switch (str[str_len-1]) {
55            case 'g':
56            case 'G':
57                retval *= 1024;
58                /* break intentionally missing */
59            case 'm':
60            case 'M':
61                retval *= 1024;
62                /* break intentionally missing */
63            case 'k':
64            case 'K':
65                retval *= 1024;
66                break;
67        }
68    }
69    return retval;
70}
71/* }}} */
72
73ZEND_API long zend_atol(const char *str, int str_len) /* {{{ */
74{
75    long retval;
76
77    if (!str_len) {
78        str_len = strlen(str);
79    }
80    retval = strtol(str, NULL, 0);
81    if (str_len>0) {
82        switch (str[str_len-1]) {
83            case 'g':
84            case 'G':
85                retval *= 1024;
86                /* break intentionally missing */
87            case 'm':
88            case 'M':
89                retval *= 1024;
90                /* break intentionally missing */
91            case 'k':
92            case 'K':
93                retval *= 1024;
94                break;
95        }
96    }
97    return retval;
98}
99/* }}} */
100
101ZEND_API double zend_string_to_double(const char *number, zend_uint length) /* {{{ */
102{
103    double divisor = 10.0;
104    double result = 0.0;
105    double exponent;
106    const char *end = number+length;
107    const char *digit = number;
108
109    if (!length) {
110        return result;
111    }
112
113    while (digit < end) {
114        if ((*digit <= '9' && *digit >= '0')) {
115            result *= 10;
116            result += *digit - '0';
117        } else if (*digit == '.') {
118            digit++;
119            break;
120        } else if (toupper(*digit) == 'E') {
121            exponent = (double) atoi(digit+1);
122            result *= pow(10.0, exponent);
123            return result;
124        } else {
125            return result;
126        }
127        digit++;
128    }
129
130    while (digit < end) {
131        if ((*digit <= '9' && *digit >= '0')) {
132            result += (*digit - '0') / divisor;
133            divisor *= 10;
134        } else if (toupper(*digit) == 'E') {
135            exponent = (double) atoi(digit+1);
136            result *= pow(10.0, exponent);
137            return result;
138        } else {
139            return result;
140        }
141        digit++;
142    }
143    return result;
144}
145/* }}} */
146
147ZEND_API void convert_scalar_to_number(zval *op TSRMLS_DC) /* {{{ */
148{
149    switch (Z_TYPE_P(op)) {
150        case IS_STRING:
151            {
152                char *strval;
153
154                strval = Z_STRVAL_P(op);
155                if ((Z_TYPE_P(op)=is_numeric_string(strval, Z_STRLEN_P(op), &Z_LVAL_P(op), &Z_DVAL_P(op), 1)) == 0) {
156                    ZVAL_LONG(op, 0);
157                }
158                STR_FREE(strval);
159                break;
160            }
161        case IS_BOOL:
162            Z_TYPE_P(op) = IS_LONG;
163            break;
164        case IS_RESOURCE:
165            zend_list_delete(Z_LVAL_P(op));
166            Z_TYPE_P(op) = IS_LONG;
167            break;
168        case IS_OBJECT:
169            convert_to_long_base(op, 10);
170            break;
171        case IS_NULL:
172            ZVAL_LONG(op, 0);
173            break;
174    }
175}
176/* }}} */
177
178/* {{{ zendi_convert_scalar_to_number */
179#define zendi_convert_scalar_to_number(op, holder, result)          \
180    if (op==result) {                                               \
181        if (Z_TYPE_P(op) != IS_LONG) {                              \
182            convert_scalar_to_number(op TSRMLS_CC);                 \
183        }                                                           \
184    } else {                                                        \
185        switch (Z_TYPE_P(op)) {                                     \
186            case IS_STRING:                                         \
187                {                                                   \
188                    if ((Z_TYPE(holder)=is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &Z_LVAL(holder), &Z_DVAL(holder), 1)) == 0) { \
189                        ZVAL_LONG(&(holder), 0);                            \
190                    }                                                       \
191                    (op) = &(holder);                                       \
192                    break;                                                  \
193                }                                                           \
194            case IS_BOOL:                                                   \
195            case IS_RESOURCE:                                               \
196                ZVAL_LONG(&(holder), Z_LVAL_P(op));                         \
197                (op) = &(holder);                                           \
198                break;                                                      \
199            case IS_NULL:                                                   \
200                ZVAL_LONG(&(holder), 0);                                    \
201                (op) = &(holder);                                           \
202                break;                                                      \
203            case IS_OBJECT:                                                 \
204                (holder) = (*(op));                                         \
205                zval_copy_ctor(&(holder));                                  \
206                convert_to_long_base(&(holder), 10);                        \
207                if (Z_TYPE(holder) == IS_LONG) {                            \
208                    (op) = &(holder);                                       \
209                }                                                           \
210                break;                                                      \
211        }                                                                   \
212    }
213
214/* }}} */
215
216/* {{{ zendi_convert_to_long */
217#define zendi_convert_to_long(op, holder, result)                   \
218    if (op == result) {                                             \
219        convert_to_long(op);                                        \
220    } else if (Z_TYPE_P(op) != IS_LONG) {                           \
221        switch (Z_TYPE_P(op)) {                                     \
222            case IS_NULL:                                           \
223                Z_LVAL(holder) = 0;                                 \
224                break;                                              \
225            case IS_DOUBLE:                                         \
226                Z_LVAL(holder) = zend_dval_to_lval(Z_DVAL_P(op));   \
227                break;                                              \
228            case IS_STRING:                                         \
229                Z_LVAL(holder) = strtol(Z_STRVAL_P(op), NULL, 10);  \
230                break;                                              \
231            case IS_ARRAY:                                          \
232                Z_LVAL(holder) = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);  \
233                break;                                              \
234            case IS_OBJECT:                                         \
235                (holder) = (*(op));                                 \
236                zval_copy_ctor(&(holder));                          \
237                convert_to_long_base(&(holder), 10);                \
238                break;                                              \
239            case IS_BOOL:                                           \
240            case IS_RESOURCE:                                       \
241                Z_LVAL(holder) = Z_LVAL_P(op);                      \
242                break;                                              \
243            default:                                                \
244                zend_error(E_WARNING, "Cannot convert to ordinal value");   \
245                Z_LVAL(holder) = 0;                                 \
246                break;                                              \
247        }                                                           \
248        Z_TYPE(holder) = IS_LONG;                                   \
249        (op) = &(holder);                                           \
250    }
251
252/* }}} */
253
254/* {{{ zendi_convert_to_boolean */
255#define zendi_convert_to_boolean(op, holder, result)                \
256    if (op==result) {                                               \
257        convert_to_boolean(op);                                     \
258    } else if (Z_TYPE_P(op) != IS_BOOL) {                           \
259        switch (Z_TYPE_P(op)) {                                     \
260            case IS_NULL:                                           \
261                Z_LVAL(holder) = 0;                                 \
262                break;                                              \
263            case IS_RESOURCE:                                       \
264            case IS_LONG:                                           \
265                Z_LVAL(holder) = (Z_LVAL_P(op) ? 1 : 0);            \
266                break;                                              \
267            case IS_DOUBLE:                                         \
268                Z_LVAL(holder) = (Z_DVAL_P(op) ? 1 : 0);            \
269                break;                                              \
270            case IS_STRING:                                         \
271                if (Z_STRLEN_P(op) == 0                             \
272                    || (Z_STRLEN_P(op)==1 && Z_STRVAL_P(op)[0]=='0')) { \
273                    Z_LVAL(holder) = 0;                             \
274                } else {                                            \
275                    Z_LVAL(holder) = 1;                             \
276                }                                                   \
277                break;                                              \
278            case IS_ARRAY:                                          \
279                Z_LVAL(holder) = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);  \
280                break;                                              \
281            case IS_OBJECT:                                         \
282                (holder) = (*(op));                                 \
283                zval_copy_ctor(&(holder));                          \
284                convert_to_boolean(&(holder));                      \
285                break;                                              \
286            default:                                                \
287                Z_LVAL(holder) = 0;                                 \
288                break;                                              \
289        }                                                           \
290        Z_TYPE(holder) = IS_BOOL;                                   \
291        (op) = &(holder);                                           \
292    }
293
294/* }}} */
295
296/* {{{ convert_object_to_type */
297#define convert_object_to_type(op, ctype, conv_func)                                        \
298    if (Z_OBJ_HT_P(op)->cast_object) {                                                      \
299        zval dst;                                                                           \
300        if (Z_OBJ_HT_P(op)->cast_object(op, &dst, ctype TSRMLS_CC) == FAILURE) {            \
301            zend_error(E_RECOVERABLE_ERROR,                                                 \
302                "Object of class %s could not be converted to %s", Z_OBJCE_P(op)->name,     \
303            zend_get_type_by_const(ctype));                                                 \
304        } else {                                                                            \
305            zval_dtor(op);                                                                  \
306            Z_TYPE_P(op) = ctype;                                                           \
307            op->value = dst.value;                                                          \
308        }                                                                                   \
309    } else {                                                                                \
310        if (Z_OBJ_HT_P(op)->get) {                                                          \
311            zval *newop = Z_OBJ_HT_P(op)->get(op TSRMLS_CC);                                \
312            if (Z_TYPE_P(newop) != IS_OBJECT) {                                             \
313                /* for safety - avoid loop */                                               \
314                zval_dtor(op);                                                              \
315                *op = *newop;                                                               \
316                FREE_ZVAL(newop);                                                           \
317                conv_func(op);                                                              \
318            }                                                                               \
319        }                                                                                   \
320    }
321
322/* }}} */
323
324ZEND_API void convert_to_long(zval *op) /* {{{ */
325{
326    if (Z_TYPE_P(op) != IS_LONG) {
327        convert_to_long_base(op, 10);
328    }
329}
330/* }}} */
331
332ZEND_API void convert_to_long_base(zval *op, int base) /* {{{ */
333{
334    long tmp;
335
336    switch (Z_TYPE_P(op)) {
337        case IS_NULL:
338            Z_LVAL_P(op) = 0;
339            break;
340        case IS_RESOURCE: {
341                TSRMLS_FETCH();
342
343                zend_list_delete(Z_LVAL_P(op));
344            }
345            /* break missing intentionally */
346        case IS_BOOL:
347        case IS_LONG:
348            break;
349        case IS_DOUBLE:
350            Z_LVAL_P(op) = zend_dval_to_lval(Z_DVAL_P(op));
351            break;
352        case IS_STRING:
353            {
354                char *strval = Z_STRVAL_P(op);
355
356                Z_LVAL_P(op) = strtol(strval, NULL, base);
357                STR_FREE(strval);
358            }
359            break;
360        case IS_ARRAY:
361            tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
362            zval_dtor(op);
363            Z_LVAL_P(op) = tmp;
364            break;
365        case IS_OBJECT:
366            {
367                int retval = 1;
368                TSRMLS_FETCH();
369
370                convert_object_to_type(op, IS_LONG, convert_to_long);
371
372                if (Z_TYPE_P(op) == IS_LONG) {
373                    return;
374                }
375                zend_error(E_NOTICE, "Object of class %s could not be converted to int", Z_OBJCE_P(op)->name);
376
377                zval_dtor(op);
378                ZVAL_LONG(op, retval);
379                return;
380            }
381        default:
382            zend_error(E_WARNING, "Cannot convert to ordinal value");
383            zval_dtor(op);
384            Z_LVAL_P(op) = 0;
385            break;
386    }
387
388    Z_TYPE_P(op) = IS_LONG;
389}
390/* }}} */
391
392ZEND_API void convert_to_double(zval *op) /* {{{ */
393{
394    double tmp;
395
396    switch (Z_TYPE_P(op)) {
397        case IS_NULL:
398            Z_DVAL_P(op) = 0.0;
399            break;
400        case IS_RESOURCE: {
401                TSRMLS_FETCH();
402
403                zend_list_delete(Z_LVAL_P(op));
404            }
405            /* break missing intentionally */
406        case IS_BOOL:
407        case IS_LONG:
408            Z_DVAL_P(op) = (double) Z_LVAL_P(op);
409            break;
410        case IS_DOUBLE:
411            break;
412        case IS_STRING:
413            {
414                char *strval = Z_STRVAL_P(op);
415
416                Z_DVAL_P(op) = zend_strtod(strval, NULL);
417                STR_FREE(strval);
418            }
419            break;
420        case IS_ARRAY:
421            tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
422            zval_dtor(op);
423            Z_DVAL_P(op) = tmp;
424            break;
425        case IS_OBJECT:
426            {
427                double retval = 1.0;
428                TSRMLS_FETCH();
429
430                convert_object_to_type(op, IS_DOUBLE, convert_to_double);
431
432                if (Z_TYPE_P(op) == IS_DOUBLE) {
433                    return;
434                }
435                zend_error(E_NOTICE, "Object of class %s could not be converted to double", Z_OBJCE_P(op)->name);
436
437                zval_dtor(op);
438                ZVAL_DOUBLE(op, retval);
439                break;
440            }
441        default:
442            zend_error(E_WARNING, "Cannot convert to real value (type=%d)", Z_TYPE_P(op));
443            zval_dtor(op);
444            Z_DVAL_P(op) = 0;
445            break;
446    }
447    Z_TYPE_P(op) = IS_DOUBLE;
448}
449/* }}} */
450
451ZEND_API void convert_to_null(zval *op) /* {{{ */
452{
453    if (Z_TYPE_P(op) == IS_OBJECT) {
454        if (Z_OBJ_HT_P(op)->cast_object) {
455            zval *org;
456            TSRMLS_FETCH();
457
458            ALLOC_ZVAL(org);
459            *org = *op;
460            if (Z_OBJ_HT_P(op)->cast_object(org, op, IS_NULL TSRMLS_CC) == SUCCESS) {
461                zval_dtor(org);
462                return;
463            }
464            *op = *org;
465            FREE_ZVAL(org);
466        }
467    }
468
469    zval_dtor(op);
470    Z_TYPE_P(op) = IS_NULL;
471}
472/* }}} */
473
474ZEND_API void convert_to_boolean(zval *op) /* {{{ */
475{
476    int tmp;
477
478    switch (Z_TYPE_P(op)) {
479        case IS_BOOL:
480            break;
481        case IS_NULL:
482            Z_LVAL_P(op) = 0;
483            break;
484        case IS_RESOURCE: {
485                TSRMLS_FETCH();
486
487                zend_list_delete(Z_LVAL_P(op));
488            }
489            /* break missing intentionally */
490        case IS_LONG:
491            Z_LVAL_P(op) = (Z_LVAL_P(op) ? 1 : 0);
492            break;
493        case IS_DOUBLE:
494            Z_LVAL_P(op) = (Z_DVAL_P(op) ? 1 : 0);
495            break;
496        case IS_STRING:
497            {
498                char *strval = Z_STRVAL_P(op);
499
500                if (Z_STRLEN_P(op) == 0
501                    || (Z_STRLEN_P(op)==1 && Z_STRVAL_P(op)[0]=='0')) {
502                    Z_LVAL_P(op) = 0;
503                } else {
504                    Z_LVAL_P(op) = 1;
505                }
506                STR_FREE(strval);
507            }
508            break;
509        case IS_ARRAY:
510            tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
511            zval_dtor(op);
512            Z_LVAL_P(op) = tmp;
513            break;
514        case IS_OBJECT:
515            {
516                zend_bool retval = 1;
517                TSRMLS_FETCH();
518
519                convert_object_to_type(op, IS_BOOL, convert_to_boolean);
520
521                if (Z_TYPE_P(op) == IS_BOOL) {
522                    return;
523                }
524
525                zval_dtor(op);
526                ZVAL_BOOL(op, retval);
527                break;
528            }
529        default:
530            zval_dtor(op);
531            Z_LVAL_P(op) = 0;
532            break;
533    }
534    Z_TYPE_P(op) = IS_BOOL;
535}
536/* }}} */
537
538ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC) /* {{{ */
539{
540    long lval;
541    double dval;
542
543    switch (Z_TYPE_P(op)) {
544        case IS_NULL:
545            Z_STRVAL_P(op) = STR_EMPTY_ALLOC();
546            Z_STRLEN_P(op) = 0;
547            break;
548        case IS_STRING:
549            break;
550        case IS_BOOL:
551            if (Z_LVAL_P(op)) {
552                Z_STRVAL_P(op) = estrndup_rel("1", 1);
553                Z_STRLEN_P(op) = 1;
554            } else {
555                Z_STRVAL_P(op) = STR_EMPTY_ALLOC();
556                Z_STRLEN_P(op) = 0;
557            }
558            break;
559        case IS_RESOURCE: {
560            long tmp = Z_LVAL_P(op);
561            TSRMLS_FETCH();
562
563            zend_list_delete(Z_LVAL_P(op));
564            Z_STRLEN_P(op) = zend_spprintf(&Z_STRVAL_P(op), 0, "Resource id #%ld", tmp);
565            break;
566        }
567        case IS_LONG:
568            lval = Z_LVAL_P(op);
569
570            Z_STRLEN_P(op) = zend_spprintf(&Z_STRVAL_P(op), 0, "%ld", lval);
571            break;
572        case IS_DOUBLE: {
573            TSRMLS_FETCH();
574            dval = Z_DVAL_P(op);
575            Z_STRLEN_P(op) = zend_spprintf(&Z_STRVAL_P(op), 0, "%.*G", (int) EG(precision), dval);
576            /* %G already handles removing trailing zeros from the fractional part, yay */
577            break;
578        }
579        case IS_ARRAY:
580            zend_error(E_NOTICE, "Array to string conversion");
581            zval_dtor(op);
582            Z_STRVAL_P(op) = estrndup_rel("Array", sizeof("Array")-1);
583            Z_STRLEN_P(op) = sizeof("Array")-1;
584            break;
585        case IS_OBJECT: {
586            TSRMLS_FETCH();
587
588            convert_object_to_type(op, IS_STRING, convert_to_string);
589
590            if (Z_TYPE_P(op) == IS_STRING) {
591                return;
592            }
593
594            zend_error(E_NOTICE, "Object of class %s to string conversion", Z_OBJCE_P(op)->name);
595            zval_dtor(op);
596            Z_STRVAL_P(op) = estrndup_rel("Object", sizeof("Object")-1);
597            Z_STRLEN_P(op) = sizeof("Object")-1;
598            break;
599        }
600        default:
601            zval_dtor(op);
602            ZVAL_BOOL(op, 0);
603            break;
604    }
605    Z_TYPE_P(op) = IS_STRING;
606}
607/* }}} */
608
609static void convert_scalar_to_array(zval *op, int type TSRMLS_DC) /* {{{ */
610{
611    zval *entry;
612
613    ALLOC_ZVAL(entry);
614    *entry = *op;
615    INIT_PZVAL(entry);
616
617    switch (type) {
618        case IS_ARRAY:
619            ALLOC_HASHTABLE(Z_ARRVAL_P(op));
620            zend_hash_init(Z_ARRVAL_P(op), 0, NULL, ZVAL_PTR_DTOR, 0);
621            zend_hash_index_update(Z_ARRVAL_P(op), 0, (void *) &entry, sizeof(zval *), NULL);
622            Z_TYPE_P(op) = IS_ARRAY;
623            break;
624        case IS_OBJECT:
625            object_init(op);
626            zend_hash_update(Z_OBJPROP_P(op), "scalar", sizeof("scalar"), (void *) &entry, sizeof(zval *), NULL);
627            break;
628    }
629}
630/* }}} */
631
632ZEND_API void convert_to_array(zval *op) /* {{{ */
633{
634    TSRMLS_FETCH();
635
636    switch (Z_TYPE_P(op)) {
637        case IS_ARRAY:
638            break;
639/* OBJECTS_OPTIMIZE */
640        case IS_OBJECT:
641            {
642                zval *tmp;
643                HashTable *ht;
644
645                ALLOC_HASHTABLE(ht);
646                zend_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0);
647                if (Z_OBJCE_P(op) == zend_ce_closure) {
648                    convert_scalar_to_array(op, IS_ARRAY TSRMLS_CC);
649                    if (Z_TYPE_P(op) == IS_ARRAY) {
650                        zend_hash_destroy(ht);
651                        FREE_HASHTABLE(ht);
652                        return;
653                    }
654                } else if (Z_OBJ_HT_P(op)->get_properties) {
655                    HashTable *obj_ht = Z_OBJ_HT_P(op)->get_properties(op TSRMLS_CC);
656                    if (obj_ht) {
657                        zend_hash_copy(ht, obj_ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
658                    }
659                } else {
660                    convert_object_to_type(op, IS_ARRAY, convert_to_array);
661
662                    if (Z_TYPE_P(op) == IS_ARRAY) {
663                        zend_hash_destroy(ht);
664                        FREE_HASHTABLE(ht);
665                        return;
666                    }
667                }
668                zval_dtor(op);
669                Z_TYPE_P(op) = IS_ARRAY;
670                Z_ARRVAL_P(op) = ht;
671            }
672            break;
673        case IS_NULL:
674            ALLOC_HASHTABLE(Z_ARRVAL_P(op));
675            zend_hash_init(Z_ARRVAL_P(op), 0, NULL, ZVAL_PTR_DTOR, 0);
676            Z_TYPE_P(op) = IS_ARRAY;
677            break;
678        default:
679            convert_scalar_to_array(op, IS_ARRAY TSRMLS_CC);
680            break;
681    }
682}
683/* }}} */
684
685ZEND_API void convert_to_object(zval *op) /* {{{ */
686{
687    TSRMLS_FETCH();
688
689    switch (Z_TYPE_P(op)) {
690        case IS_ARRAY:
691            {
692                object_and_properties_init(op, zend_standard_class_def, Z_ARRVAL_P(op));
693                break;
694            }
695        case IS_OBJECT:
696            break;
697        case IS_NULL:
698            object_init(op);
699            break;
700        default:
701            convert_scalar_to_array(op, IS_OBJECT TSRMLS_CC);
702            break;
703    }
704}
705/* }}} */
706
707ZEND_API void multi_convert_to_long_ex(int argc, ...) /* {{{ */
708{
709    zval **arg;
710    va_list ap;
711
712    va_start(ap, argc);
713
714    while (argc--) {
715        arg = va_arg(ap, zval **);
716        convert_to_long_ex(arg);
717    }
718
719    va_end(ap);
720}
721/* }}} */
722
723ZEND_API void multi_convert_to_double_ex(int argc, ...) /* {{{ */
724{
725    zval **arg;
726    va_list ap;
727
728    va_start(ap, argc);
729
730    while (argc--) {
731        arg = va_arg(ap, zval **);
732        convert_to_double_ex(arg);
733    }
734
735    va_end(ap);
736}
737/* }}} */
738
739ZEND_API void multi_convert_to_string_ex(int argc, ...) /* {{{ */
740{
741    zval **arg;
742    va_list ap;
743
744    va_start(ap, argc);
745
746    while (argc--) {
747        arg = va_arg(ap, zval **);
748        convert_to_string_ex(arg);
749    }
750
751    va_end(ap);
752}
753/* }}} */
754
755ZEND_API int add_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
756{
757    zval op1_copy, op2_copy;
758    int converted = 0;
759
760    while (1) {
761        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
762            case TYPE_PAIR(IS_LONG, IS_LONG): {
763                long lval = Z_LVAL_P(op1) + Z_LVAL_P(op2);
764
765                /* check for overflow by comparing sign bits */
766                if ((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK)
767                    && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (lval & LONG_SIGN_MASK)) {
768
769                    ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2));
770                } else {
771                    ZVAL_LONG(result, lval);
772                }
773                return SUCCESS;
774            }
775
776            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
777                ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
778                return SUCCESS;
779
780            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
781                ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
782                return SUCCESS;
783
784            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
785                ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
786                return SUCCESS;
787
788            case TYPE_PAIR(IS_ARRAY, IS_ARRAY): {
789                zval *tmp;
790
791                if ((result == op1) && (result == op2)) {
792                    /* $a += $a */
793                    return SUCCESS;
794                }
795                if (result != op1) {
796                    *result = *op1;
797                    zval_copy_ctor(result);
798                }
799                zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), (void (*)(void *pData)) zval_add_ref, (void *) &tmp, sizeof(zval *), 0);
800                return SUCCESS;
801            }
802
803            default:
804                if (!converted) {
805                    zendi_convert_scalar_to_number(op1, op1_copy, result);
806                    zendi_convert_scalar_to_number(op2, op2_copy, result);
807                    converted = 1;
808                } else {
809                    zend_error(E_ERROR, "Unsupported operand types");
810                    return FAILURE; /* unknown datatype */
811                }
812        }
813    }
814}
815/* }}} */
816
817ZEND_API int sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
818{
819    zval op1_copy, op2_copy;
820    int converted = 0;
821
822    while (1) {
823        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
824            case TYPE_PAIR(IS_LONG, IS_LONG): {
825                long lval = Z_LVAL_P(op1) - Z_LVAL_P(op2);
826
827                /* check for overflow by comparing sign bits */
828                if ((Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(op2) & LONG_SIGN_MASK)
829                    && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (lval & LONG_SIGN_MASK)) {
830
831                    ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2));
832                } else {
833                    ZVAL_LONG(result, lval);
834                }
835                return SUCCESS;
836
837            }
838            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
839                ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) - Z_DVAL_P(op2));
840                return SUCCESS;
841
842            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
843                ZVAL_DOUBLE(result, Z_DVAL_P(op1) - ((double)Z_LVAL_P(op2)));
844                return SUCCESS;
845
846            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
847                ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2));
848                return SUCCESS;
849
850            default:
851                if (!converted) {
852                    zendi_convert_scalar_to_number(op1, op1_copy, result);
853                    zendi_convert_scalar_to_number(op2, op2_copy, result);
854                    converted = 1;
855                } else {
856                    zend_error(E_ERROR, "Unsupported operand types");
857                    return FAILURE; /* unknown datatype */
858                }
859        }
860    }
861}
862/* }}} */
863
864ZEND_API int mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
865{
866    zval op1_copy, op2_copy;
867    int converted = 0;
868
869    while (1) {
870        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
871            case TYPE_PAIR(IS_LONG, IS_LONG): {
872                long overflow;
873
874                ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1),Z_LVAL_P(op2), Z_LVAL_P(result),Z_DVAL_P(result),overflow);
875                Z_TYPE_P(result) = overflow ? IS_DOUBLE : IS_LONG;
876                return SUCCESS;
877
878            }
879            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
880                ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2));
881                return SUCCESS;
882
883            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
884                ZVAL_DOUBLE(result, Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2)));
885                return SUCCESS;
886
887            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
888                ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2));
889                return SUCCESS;
890
891            default:
892                if (!converted) {
893                    zendi_convert_scalar_to_number(op1, op1_copy, result);
894                    zendi_convert_scalar_to_number(op2, op2_copy, result);
895                    converted = 1;
896                } else {
897                    zend_error(E_ERROR, "Unsupported operand types");
898                    return FAILURE; /* unknown datatype */
899                }
900        }
901    }
902}
903/* }}} */
904
905ZEND_API int div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
906{
907    zval op1_copy, op2_copy;
908    int converted = 0;
909
910    while (1) {
911        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
912            case TYPE_PAIR(IS_LONG, IS_LONG):
913                if (Z_LVAL_P(op2) == 0) {
914                    zend_error(E_WARNING, "Division by zero");
915                    ZVAL_BOOL(result, 0);
916                    return FAILURE;         /* division by zero */
917                } else if (Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == LONG_MIN) {
918                    /* Prevent overflow error/crash */
919                    ZVAL_DOUBLE(result, (double) LONG_MIN / -1);
920                    return SUCCESS;
921                }
922                if (Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0) { /* integer */
923                    ZVAL_LONG(result, Z_LVAL_P(op1) / Z_LVAL_P(op2));
924                } else {
925                    ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1)) / Z_LVAL_P(op2));
926                }
927                return SUCCESS;
928
929            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
930                if (Z_LVAL_P(op2) == 0) {
931                    zend_error(E_WARNING, "Division by zero");
932                    ZVAL_BOOL(result, 0);
933                    return FAILURE;         /* division by zero */
934                }
935                ZVAL_DOUBLE(result, Z_DVAL_P(op1) / (double)Z_LVAL_P(op2));
936                return SUCCESS;
937
938            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
939                if (Z_DVAL_P(op2) == 0) {
940                    zend_error(E_WARNING, "Division by zero");
941                    ZVAL_BOOL(result, 0);
942                    return FAILURE;         /* division by zero */
943                }
944                ZVAL_DOUBLE(result, (double)Z_LVAL_P(op1) / Z_DVAL_P(op2));
945                return SUCCESS;
946
947            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
948                if (Z_DVAL_P(op2) == 0) {
949                    zend_error(E_WARNING, "Division by zero");
950                    ZVAL_BOOL(result, 0);
951                    return FAILURE;         /* division by zero */
952                }
953                ZVAL_DOUBLE(result, Z_DVAL_P(op1) / Z_DVAL_P(op2));
954                return SUCCESS;
955
956            default:
957                if (!converted) {
958                    zendi_convert_scalar_to_number(op1, op1_copy, result);
959                    zendi_convert_scalar_to_number(op2, op2_copy, result);
960                    converted = 1;
961                } else {
962                    zend_error(E_ERROR, "Unsupported operand types");
963                    return FAILURE; /* unknown datatype */
964                }
965        }
966    }
967}
968/* }}} */
969
970ZEND_API int mod_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
971{
972    zval op1_copy, op2_copy;
973    long op1_lval;
974
975    zendi_convert_to_long(op1, op1_copy, result);
976    op1_lval = Z_LVAL_P(op1);
977    zendi_convert_to_long(op2, op2_copy, result);
978
979    if (Z_LVAL_P(op2) == 0) {
980        zend_error(E_WARNING, "Division by zero");
981        ZVAL_BOOL(result, 0);
982        return FAILURE;         /* modulus by zero */
983    }
984
985    if (Z_LVAL_P(op2) == -1) {
986        /* Prevent overflow error/crash if op1==LONG_MIN */
987        ZVAL_LONG(result, 0);
988        return SUCCESS;
989    }
990
991    ZVAL_LONG(result, op1_lval % Z_LVAL_P(op2));
992    return SUCCESS;
993}
994/* }}} */
995
996ZEND_API int boolean_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
997{
998    zval op1_copy, op2_copy;
999    long op1_lval;
1000
1001    zendi_convert_to_boolean(op1, op1_copy, result);
1002    op1_lval = Z_LVAL_P(op1);
1003    zendi_convert_to_boolean(op2, op2_copy, result);
1004    ZVAL_BOOL(result, op1_lval ^ Z_LVAL_P(op2));
1005    return SUCCESS;
1006}
1007/* }}} */
1008
1009ZEND_API int boolean_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */
1010{
1011    zval op1_copy;
1012
1013    zendi_convert_to_boolean(op1, op1_copy, result);
1014    ZVAL_BOOL(result, !Z_LVAL_P(op1));
1015    return SUCCESS;
1016}
1017/* }}} */
1018
1019ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */
1020{
1021    zval op1_copy = *op1;
1022
1023    op1 = &op1_copy;
1024
1025    if (Z_TYPE_P(op1) == IS_LONG) {
1026        ZVAL_LONG(result, ~Z_LVAL_P(op1));
1027        return SUCCESS;
1028    } else if (Z_TYPE_P(op1) == IS_DOUBLE) {
1029        ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1)));
1030        return SUCCESS;
1031    } else if (Z_TYPE_P(op1) == IS_STRING) {
1032        int i;
1033
1034        Z_TYPE_P(result) = IS_STRING;
1035        Z_STRVAL_P(result) = estrndup(Z_STRVAL_P(op1), Z_STRLEN_P(op1));
1036        Z_STRLEN_P(result) = Z_STRLEN_P(op1);
1037        for (i = 0; i < Z_STRLEN_P(op1); i++) {
1038            Z_STRVAL_P(result)[i] = ~Z_STRVAL_P(op1)[i];
1039        }
1040        return SUCCESS;
1041    }
1042    zend_error(E_ERROR, "Unsupported operand types");
1043    return FAILURE;             /* unknown datatype */
1044}
1045/* }}} */
1046
1047ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1048{
1049    zval op1_copy, op2_copy;
1050    long op1_lval;
1051
1052    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1053        zval *longer, *shorter;
1054        char *result_str;
1055        int i, result_len;
1056
1057        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1058            longer = op1;
1059            shorter = op2;
1060        } else {
1061            longer = op2;
1062            shorter = op1;
1063        }
1064
1065        Z_TYPE_P(result) = IS_STRING;
1066        result_len = Z_STRLEN_P(longer);
1067        result_str = estrndup(Z_STRVAL_P(longer), Z_STRLEN_P(longer));
1068        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1069            result_str[i] |= Z_STRVAL_P(shorter)[i];
1070        }
1071        if (result==op1) {
1072            STR_FREE(Z_STRVAL_P(result));
1073        }
1074        Z_STRVAL_P(result) = result_str;
1075        Z_STRLEN_P(result) = result_len;
1076        return SUCCESS;
1077    }
1078    zendi_convert_to_long(op1, op1_copy, result);
1079    op1_lval = Z_LVAL_P(op1);
1080    zendi_convert_to_long(op2, op2_copy, result);
1081
1082    ZVAL_LONG(result, op1_lval | Z_LVAL_P(op2));
1083    return SUCCESS;
1084}
1085/* }}} */
1086
1087ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1088{
1089    zval op1_copy, op2_copy;
1090    long op1_lval;
1091
1092    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1093        zval *longer, *shorter;
1094        char *result_str;
1095        int i, result_len;
1096
1097        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1098            longer = op1;
1099            shorter = op2;
1100        } else {
1101            longer = op2;
1102            shorter = op1;
1103        }
1104
1105        Z_TYPE_P(result) = IS_STRING;
1106        result_len = Z_STRLEN_P(shorter);
1107        result_str = estrndup(Z_STRVAL_P(shorter), Z_STRLEN_P(shorter));
1108        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1109            result_str[i] &= Z_STRVAL_P(longer)[i];
1110        }
1111        if (result==op1) {
1112            STR_FREE(Z_STRVAL_P(result));
1113        }
1114        Z_STRVAL_P(result) = result_str;
1115        Z_STRLEN_P(result) = result_len;
1116        return SUCCESS;
1117    }
1118
1119
1120    zendi_convert_to_long(op1, op1_copy, result);
1121    op1_lval = Z_LVAL_P(op1);
1122    zendi_convert_to_long(op2, op2_copy, result);
1123
1124    ZVAL_LONG(result, op1_lval & Z_LVAL_P(op2));
1125    return SUCCESS;
1126}
1127/* }}} */
1128
1129ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1130{
1131    zval op1_copy, op2_copy;
1132    long op1_lval;
1133
1134    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1135        zval *longer, *shorter;
1136        char *result_str;
1137        int i, result_len;
1138
1139        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1140            longer = op1;
1141            shorter = op2;
1142        } else {
1143            longer = op2;
1144            shorter = op1;
1145        }
1146
1147        Z_TYPE_P(result) = IS_STRING;
1148        result_len = Z_STRLEN_P(shorter);
1149        result_str = estrndup(Z_STRVAL_P(shorter), Z_STRLEN_P(shorter));
1150        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1151            result_str[i] ^= Z_STRVAL_P(longer)[i];
1152        }
1153        if (result==op1) {
1154            STR_FREE(Z_STRVAL_P(result));
1155        }
1156        Z_STRVAL_P(result) = result_str;
1157        Z_STRLEN_P(result) = result_len;
1158        return SUCCESS;
1159    }
1160
1161    zendi_convert_to_long(op1, op1_copy, result);
1162    op1_lval = Z_LVAL_P(op1);
1163    zendi_convert_to_long(op2, op2_copy, result);
1164
1165    ZVAL_LONG(result, op1_lval ^ Z_LVAL_P(op2));
1166    return SUCCESS;
1167}
1168/* }}} */
1169
1170ZEND_API int shift_left_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1171{
1172    zval op1_copy, op2_copy;
1173    long op1_lval;
1174
1175    zendi_convert_to_long(op1, op1_copy, result);
1176    op1_lval = Z_LVAL_P(op1);
1177    zendi_convert_to_long(op2, op2_copy, result);
1178    ZVAL_LONG(result, op1_lval << Z_LVAL_P(op2));
1179    return SUCCESS;
1180}
1181/* }}} */
1182
1183ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1184{
1185    zval op1_copy, op2_copy;
1186    long op1_lval;
1187
1188    zendi_convert_to_long(op1, op1_copy, result);
1189    op1_lval = Z_LVAL_P(op1);
1190    zendi_convert_to_long(op2, op2_copy, result);
1191    ZVAL_LONG(result, op1_lval >> Z_LVAL_P(op2));
1192    return SUCCESS;
1193}
1194/* }}} */
1195
1196/* must support result==op1 */
1197ZEND_API int add_char_to_string(zval *result, const zval *op1, const zval *op2) /* {{{ */
1198{
1199    int length = Z_STRLEN_P(op1) + 1;
1200    char *buf;
1201
1202    if (IS_INTERNED(Z_STRVAL_P(op1))) {
1203        buf = (char *) emalloc(length + 1);
1204        memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1));
1205    } else {
1206        buf = (char *) erealloc(Z_STRVAL_P(op1), length + 1);
1207    }
1208    buf[length - 1] = (char) Z_LVAL_P(op2);
1209    buf[length] = 0;
1210    ZVAL_STRINGL(result, buf, length, 0);
1211    return SUCCESS;
1212}
1213/* }}} */
1214
1215/* must support result==op1 */
1216ZEND_API int add_string_to_string(zval *result, const zval *op1, const zval *op2) /* {{{ */
1217{
1218    int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
1219    char *buf;
1220
1221    if (IS_INTERNED(Z_STRVAL_P(op1))) {
1222        buf = (char *) emalloc(length+1);
1223        memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1));
1224    } else {
1225        buf = (char *) erealloc(Z_STRVAL_P(op1), length+1);
1226    }
1227    memcpy(buf + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1228    buf[length] = 0;
1229    ZVAL_STRINGL(result, buf, length, 0);
1230    return SUCCESS;
1231}
1232/* }}} */
1233
1234ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1235{
1236    zval op1_copy, op2_copy;
1237    int use_copy1 = 0, use_copy2 = 0;
1238
1239    if (Z_TYPE_P(op1) != IS_STRING) {
1240        zend_make_printable_zval(op1, &op1_copy, &use_copy1);
1241    }
1242    if (Z_TYPE_P(op2) != IS_STRING) {
1243        zend_make_printable_zval(op2, &op2_copy, &use_copy2);
1244    }
1245
1246    if (use_copy1) {
1247        /* We have created a converted copy of op1. Therefore, op1 won't become the result so
1248         * we have to free it.
1249         */
1250        if (result == op1) {
1251            zval_dtor(op1);
1252        }
1253        op1 = &op1_copy;
1254    }
1255    if (use_copy2) {
1256        op2 = &op2_copy;
1257    }
1258    if (result==op1 && !IS_INTERNED(Z_STRVAL_P(op1))) { /* special case, perform operations on result */
1259        uint res_len = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
1260
1261        if (Z_STRLEN_P(result) < 0 || (int) (Z_STRLEN_P(op1) + Z_STRLEN_P(op2)) < 0) {
1262            efree(Z_STRVAL_P(result));
1263            ZVAL_EMPTY_STRING(result);
1264            zend_error(E_ERROR, "String size overflow");
1265        }
1266
1267        Z_STRVAL_P(result) = erealloc(Z_STRVAL_P(result), res_len+1);
1268
1269        memcpy(Z_STRVAL_P(result)+Z_STRLEN_P(result), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1270        Z_STRVAL_P(result)[res_len]=0;
1271        Z_STRLEN_P(result) = res_len;
1272    } else {
1273        int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
1274        char *buf = (char *) emalloc(length + 1);
1275
1276        memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1));
1277        memcpy(buf + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1278        buf[length] = 0;
1279        ZVAL_STRINGL(result, buf, length, 0);
1280    }
1281    if (use_copy1) {
1282        zval_dtor(op1);
1283    }
1284    if (use_copy2) {
1285        zval_dtor(op2);
1286    }
1287    return SUCCESS;
1288}
1289/* }}} */
1290
1291ZEND_API int string_compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool case_insensitive TSRMLS_DC) /* {{{ */
1292{
1293    zval op1_copy, op2_copy;
1294    int use_copy1 = 0, use_copy2 = 0;
1295
1296    if (Z_TYPE_P(op1) != IS_STRING) {
1297        zend_make_printable_zval(op1, &op1_copy, &use_copy1);
1298    }
1299    if (Z_TYPE_P(op2) != IS_STRING) {
1300        zend_make_printable_zval(op2, &op2_copy, &use_copy2);
1301    }
1302
1303    if (use_copy1) {
1304        op1 = &op1_copy;
1305    }
1306    if (use_copy2) {
1307        op2 = &op2_copy;
1308    }
1309
1310    if (case_insensitive) {
1311        ZVAL_LONG(result, zend_binary_zval_strcasecmp(op1, op2));
1312    } else {
1313        ZVAL_LONG(result, zend_binary_zval_strcmp(op1, op2));
1314    }
1315
1316    if (use_copy1) {
1317        zval_dtor(op1);
1318    }
1319    if (use_copy2) {
1320        zval_dtor(op2);
1321    }
1322    return SUCCESS;
1323}
1324/* }}} */
1325
1326ZEND_API int string_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1327{
1328    return string_compare_function_ex(result, op1, op2, 0 TSRMLS_CC);
1329}
1330/* }}} */
1331
1332ZEND_API int string_case_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1333{
1334    return string_compare_function_ex(result, op1, op2, 1 TSRMLS_CC);
1335}
1336/* }}} */
1337
1338#if HAVE_STRCOLL
1339ZEND_API int string_locale_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1340{
1341    zval op1_copy, op2_copy;
1342    int use_copy1 = 0, use_copy2 = 0;
1343
1344    if (Z_TYPE_P(op1) != IS_STRING) {
1345        zend_make_printable_zval(op1, &op1_copy, &use_copy1);
1346    }
1347    if (Z_TYPE_P(op2) != IS_STRING) {
1348        zend_make_printable_zval(op2, &op2_copy, &use_copy2);
1349    }
1350
1351    if (use_copy1) {
1352        op1 = &op1_copy;
1353    }
1354    if (use_copy2) {
1355        op2 = &op2_copy;
1356    }
1357
1358    ZVAL_LONG(result, strcoll(Z_STRVAL_P(op1), Z_STRVAL_P(op2)));
1359
1360    if (use_copy1) {
1361        zval_dtor(op1);
1362    }
1363    if (use_copy2) {
1364        zval_dtor(op2);
1365    }
1366    return SUCCESS;
1367}
1368/* }}} */
1369#endif
1370
1371ZEND_API int numeric_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1372{
1373    zval op1_copy, op2_copy;
1374
1375    op1_copy = *op1;
1376    zval_copy_ctor(&op1_copy);
1377
1378    op2_copy = *op2;
1379    zval_copy_ctor(&op2_copy);
1380
1381    convert_to_double(&op1_copy);
1382    convert_to_double(&op2_copy);
1383
1384    ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL(op1_copy)-Z_DVAL(op2_copy)));
1385
1386    return SUCCESS;
1387}
1388/* }}} */
1389
1390static inline void zend_free_obj_get_result(zval *op TSRMLS_DC) /* {{{ */
1391{
1392    if (Z_REFCOUNT_P(op) == 0) {
1393        GC_REMOVE_ZVAL_FROM_BUFFER(op);
1394        zval_dtor(op);
1395        FREE_ZVAL(op);
1396    } else {
1397        zval_ptr_dtor(&op);
1398    }
1399}
1400/* }}} */
1401
1402ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1403{
1404    int ret;
1405    int converted = 0;
1406    zval op1_copy, op2_copy;
1407    zval *op_free;
1408
1409    while (1) {
1410        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
1411            case TYPE_PAIR(IS_LONG, IS_LONG):
1412                ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0));
1413                return SUCCESS;
1414
1415            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1416                Z_DVAL_P(result) = Z_DVAL_P(op1) - (double)Z_LVAL_P(op2);
1417                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1418                return SUCCESS;
1419
1420            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1421                Z_DVAL_P(result) = (double)Z_LVAL_P(op1) - Z_DVAL_P(op2);
1422                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1423                return SUCCESS;
1424
1425            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1426                if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
1427                    ZVAL_LONG(result, 0);
1428                } else {
1429                    Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2);
1430                    ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1431                }
1432                return SUCCESS;
1433
1434            case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
1435                zend_compare_arrays(result, op1, op2 TSRMLS_CC);
1436                return SUCCESS;
1437
1438            case TYPE_PAIR(IS_NULL, IS_NULL):
1439                ZVAL_LONG(result, 0);
1440                return SUCCESS;
1441
1442            case TYPE_PAIR(IS_NULL, IS_BOOL):
1443                ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0);
1444                return SUCCESS;
1445
1446            case TYPE_PAIR(IS_BOOL, IS_NULL):
1447                ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0);
1448                return SUCCESS;
1449
1450            case TYPE_PAIR(IS_BOOL, IS_BOOL):
1451                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1452                return SUCCESS;
1453
1454            case TYPE_PAIR(IS_STRING, IS_STRING):
1455                zendi_smart_strcmp(result, op1, op2);
1456                return SUCCESS;
1457
1458            case TYPE_PAIR(IS_NULL, IS_STRING):
1459                ZVAL_LONG(result, zend_binary_strcmp("", 0, Z_STRVAL_P(op2), Z_STRLEN_P(op2)));
1460                return SUCCESS;
1461
1462            case TYPE_PAIR(IS_STRING, IS_NULL):
1463                ZVAL_LONG(result, zend_binary_strcmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), "", 0));
1464                return SUCCESS;
1465
1466            case TYPE_PAIR(IS_OBJECT, IS_NULL):
1467                ZVAL_LONG(result, 1);
1468                return SUCCESS;
1469
1470            case TYPE_PAIR(IS_NULL, IS_OBJECT):
1471                ZVAL_LONG(result, -1);
1472                return SUCCESS;
1473
1474            case TYPE_PAIR(IS_OBJECT, IS_OBJECT):
1475                /* If both are objects sharing the same comparision handler then use is */
1476                if (Z_OBJ_HANDLER_P(op1,compare_objects) == Z_OBJ_HANDLER_P(op2,compare_objects)) {
1477                    if (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2)) {
1478                        /* object handles are identical, apparently this is the same object */
1479                        ZVAL_LONG(result, 0);
1480                        return SUCCESS;
1481                    }
1482                    ZVAL_LONG(result, Z_OBJ_HT_P(op1)->compare_objects(op1, op2 TSRMLS_CC));
1483                    return SUCCESS;
1484                }
1485                /* break missing intentionally */
1486
1487            default:
1488                if (Z_TYPE_P(op1) == IS_OBJECT) {
1489                    if (Z_OBJ_HT_P(op1)->get) {
1490                        op_free = Z_OBJ_HT_P(op1)->get(op1 TSRMLS_CC);
1491                        ret = compare_function(result, op_free, op2 TSRMLS_CC);
1492                        zend_free_obj_get_result(op_free TSRMLS_CC);
1493                        return ret;
1494                    } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) {
1495                        ALLOC_INIT_ZVAL(op_free);
1496                        if (Z_OBJ_HT_P(op1)->cast_object(op1, op_free, Z_TYPE_P(op2) TSRMLS_CC) == FAILURE) {
1497                            ZVAL_LONG(result, 1);
1498                            zend_free_obj_get_result(op_free TSRMLS_CC);
1499                            return SUCCESS;
1500                        }
1501                        ret = compare_function(result, op_free, op2 TSRMLS_CC);
1502                        zend_free_obj_get_result(op_free TSRMLS_CC);
1503                        return ret;
1504                    }
1505                }
1506                if (Z_TYPE_P(op2) == IS_OBJECT) {
1507                    if (Z_OBJ_HT_P(op2)->get) {
1508                        op_free = Z_OBJ_HT_P(op2)->get(op2 TSRMLS_CC);
1509                        ret = compare_function(result, op1, op_free TSRMLS_CC);
1510                        zend_free_obj_get_result(op_free TSRMLS_CC);
1511                        return ret;
1512                    } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) {
1513                        ALLOC_INIT_ZVAL(op_free);
1514                        if (Z_OBJ_HT_P(op2)->cast_object(op2, op_free, Z_TYPE_P(op1) TSRMLS_CC) == FAILURE) {
1515                            ZVAL_LONG(result, -1);
1516                            zend_free_obj_get_result(op_free TSRMLS_CC);
1517                            return SUCCESS;
1518                        }
1519                        ret = compare_function(result, op1, op_free TSRMLS_CC);
1520                        zend_free_obj_get_result(op_free TSRMLS_CC);
1521                        return ret;
1522                    } else if (Z_TYPE_P(op1) == IS_OBJECT) {
1523                        ZVAL_LONG(result, 1);
1524                        return SUCCESS;
1525                    }
1526                }
1527                if (!converted) {
1528                    if (Z_TYPE_P(op1) == IS_NULL) {
1529                        zendi_convert_to_boolean(op2, op2_copy, result);
1530                        ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0);
1531                        return SUCCESS;
1532                    } else if (Z_TYPE_P(op2) == IS_NULL) {
1533                        zendi_convert_to_boolean(op1, op1_copy, result);
1534                        ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0);
1535                        return SUCCESS;
1536                    } else if (Z_TYPE_P(op1) == IS_BOOL) {
1537                        zendi_convert_to_boolean(op2, op2_copy, result);
1538                        ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1539                        return SUCCESS;
1540                    } else if (Z_TYPE_P(op2) == IS_BOOL) {
1541                        zendi_convert_to_boolean(op1, op1_copy, result);
1542                        ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1543                        return SUCCESS;
1544                    } else {
1545                        zendi_convert_scalar_to_number(op1, op1_copy, result);
1546                        zendi_convert_scalar_to_number(op2, op2_copy, result);
1547                        converted = 1;
1548                    }
1549                } else if (Z_TYPE_P(op1)==IS_ARRAY) {
1550                    ZVAL_LONG(result, 1);
1551                    return SUCCESS;
1552                } else if (Z_TYPE_P(op2)==IS_ARRAY) {
1553                    ZVAL_LONG(result, -1);
1554                    return SUCCESS;
1555                } else if (Z_TYPE_P(op1)==IS_OBJECT) {
1556                    ZVAL_LONG(result, 1);
1557                    return SUCCESS;
1558                } else if (Z_TYPE_P(op2)==IS_OBJECT) {
1559                    ZVAL_LONG(result, -1);
1560                    return SUCCESS;
1561                } else {
1562                    ZVAL_LONG(result, 0);
1563                    return FAILURE;
1564                }
1565        }
1566    }
1567}
1568/* }}} */
1569
1570static int hash_zval_identical_function(const zval **z1, const zval **z2) /* {{{ */
1571{
1572    zval result;
1573    TSRMLS_FETCH();
1574
1575    /* is_identical_function() returns 1 in case of identity and 0 in case
1576     * of a difference;
1577     * whereas this comparison function is expected to return 0 on identity,
1578     * and non zero otherwise.
1579     */
1580    if (is_identical_function(&result, (zval *) *z1, (zval *) *z2 TSRMLS_CC)==FAILURE) {
1581        return 1;
1582    }
1583    return !Z_LVAL(result);
1584}
1585/* }}} */
1586
1587ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1588{
1589    Z_TYPE_P(result) = IS_BOOL;
1590    if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
1591        Z_LVAL_P(result) = 0;
1592        return SUCCESS;
1593    }
1594    switch (Z_TYPE_P(op1)) {
1595        case IS_NULL:
1596            Z_LVAL_P(result) = 1;
1597            break;
1598        case IS_BOOL:
1599        case IS_LONG:
1600        case IS_RESOURCE:
1601            Z_LVAL_P(result) = (Z_LVAL_P(op1) == Z_LVAL_P(op2));
1602            break;
1603        case IS_DOUBLE:
1604            Z_LVAL_P(result) = (Z_DVAL_P(op1) == Z_DVAL_P(op2));
1605            break;
1606        case IS_STRING:
1607            Z_LVAL_P(result) = ((Z_STRLEN_P(op1) == Z_STRLEN_P(op2))
1608                && (!memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1))));
1609            break;
1610        case IS_ARRAY:
1611            Z_LVAL_P(result) = (Z_ARRVAL_P(op1) == Z_ARRVAL_P(op2) ||
1612                zend_hash_compare(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2), (compare_func_t) hash_zval_identical_function, 1 TSRMLS_CC)==0);
1613            break;
1614        case IS_OBJECT:
1615            if (Z_OBJ_HT_P(op1) == Z_OBJ_HT_P(op2)) {
1616                Z_LVAL_P(result) = (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2));
1617            } else {
1618                Z_LVAL_P(result) = 0;
1619            }
1620            break;
1621        default:
1622            Z_LVAL_P(result) = 0;
1623            return FAILURE;
1624    }
1625    return SUCCESS;
1626}
1627/* }}} */
1628
1629ZEND_API int is_not_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1630{
1631    if (is_identical_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1632        return FAILURE;
1633    }
1634    Z_LVAL_P(result) = !Z_LVAL_P(result);
1635    return SUCCESS;
1636}
1637/* }}} */
1638
1639ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1640{
1641    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1642        return FAILURE;
1643    }
1644    ZVAL_BOOL(result, (Z_LVAL_P(result) == 0));
1645    return SUCCESS;
1646}
1647/* }}} */
1648
1649ZEND_API int is_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1650{
1651    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1652        return FAILURE;
1653    }
1654    ZVAL_BOOL(result, (Z_LVAL_P(result) != 0));
1655    return SUCCESS;
1656}
1657/* }}} */
1658
1659ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1660{
1661    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1662        return FAILURE;
1663    }
1664    ZVAL_BOOL(result, (Z_LVAL_P(result) < 0));
1665    return SUCCESS;
1666}
1667/* }}} */
1668
1669ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1670{
1671    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1672        return FAILURE;
1673    }
1674    ZVAL_BOOL(result, (Z_LVAL_P(result) <= 0));
1675    return SUCCESS;
1676}
1677/* }}} */
1678
1679ZEND_API zend_bool instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool interfaces_only TSRMLS_DC) /* {{{ */
1680{
1681    zend_uint i;
1682
1683    for (i=0; i<instance_ce->num_interfaces; i++) {
1684        if (instanceof_function(instance_ce->interfaces[i], ce TSRMLS_CC)) {
1685            return 1;
1686        }
1687    }
1688    if (!interfaces_only) {
1689        while (instance_ce) {
1690            if (instance_ce == ce) {
1691                return 1;
1692            }
1693            instance_ce = instance_ce->parent;
1694        }
1695    }
1696
1697    return 0;
1698}
1699/* }}} */
1700
1701ZEND_API zend_bool instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce TSRMLS_DC) /* {{{ */
1702{
1703    return instanceof_function_ex(instance_ce, ce, 0 TSRMLS_CC);
1704}
1705/* }}} */
1706
1707#define LOWER_CASE 1
1708#define UPPER_CASE 2
1709#define NUMERIC 3
1710
1711static void increment_string(zval *str) /* {{{ */
1712{
1713    int carry=0;
1714    int pos=Z_STRLEN_P(str)-1;
1715    char *s=Z_STRVAL_P(str);
1716    char *t;
1717    int last=0; /* Shut up the compiler warning */
1718    int ch;
1719
1720    if (Z_STRLEN_P(str) == 0) {
1721        STR_FREE(Z_STRVAL_P(str));
1722        Z_STRVAL_P(str) = estrndup("1", sizeof("1")-1);
1723        Z_STRLEN_P(str) = 1;
1724        return;
1725    }
1726
1727    if (IS_INTERNED(s)) {
1728        s = (char*) emalloc(Z_STRLEN_P(str) + 1);
1729        memcpy(s, Z_STRVAL_P(str), Z_STRLEN_P(str) + 1);
1730        Z_STRVAL_P(str) = s;
1731    }
1732
1733    while (pos >= 0) {
1734        ch = s[pos];
1735        if (ch >= 'a' && ch <= 'z') {
1736            if (ch == 'z') {
1737                s[pos] = 'a';
1738                carry=1;
1739            } else {
1740                s[pos]++;
1741                carry=0;
1742            }
1743            last=LOWER_CASE;
1744        } else if (ch >= 'A' && ch <= 'Z') {
1745            if (ch == 'Z') {
1746                s[pos] = 'A';
1747                carry=1;
1748            } else {
1749                s[pos]++;
1750                carry=0;
1751            }
1752            last=UPPER_CASE;
1753        } else if (ch >= '0' && ch <= '9') {
1754            if (ch == '9') {
1755                s[pos] = '0';
1756                carry=1;
1757            } else {
1758                s[pos]++;
1759                carry=0;
1760            }
1761            last = NUMERIC;
1762        } else {
1763            carry=0;
1764            break;
1765        }
1766        if (carry == 0) {
1767            break;
1768        }
1769        pos--;
1770    }
1771
1772    if (carry) {
1773        t = (char *) emalloc(Z_STRLEN_P(str)+1+1);
1774        memcpy(t+1, Z_STRVAL_P(str), Z_STRLEN_P(str));
1775        Z_STRLEN_P(str)++;
1776        t[Z_STRLEN_P(str)] = '\0';
1777        switch (last) {
1778            case NUMERIC:
1779                t[0] = '1';
1780                break;
1781            case UPPER_CASE:
1782                t[0] = 'A';
1783                break;
1784            case LOWER_CASE:
1785                t[0] = 'a';
1786                break;
1787        }
1788        STR_FREE(Z_STRVAL_P(str));
1789        Z_STRVAL_P(str) = t;
1790    }
1791}
1792/* }}} */
1793
1794ZEND_API int increment_function(zval *op1) /* {{{ */
1795{
1796    switch (Z_TYPE_P(op1)) {
1797        case IS_LONG:
1798            if (Z_LVAL_P(op1) == LONG_MAX) {
1799                /* switch to double */
1800                double d = (double)Z_LVAL_P(op1);
1801                ZVAL_DOUBLE(op1, d+1);
1802            } else {
1803            Z_LVAL_P(op1)++;
1804            }
1805            break;
1806        case IS_DOUBLE:
1807            Z_DVAL_P(op1) = Z_DVAL_P(op1) + 1;
1808            break;
1809        case IS_NULL:
1810            ZVAL_LONG(op1, 1);
1811            break;
1812        case IS_STRING: {
1813                long lval;
1814                double dval;
1815
1816                switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
1817                    case IS_LONG:
1818                        str_efree(Z_STRVAL_P(op1));
1819                        if (lval == LONG_MAX) {
1820                            /* switch to double */
1821                            double d = (double)lval;
1822                            ZVAL_DOUBLE(op1, d+1);
1823                        } else {
1824                            ZVAL_LONG(op1, lval+1);
1825                        }
1826                        break;
1827                    case IS_DOUBLE:
1828                        str_efree(Z_STRVAL_P(op1));
1829                        ZVAL_DOUBLE(op1, dval+1);
1830                        break;
1831                    default:
1832                        /* Perl style string increment */
1833                        increment_string(op1);
1834                        break;
1835                }
1836            }
1837            break;
1838        default:
1839            return FAILURE;
1840    }
1841    return SUCCESS;
1842}
1843/* }}} */
1844
1845ZEND_API int decrement_function(zval *op1) /* {{{ */
1846{
1847    long lval;
1848    double dval;
1849
1850    switch (Z_TYPE_P(op1)) {
1851        case IS_LONG:
1852            if (Z_LVAL_P(op1) == LONG_MIN) {
1853                double d = (double)Z_LVAL_P(op1);
1854                ZVAL_DOUBLE(op1, d-1);
1855            } else {
1856            Z_LVAL_P(op1)--;
1857            }
1858            break;
1859        case IS_DOUBLE:
1860            Z_DVAL_P(op1) = Z_DVAL_P(op1) - 1;
1861            break;
1862        case IS_STRING:     /* Like perl we only support string increment */
1863            if (Z_STRLEN_P(op1) == 0) { /* consider as 0 */
1864                STR_FREE(Z_STRVAL_P(op1));
1865                ZVAL_LONG(op1, -1);
1866                break;
1867            }
1868            switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
1869                case IS_LONG:
1870                    STR_FREE(Z_STRVAL_P(op1));
1871                    if (lval == LONG_MIN) {
1872                        double d = (double)lval;
1873                        ZVAL_DOUBLE(op1, d-1);
1874                    } else {
1875                        ZVAL_LONG(op1, lval-1);
1876                    }
1877                    break;
1878                case IS_DOUBLE:
1879                    STR_FREE(Z_STRVAL_P(op1));
1880                    ZVAL_DOUBLE(op1, dval - 1);
1881                    break;
1882            }
1883            break;
1884        default:
1885            return FAILURE;
1886    }
1887
1888    return SUCCESS;
1889}
1890/* }}} */
1891
1892ZEND_API int zval_is_true(zval *op) /* {{{ */
1893{
1894    convert_to_boolean(op);
1895    return (Z_LVAL_P(op) ? 1 : 0);
1896}
1897/* }}} */
1898
1899#ifdef ZEND_USE_TOLOWER_L
1900ZEND_API void zend_update_current_locale(void) /* {{{ */
1901{
1902    current_locale = _get_current_locale();
1903}
1904/* }}} */
1905#endif
1906
1907ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, unsigned int length) /* {{{ */
1908{
1909    register unsigned char *str = (unsigned char*)source;
1910    register unsigned char *result = (unsigned char*)dest;
1911    register unsigned char *end = str + length;
1912
1913    while (str < end) {
1914        *result++ = zend_tolower((int)*str++);
1915    }
1916    *result = '\0';
1917
1918    return dest;
1919}
1920/* }}} */
1921
1922ZEND_API char *zend_str_tolower_dup(const char *source, unsigned int length) /* {{{ */
1923{
1924    return zend_str_tolower_copy((char *)emalloc(length+1), source, length);
1925}
1926/* }}} */
1927
1928ZEND_API void zend_str_tolower(char *str, unsigned int length) /* {{{ */
1929{
1930    register unsigned char *p = (unsigned char*)str;
1931    register unsigned char *end = p + length;
1932
1933    while (p < end) {
1934        *p = zend_tolower((int)*p);
1935        p++;
1936    }
1937}
1938/* }}} */
1939
1940ZEND_API int zend_binary_strcmp(const char *s1, uint len1, const char *s2, uint len2) /* {{{ */
1941{
1942    int retval;
1943
1944    if (s1 == s2) {
1945        return 0;
1946    }
1947    retval = memcmp(s1, s2, MIN(len1, len2));
1948    if (!retval) {
1949        return (len1 - len2);
1950    } else {
1951        return retval;
1952    }
1953}
1954/* }}} */
1955
1956ZEND_API int zend_binary_strncmp(const char *s1, uint len1, const char *s2, uint len2, uint length) /* {{{ */
1957{
1958    int retval;
1959
1960    if (s1 == s2) {
1961        return 0;
1962    }
1963    retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
1964    if (!retval) {
1965        return (MIN(length, len1) - MIN(length, len2));
1966    } else {
1967        return retval;
1968    }
1969}
1970/* }}} */
1971
1972ZEND_API int zend_binary_strcasecmp(const char *s1, uint len1, const char *s2, uint len2) /* {{{ */
1973{
1974    int len;
1975    int c1, c2;
1976
1977    if (s1 == s2) {
1978        return 0;
1979    }
1980
1981    len = MIN(len1, len2);
1982    while (len--) {
1983        c1 = zend_tolower((int)*(unsigned char *)s1++);
1984        c2 = zend_tolower((int)*(unsigned char *)s2++);
1985        if (c1 != c2) {
1986            return c1 - c2;
1987        }
1988    }
1989
1990    return len1 - len2;
1991}
1992/* }}} */
1993
1994ZEND_API int zend_binary_strncasecmp(const char *s1, uint len1, const char *s2, uint len2, uint length) /* {{{ */
1995{
1996    int len;
1997    int c1, c2;
1998
1999    if (s1 == s2) {
2000        return 0;
2001    }
2002    len = MIN(length, MIN(len1, len2));
2003    while (len--) {
2004        c1 = zend_tolower((int)*(unsigned char *)s1++);
2005        c2 = zend_tolower((int)*(unsigned char *)s2++);
2006        if (c1 != c2) {
2007            return c1 - c2;
2008        }
2009    }
2010
2011    return MIN(length, len1) - MIN(length, len2);
2012}
2013/* }}} */
2014
2015ZEND_API int zend_binary_zval_strcmp(zval *s1, zval *s2) /* {{{ */
2016{
2017    return zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2018}
2019/* }}} */
2020
2021ZEND_API int zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2022{
2023    return zend_binary_strncmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
2024}
2025/* }}} */
2026
2027ZEND_API int zend_binary_zval_strcasecmp(zval *s1, zval *s2) /* {{{ */
2028{
2029    return zend_binary_strcasecmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2030}
2031/* }}} */
2032
2033ZEND_API int zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2034{
2035    return zend_binary_strncasecmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
2036}
2037/* }}} */
2038
2039ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2) /* {{{ */
2040{
2041    int ret1, ret2;
2042    int oflow1, oflow2;
2043    long lval1, lval2;
2044    double dval1, dval2;
2045
2046    if ((ret1=is_numeric_string_ex(Z_STRVAL_P(s1), Z_STRLEN_P(s1), &lval1, &dval1, 0, &oflow1)) &&
2047        (ret2=is_numeric_string_ex(Z_STRVAL_P(s2), Z_STRLEN_P(s2), &lval2, &dval2, 0, &oflow2))) {
2048#if ULONG_MAX == 0xFFFFFFFF
2049        if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
2050            ((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
2051            || (oflow1 == -1 && dval1 < -9007199254740991.))) {
2052#else
2053        if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
2054#endif
2055            /* both values are integers overflown to the same side, and the
2056             * double comparison may have resulted in crucial accuracy lost */
2057            goto string_cmp;
2058        }
2059        if ((ret1==IS_DOUBLE) || (ret2==IS_DOUBLE)) {
2060            if (ret1!=IS_DOUBLE) {
2061                if (oflow2) {
2062                    /* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
2063                    ZVAL_LONG(result, -1 * oflow2);
2064                    return;
2065                }
2066                dval1 = (double) lval1;
2067            } else if (ret2!=IS_DOUBLE) {
2068                if (oflow1) {
2069                    ZVAL_LONG(result, oflow1);
2070                    return;
2071                }
2072                dval2 = (double) lval2;
2073            } else if (dval1 == dval2 && !zend_finite(dval1)) {
2074                /* Both values overflowed and have the same sign,
2075                 * so a numeric comparison would be inaccurate */
2076                goto string_cmp;
2077            }
2078            Z_DVAL_P(result) = dval1 - dval2;
2079            ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
2080        } else { /* they both have to be long's */
2081            ZVAL_LONG(result, lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0));
2082        }
2083    } else {
2084string_cmp:
2085        Z_LVAL_P(result) = zend_binary_zval_strcmp(s1, s2);
2086        ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(result)));
2087    }
2088}
2089/* }}} */
2090
2091static int hash_zval_compare_function(const zval **z1, const zval **z2 TSRMLS_DC) /* {{{ */
2092{
2093    zval result;
2094
2095    if (compare_function(&result, (zval *) *z1, (zval *) *z2 TSRMLS_CC)==FAILURE) {
2096        return 1;
2097    }
2098    return Z_LVAL(result);
2099}
2100/* }}} */
2101
2102ZEND_API int zend_compare_symbol_tables_i(HashTable *ht1, HashTable *ht2 TSRMLS_DC) /* {{{ */
2103{
2104    return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0 TSRMLS_CC);
2105}
2106/* }}} */
2107
2108ZEND_API void zend_compare_symbol_tables(zval *result, HashTable *ht1, HashTable *ht2 TSRMLS_DC) /* {{{ */
2109{
2110    ZVAL_LONG(result, ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0 TSRMLS_CC));
2111}
2112/* }}} */
2113
2114ZEND_API void zend_compare_arrays(zval *result, zval *a1, zval *a2 TSRMLS_DC) /* {{{ */
2115{
2116    zend_compare_symbol_tables(result, Z_ARRVAL_P(a1), Z_ARRVAL_P(a2) TSRMLS_CC);
2117}
2118/* }}} */
2119
2120ZEND_API void zend_compare_objects(zval *result, zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
2121{
2122    Z_TYPE_P(result) = IS_LONG;
2123
2124    if (Z_OBJ_HANDLE_P(o1) == Z_OBJ_HANDLE_P(o2)) {
2125        Z_LVAL_P(result) = 0;
2126        return;
2127    }
2128
2129    if (Z_OBJ_HT_P(o1)->compare_objects == NULL) {
2130        Z_LVAL_P(result) = 1;
2131    } else {
2132        Z_LVAL_P(result) = Z_OBJ_HT_P(o1)->compare_objects(o1, o2 TSRMLS_CC);
2133    }
2134}
2135/* }}} */
2136
2137ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) /* {{{ */
2138{
2139    TSRMLS_FETCH();
2140
2141    Z_STRLEN_P(op) = zend_spprintf(&Z_STRVAL_P(op), 0, "%.*G", (int) EG(precision), (double)Z_DVAL_P(op));
2142}
2143/* }}} */
2144
2145/*
2146 * Local variables:
2147 * tab-width: 4
2148 * c-basic-offset: 4
2149 * indent-tabs-mode: t
2150 * End:
2151 */
2152