1/*
2   +----------------------------------------------------------------------+
3   | Zend Engine                                                          |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1998-2013 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_FREE(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_FREE(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_FREE(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_FREE(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                    zendi_convert_scalar_to_number(op1, op1_copy, result);
861                    zendi_convert_scalar_to_number(op2, op2_copy, result);
862                    converted = 1;
863                } else {
864                    zend_error(E_ERROR, "Unsupported operand types");
865                    return FAILURE; /* unknown datatype */
866                }
867        }
868    }
869}
870/* }}} */
871
872ZEND_API int sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
873{
874    zval op1_copy, op2_copy;
875    int converted = 0;
876
877    while (1) {
878        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
879            case TYPE_PAIR(IS_LONG, IS_LONG): {
880                long lval = Z_LVAL_P(op1) - Z_LVAL_P(op2);
881
882                /* check for overflow by comparing sign bits */
883                if ((Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(op2) & LONG_SIGN_MASK)
884                    && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (lval & LONG_SIGN_MASK)) {
885
886                    ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2));
887                } else {
888                    ZVAL_LONG(result, lval);
889                }
890                return SUCCESS;
891
892            }
893            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
894                ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) - Z_DVAL_P(op2));
895                return SUCCESS;
896
897            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
898                ZVAL_DOUBLE(result, Z_DVAL_P(op1) - ((double)Z_LVAL_P(op2)));
899                return SUCCESS;
900
901            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
902                ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2));
903                return SUCCESS;
904
905            default:
906                if (!converted) {
907                    zendi_convert_scalar_to_number(op1, op1_copy, result);
908                    zendi_convert_scalar_to_number(op2, op2_copy, result);
909                    converted = 1;
910                } else {
911                    zend_error(E_ERROR, "Unsupported operand types");
912                    return FAILURE; /* unknown datatype */
913                }
914        }
915    }
916}
917/* }}} */
918
919ZEND_API int mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
920{
921    zval op1_copy, op2_copy;
922    int converted = 0;
923
924    while (1) {
925        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
926            case TYPE_PAIR(IS_LONG, IS_LONG): {
927                long overflow;
928
929                ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1),Z_LVAL_P(op2), Z_LVAL_P(result),Z_DVAL_P(result),overflow);
930                Z_TYPE_P(result) = overflow ? IS_DOUBLE : IS_LONG;
931                return SUCCESS;
932
933            }
934            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
935                ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2));
936                return SUCCESS;
937
938            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
939                ZVAL_DOUBLE(result, Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2)));
940                return SUCCESS;
941
942            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
943                ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2));
944                return SUCCESS;
945
946            default:
947                if (!converted) {
948                    zendi_convert_scalar_to_number(op1, op1_copy, result);
949                    zendi_convert_scalar_to_number(op2, op2_copy, result);
950                    converted = 1;
951                } else {
952                    zend_error(E_ERROR, "Unsupported operand types");
953                    return FAILURE; /* unknown datatype */
954                }
955        }
956    }
957}
958/* }}} */
959
960ZEND_API int div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
961{
962    zval op1_copy, op2_copy;
963    int converted = 0;
964
965    while (1) {
966        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
967            case TYPE_PAIR(IS_LONG, IS_LONG):
968                if (Z_LVAL_P(op2) == 0) {
969                    zend_error(E_WARNING, "Division by zero");
970                    ZVAL_BOOL(result, 0);
971                    return FAILURE;         /* division by zero */
972                } else if (Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == LONG_MIN) {
973                    /* Prevent overflow error/crash */
974                    ZVAL_DOUBLE(result, (double) LONG_MIN / -1);
975                    return SUCCESS;
976                }
977                if (Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0) { /* integer */
978                    ZVAL_LONG(result, Z_LVAL_P(op1) / Z_LVAL_P(op2));
979                } else {
980                    ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1)) / Z_LVAL_P(op2));
981                }
982                return SUCCESS;
983
984            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
985                if (Z_LVAL_P(op2) == 0) {
986                    zend_error(E_WARNING, "Division by zero");
987                    ZVAL_BOOL(result, 0);
988                    return FAILURE;         /* division by zero */
989                }
990                ZVAL_DOUBLE(result, Z_DVAL_P(op1) / (double)Z_LVAL_P(op2));
991                return SUCCESS;
992
993            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
994                if (Z_DVAL_P(op2) == 0) {
995                    zend_error(E_WARNING, "Division by zero");
996                    ZVAL_BOOL(result, 0);
997                    return FAILURE;         /* division by zero */
998                }
999                ZVAL_DOUBLE(result, (double)Z_LVAL_P(op1) / Z_DVAL_P(op2));
1000                return SUCCESS;
1001
1002            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1003                if (Z_DVAL_P(op2) == 0) {
1004                    zend_error(E_WARNING, "Division by zero");
1005                    ZVAL_BOOL(result, 0);
1006                    return FAILURE;         /* division by zero */
1007                }
1008                ZVAL_DOUBLE(result, Z_DVAL_P(op1) / Z_DVAL_P(op2));
1009                return SUCCESS;
1010
1011            default:
1012                if (!converted) {
1013                    zendi_convert_scalar_to_number(op1, op1_copy, result);
1014                    zendi_convert_scalar_to_number(op2, op2_copy, result);
1015                    converted = 1;
1016                } else {
1017                    zend_error(E_ERROR, "Unsupported operand types");
1018                    return FAILURE; /* unknown datatype */
1019                }
1020        }
1021    }
1022}
1023/* }}} */
1024
1025ZEND_API int mod_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1026{
1027    zval op1_copy, op2_copy;
1028    long op1_lval;
1029
1030    zendi_convert_to_long(op1, op1_copy, result);
1031    op1_lval = Z_LVAL_P(op1);
1032    zendi_convert_to_long(op2, op2_copy, result);
1033
1034    if (Z_LVAL_P(op2) == 0) {
1035        zend_error(E_WARNING, "Division by zero");
1036        ZVAL_BOOL(result, 0);
1037        return FAILURE;         /* modulus by zero */
1038    }
1039
1040    if (Z_LVAL_P(op2) == -1) {
1041        /* Prevent overflow error/crash if op1==LONG_MIN */
1042        ZVAL_LONG(result, 0);
1043        return SUCCESS;
1044    }
1045
1046    ZVAL_LONG(result, op1_lval % Z_LVAL_P(op2));
1047    return SUCCESS;
1048}
1049/* }}} */
1050
1051ZEND_API int boolean_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1052{
1053    zval op1_copy, op2_copy;
1054    long op1_lval;
1055
1056    zendi_convert_to_boolean(op1, op1_copy, result);
1057    op1_lval = Z_LVAL_P(op1);
1058    zendi_convert_to_boolean(op2, op2_copy, result);
1059    ZVAL_BOOL(result, op1_lval ^ Z_LVAL_P(op2));
1060    return SUCCESS;
1061}
1062/* }}} */
1063
1064ZEND_API int boolean_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */
1065{
1066    zval op1_copy;
1067
1068    zendi_convert_to_boolean(op1, op1_copy, result);
1069    ZVAL_BOOL(result, !Z_LVAL_P(op1));
1070    return SUCCESS;
1071}
1072/* }}} */
1073
1074ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */
1075{
1076    zval op1_copy = *op1;
1077
1078    op1 = &op1_copy;
1079
1080    if (Z_TYPE_P(op1) == IS_LONG) {
1081        ZVAL_LONG(result, ~Z_LVAL_P(op1));
1082        return SUCCESS;
1083    } else if (Z_TYPE_P(op1) == IS_DOUBLE) {
1084        ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1)));
1085        return SUCCESS;
1086    } else if (Z_TYPE_P(op1) == IS_STRING) {
1087        int i;
1088
1089        Z_TYPE_P(result) = IS_STRING;
1090        Z_STRVAL_P(result) = estrndup(Z_STRVAL_P(op1), Z_STRLEN_P(op1));
1091        Z_STRLEN_P(result) = Z_STRLEN_P(op1);
1092        for (i = 0; i < Z_STRLEN_P(op1); i++) {
1093            Z_STRVAL_P(result)[i] = ~Z_STRVAL_P(op1)[i];
1094        }
1095        return SUCCESS;
1096    }
1097    zend_error(E_ERROR, "Unsupported operand types");
1098    return FAILURE;             /* unknown datatype */
1099}
1100/* }}} */
1101
1102ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1103{
1104    zval op1_copy, op2_copy;
1105    long op1_lval;
1106
1107    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1108        zval *longer, *shorter;
1109        char *result_str;
1110        int i, result_len;
1111
1112        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1113            longer = op1;
1114            shorter = op2;
1115        } else {
1116            longer = op2;
1117            shorter = op1;
1118        }
1119
1120        Z_TYPE_P(result) = IS_STRING;
1121        result_len = Z_STRLEN_P(longer);
1122        result_str = estrndup(Z_STRVAL_P(longer), Z_STRLEN_P(longer));
1123        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1124            result_str[i] |= Z_STRVAL_P(shorter)[i];
1125        }
1126        if (result==op1) {
1127            STR_FREE(Z_STRVAL_P(result));
1128        }
1129        Z_STRVAL_P(result) = result_str;
1130        Z_STRLEN_P(result) = result_len;
1131        return SUCCESS;
1132    }
1133    zendi_convert_to_long(op1, op1_copy, result);
1134    op1_lval = Z_LVAL_P(op1);
1135    zendi_convert_to_long(op2, op2_copy, result);
1136
1137    ZVAL_LONG(result, op1_lval | Z_LVAL_P(op2));
1138    return SUCCESS;
1139}
1140/* }}} */
1141
1142ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1143{
1144    zval op1_copy, op2_copy;
1145    long op1_lval;
1146
1147    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1148        zval *longer, *shorter;
1149        char *result_str;
1150        int i, result_len;
1151
1152        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1153            longer = op1;
1154            shorter = op2;
1155        } else {
1156            longer = op2;
1157            shorter = op1;
1158        }
1159
1160        Z_TYPE_P(result) = IS_STRING;
1161        result_len = Z_STRLEN_P(shorter);
1162        result_str = estrndup(Z_STRVAL_P(shorter), Z_STRLEN_P(shorter));
1163        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1164            result_str[i] &= Z_STRVAL_P(longer)[i];
1165        }
1166        if (result==op1) {
1167            STR_FREE(Z_STRVAL_P(result));
1168        }
1169        Z_STRVAL_P(result) = result_str;
1170        Z_STRLEN_P(result) = result_len;
1171        return SUCCESS;
1172    }
1173
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
1179    ZVAL_LONG(result, op1_lval & Z_LVAL_P(op2));
1180    return SUCCESS;
1181}
1182/* }}} */
1183
1184ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1185{
1186    zval op1_copy, op2_copy;
1187    long op1_lval;
1188
1189    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1190        zval *longer, *shorter;
1191        char *result_str;
1192        int i, result_len;
1193
1194        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1195            longer = op1;
1196            shorter = op2;
1197        } else {
1198            longer = op2;
1199            shorter = op1;
1200        }
1201
1202        Z_TYPE_P(result) = IS_STRING;
1203        result_len = Z_STRLEN_P(shorter);
1204        result_str = estrndup(Z_STRVAL_P(shorter), Z_STRLEN_P(shorter));
1205        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1206            result_str[i] ^= Z_STRVAL_P(longer)[i];
1207        }
1208        if (result==op1) {
1209            STR_FREE(Z_STRVAL_P(result));
1210        }
1211        Z_STRVAL_P(result) = result_str;
1212        Z_STRLEN_P(result) = result_len;
1213        return SUCCESS;
1214    }
1215
1216    zendi_convert_to_long(op1, op1_copy, result);
1217    op1_lval = Z_LVAL_P(op1);
1218    zendi_convert_to_long(op2, op2_copy, result);
1219
1220    ZVAL_LONG(result, op1_lval ^ Z_LVAL_P(op2));
1221    return SUCCESS;
1222}
1223/* }}} */
1224
1225ZEND_API int shift_left_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1226{
1227    zval op1_copy, op2_copy;
1228    long op1_lval;
1229
1230    zendi_convert_to_long(op1, op1_copy, result);
1231    op1_lval = Z_LVAL_P(op1);
1232    zendi_convert_to_long(op2, op2_copy, result);
1233    ZVAL_LONG(result, op1_lval << Z_LVAL_P(op2));
1234    return SUCCESS;
1235}
1236/* }}} */
1237
1238ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1239{
1240    zval op1_copy, op2_copy;
1241    long op1_lval;
1242
1243    zendi_convert_to_long(op1, op1_copy, result);
1244    op1_lval = Z_LVAL_P(op1);
1245    zendi_convert_to_long(op2, op2_copy, result);
1246    ZVAL_LONG(result, op1_lval >> Z_LVAL_P(op2));
1247    return SUCCESS;
1248}
1249/* }}} */
1250
1251/* must support result==op1 */
1252ZEND_API int add_char_to_string(zval *result, const zval *op1, const zval *op2) /* {{{ */
1253{
1254    int length = Z_STRLEN_P(op1) + 1;
1255    char *buf;
1256
1257    if (IS_INTERNED(Z_STRVAL_P(op1))) {
1258        buf = (char *) emalloc(length + 1);
1259        memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1));
1260    } else {
1261        buf = (char *) erealloc(Z_STRVAL_P(op1), length + 1);
1262    }
1263    buf[length - 1] = (char) Z_LVAL_P(op2);
1264    buf[length] = 0;
1265    ZVAL_STRINGL(result, buf, length, 0);
1266    return SUCCESS;
1267}
1268/* }}} */
1269
1270/* must support result==op1 */
1271ZEND_API int add_string_to_string(zval *result, const zval *op1, const zval *op2) /* {{{ */
1272{
1273    int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
1274    char *buf;
1275
1276    if (IS_INTERNED(Z_STRVAL_P(op1))) {
1277        buf = (char *) emalloc(length+1);
1278        memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1));
1279    } else {
1280        buf = (char *) erealloc(Z_STRVAL_P(op1), length+1);
1281    }
1282    memcpy(buf + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1283    buf[length] = 0;
1284    ZVAL_STRINGL(result, buf, length, 0);
1285    return SUCCESS;
1286}
1287/* }}} */
1288
1289ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1290{
1291    zval op1_copy, op2_copy;
1292    int use_copy1 = 0, use_copy2 = 0;
1293
1294    if (Z_TYPE_P(op1) != IS_STRING) {
1295        zend_make_printable_zval(op1, &op1_copy, &use_copy1);
1296    }
1297    if (Z_TYPE_P(op2) != IS_STRING) {
1298        zend_make_printable_zval(op2, &op2_copy, &use_copy2);
1299    }
1300
1301    if (use_copy1) {
1302        /* We have created a converted copy of op1. Therefore, op1 won't become the result so
1303         * we have to free it.
1304         */
1305        if (result == op1) {
1306            zval_dtor(op1);
1307        }
1308        op1 = &op1_copy;
1309    }
1310    if (use_copy2) {
1311        op2 = &op2_copy;
1312    }
1313    if (result==op1 && !IS_INTERNED(Z_STRVAL_P(op1))) { /* special case, perform operations on result */
1314        uint res_len = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
1315
1316        if (Z_STRLEN_P(result) < 0 || (int) (Z_STRLEN_P(op1) + Z_STRLEN_P(op2)) < 0) {
1317            efree(Z_STRVAL_P(result));
1318            ZVAL_EMPTY_STRING(result);
1319            zend_error(E_ERROR, "String size overflow");
1320        }
1321
1322        Z_STRVAL_P(result) = erealloc(Z_STRVAL_P(result), res_len+1);
1323
1324        memcpy(Z_STRVAL_P(result)+Z_STRLEN_P(result), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1325        Z_STRVAL_P(result)[res_len]=0;
1326        Z_STRLEN_P(result) = res_len;
1327    } else {
1328        int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
1329        char *buf = (char *) emalloc(length + 1);
1330
1331        memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1));
1332        memcpy(buf + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1333        buf[length] = 0;
1334        ZVAL_STRINGL(result, buf, length, 0);
1335    }
1336    if (use_copy1) {
1337        zval_dtor(op1);
1338    }
1339    if (use_copy2) {
1340        zval_dtor(op2);
1341    }
1342    return SUCCESS;
1343}
1344/* }}} */
1345
1346ZEND_API int string_compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool case_insensitive TSRMLS_DC) /* {{{ */
1347{
1348    zval op1_copy, op2_copy;
1349    int use_copy1 = 0, use_copy2 = 0;
1350
1351    if (Z_TYPE_P(op1) != IS_STRING) {
1352        zend_make_printable_zval(op1, &op1_copy, &use_copy1);
1353    }
1354    if (Z_TYPE_P(op2) != IS_STRING) {
1355        zend_make_printable_zval(op2, &op2_copy, &use_copy2);
1356    }
1357
1358    if (use_copy1) {
1359        op1 = &op1_copy;
1360    }
1361    if (use_copy2) {
1362        op2 = &op2_copy;
1363    }
1364
1365    if (case_insensitive) {
1366        ZVAL_LONG(result, zend_binary_zval_strcasecmp(op1, op2));
1367    } else {
1368        ZVAL_LONG(result, zend_binary_zval_strcmp(op1, op2));
1369    }
1370
1371    if (use_copy1) {
1372        zval_dtor(op1);
1373    }
1374    if (use_copy2) {
1375        zval_dtor(op2);
1376    }
1377    return SUCCESS;
1378}
1379/* }}} */
1380
1381ZEND_API int string_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1382{
1383    return string_compare_function_ex(result, op1, op2, 0 TSRMLS_CC);
1384}
1385/* }}} */
1386
1387ZEND_API int string_case_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1388{
1389    return string_compare_function_ex(result, op1, op2, 1 TSRMLS_CC);
1390}
1391/* }}} */
1392
1393#if HAVE_STRCOLL
1394ZEND_API int string_locale_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1395{
1396    zval op1_copy, op2_copy;
1397    int use_copy1 = 0, use_copy2 = 0;
1398
1399    if (Z_TYPE_P(op1) != IS_STRING) {
1400        zend_make_printable_zval(op1, &op1_copy, &use_copy1);
1401    }
1402    if (Z_TYPE_P(op2) != IS_STRING) {
1403        zend_make_printable_zval(op2, &op2_copy, &use_copy2);
1404    }
1405
1406    if (use_copy1) {
1407        op1 = &op1_copy;
1408    }
1409    if (use_copy2) {
1410        op2 = &op2_copy;
1411    }
1412
1413    ZVAL_LONG(result, strcoll(Z_STRVAL_P(op1), Z_STRVAL_P(op2)));
1414
1415    if (use_copy1) {
1416        zval_dtor(op1);
1417    }
1418    if (use_copy2) {
1419        zval_dtor(op2);
1420    }
1421    return SUCCESS;
1422}
1423/* }}} */
1424#endif
1425
1426ZEND_API int numeric_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1427{
1428    zval op1_copy, op2_copy;
1429
1430    op1_copy = *op1;
1431    zval_copy_ctor(&op1_copy);
1432
1433    op2_copy = *op2;
1434    zval_copy_ctor(&op2_copy);
1435
1436    convert_to_double(&op1_copy);
1437    convert_to_double(&op2_copy);
1438
1439    ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL(op1_copy)-Z_DVAL(op2_copy)));
1440
1441    return SUCCESS;
1442}
1443/* }}} */
1444
1445static inline void zend_free_obj_get_result(zval *op TSRMLS_DC) /* {{{ */
1446{
1447    if (Z_REFCOUNT_P(op) == 0) {
1448        GC_REMOVE_ZVAL_FROM_BUFFER(op);
1449        zval_dtor(op);
1450        FREE_ZVAL(op);
1451    } else {
1452        zval_ptr_dtor(&op);
1453    }
1454}
1455/* }}} */
1456
1457ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1458{
1459    int ret;
1460    int converted = 0;
1461    zval op1_copy, op2_copy;
1462    zval *op_free;
1463
1464    while (1) {
1465        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
1466            case TYPE_PAIR(IS_LONG, IS_LONG):
1467                ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0));
1468                return SUCCESS;
1469
1470            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1471                Z_DVAL_P(result) = Z_DVAL_P(op1) - (double)Z_LVAL_P(op2);
1472                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1473                return SUCCESS;
1474
1475            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1476                Z_DVAL_P(result) = (double)Z_LVAL_P(op1) - Z_DVAL_P(op2);
1477                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1478                return SUCCESS;
1479
1480            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1481                if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
1482                    ZVAL_LONG(result, 0);
1483                } else {
1484                    Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2);
1485                    ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1486                }
1487                return SUCCESS;
1488
1489            case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
1490                zend_compare_arrays(result, op1, op2 TSRMLS_CC);
1491                return SUCCESS;
1492
1493            case TYPE_PAIR(IS_NULL, IS_NULL):
1494                ZVAL_LONG(result, 0);
1495                return SUCCESS;
1496
1497            case TYPE_PAIR(IS_NULL, IS_BOOL):
1498                ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0);
1499                return SUCCESS;
1500
1501            case TYPE_PAIR(IS_BOOL, IS_NULL):
1502                ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0);
1503                return SUCCESS;
1504
1505            case TYPE_PAIR(IS_BOOL, IS_BOOL):
1506                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1507                return SUCCESS;
1508
1509            case TYPE_PAIR(IS_STRING, IS_STRING):
1510                zendi_smart_strcmp(result, op1, op2);
1511                return SUCCESS;
1512
1513            case TYPE_PAIR(IS_NULL, IS_STRING):
1514                ZVAL_LONG(result, zend_binary_strcmp("", 0, Z_STRVAL_P(op2), Z_STRLEN_P(op2)));
1515                return SUCCESS;
1516
1517            case TYPE_PAIR(IS_STRING, IS_NULL):
1518                ZVAL_LONG(result, zend_binary_strcmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), "", 0));
1519                return SUCCESS;
1520
1521            case TYPE_PAIR(IS_OBJECT, IS_NULL):
1522                ZVAL_LONG(result, 1);
1523                return SUCCESS;
1524
1525            case TYPE_PAIR(IS_NULL, IS_OBJECT):
1526                ZVAL_LONG(result, -1);
1527                return SUCCESS;
1528
1529            case TYPE_PAIR(IS_OBJECT, IS_OBJECT):
1530                /* If both are objects sharing the same comparision handler then use is */
1531                if (Z_OBJ_HANDLER_P(op1,compare_objects) == Z_OBJ_HANDLER_P(op2,compare_objects)) {
1532                    if (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2)) {
1533                        /* object handles are identical, apprently this is the same object */
1534                        ZVAL_LONG(result, 0);
1535                        return SUCCESS;
1536                    }
1537                    ZVAL_LONG(result, Z_OBJ_HT_P(op1)->compare_objects(op1, op2 TSRMLS_CC));
1538                    return SUCCESS;
1539                }
1540                /* break missing intentionally */
1541
1542            default:
1543                if (Z_TYPE_P(op1) == IS_OBJECT) {
1544                    if (Z_OBJ_HT_P(op1)->get) {
1545                        op_free = Z_OBJ_HT_P(op1)->get(op1 TSRMLS_CC);
1546                        ret = compare_function(result, op_free, op2 TSRMLS_CC);
1547                        zend_free_obj_get_result(op_free TSRMLS_CC);
1548                        return ret;
1549                    } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) {
1550                        ALLOC_INIT_ZVAL(op_free);
1551                        if (Z_OBJ_HT_P(op1)->cast_object(op1, op_free, Z_TYPE_P(op2) TSRMLS_CC) == FAILURE) {
1552                            ZVAL_LONG(result, 1);
1553                            zend_free_obj_get_result(op_free TSRMLS_CC);
1554                            return SUCCESS;
1555                        }
1556                        ret = compare_function(result, op_free, op2 TSRMLS_CC);
1557                        zend_free_obj_get_result(op_free TSRMLS_CC);
1558                        return ret;
1559                    }
1560                }
1561                if (Z_TYPE_P(op2) == IS_OBJECT) {
1562                    if (Z_OBJ_HT_P(op2)->get) {
1563                        op_free = Z_OBJ_HT_P(op2)->get(op2 TSRMLS_CC);
1564                        ret = compare_function(result, op1, op_free TSRMLS_CC);
1565                        zend_free_obj_get_result(op_free TSRMLS_CC);
1566                        return ret;
1567                    } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) {
1568                        ALLOC_INIT_ZVAL(op_free);
1569                        if (Z_OBJ_HT_P(op2)->cast_object(op2, op_free, Z_TYPE_P(op1) TSRMLS_CC) == FAILURE) {
1570                            ZVAL_LONG(result, -1);
1571                            zend_free_obj_get_result(op_free TSRMLS_CC);
1572                            return SUCCESS;
1573                        }
1574                        ret = compare_function(result, op1, op_free TSRMLS_CC);
1575                        zend_free_obj_get_result(op_free TSRMLS_CC);
1576                        return ret;
1577                    } else if (Z_TYPE_P(op1) == IS_OBJECT) {
1578                        ZVAL_LONG(result, 1);
1579                        return SUCCESS;
1580                    }
1581                }
1582                if (!converted) {
1583                    if (Z_TYPE_P(op1) == IS_NULL) {
1584                        zendi_convert_to_boolean(op2, op2_copy, result);
1585                        ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0);
1586                        return SUCCESS;
1587                    } else if (Z_TYPE_P(op2) == IS_NULL) {
1588                        zendi_convert_to_boolean(op1, op1_copy, result);
1589                        ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0);
1590                        return SUCCESS;
1591                    } else if (Z_TYPE_P(op1) == IS_BOOL) {
1592                        zendi_convert_to_boolean(op2, op2_copy, result);
1593                        ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1594                        return SUCCESS;
1595                    } else if (Z_TYPE_P(op2) == IS_BOOL) {
1596                        zendi_convert_to_boolean(op1, op1_copy, result);
1597                        ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1598                        return SUCCESS;
1599                    } else {
1600                        zendi_convert_scalar_to_number(op1, op1_copy, result);
1601                        zendi_convert_scalar_to_number(op2, op2_copy, result);
1602                        converted = 1;
1603                    }
1604                } else if (Z_TYPE_P(op1)==IS_ARRAY) {
1605                    ZVAL_LONG(result, 1);
1606                    return SUCCESS;
1607                } else if (Z_TYPE_P(op2)==IS_ARRAY) {
1608                    ZVAL_LONG(result, -1);
1609                    return SUCCESS;
1610                } else if (Z_TYPE_P(op1)==IS_OBJECT) {
1611                    ZVAL_LONG(result, 1);
1612                    return SUCCESS;
1613                } else if (Z_TYPE_P(op2)==IS_OBJECT) {
1614                    ZVAL_LONG(result, -1);
1615                    return SUCCESS;
1616                } else {
1617                    ZVAL_LONG(result, 0);
1618                    return FAILURE;
1619                }
1620        }
1621    }
1622}
1623/* }}} */
1624
1625static int hash_zval_identical_function(const zval **z1, const zval **z2) /* {{{ */
1626{
1627    zval result;
1628    TSRMLS_FETCH();
1629
1630    /* is_identical_function() returns 1 in case of identity and 0 in case
1631     * of a difference;
1632     * whereas this comparison function is expected to return 0 on identity,
1633     * and non zero otherwise.
1634     */
1635    if (is_identical_function(&result, (zval *) *z1, (zval *) *z2 TSRMLS_CC)==FAILURE) {
1636        return 1;
1637    }
1638    return !Z_LVAL(result);
1639}
1640/* }}} */
1641
1642ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1643{
1644    Z_TYPE_P(result) = IS_BOOL;
1645    if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
1646        Z_LVAL_P(result) = 0;
1647        return SUCCESS;
1648    }
1649    switch (Z_TYPE_P(op1)) {
1650        case IS_NULL:
1651            Z_LVAL_P(result) = 1;
1652            break;
1653        case IS_BOOL:
1654        case IS_LONG:
1655        case IS_RESOURCE:
1656            Z_LVAL_P(result) = (Z_LVAL_P(op1) == Z_LVAL_P(op2));
1657            break;
1658        case IS_DOUBLE:
1659            Z_LVAL_P(result) = (Z_DVAL_P(op1) == Z_DVAL_P(op2));
1660            break;
1661        case IS_STRING:
1662            Z_LVAL_P(result) = ((Z_STRLEN_P(op1) == Z_STRLEN_P(op2))
1663                && (!memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1))));
1664            break;
1665        case IS_ARRAY:
1666            Z_LVAL_P(result) = (Z_ARRVAL_P(op1) == Z_ARRVAL_P(op2) ||
1667                zend_hash_compare(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2), (compare_func_t) hash_zval_identical_function, 1 TSRMLS_CC)==0);
1668            break;
1669        case IS_OBJECT:
1670            if (Z_OBJ_HT_P(op1) == Z_OBJ_HT_P(op2)) {
1671                Z_LVAL_P(result) = (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2));
1672            } else {
1673                Z_LVAL_P(result) = 0;
1674            }
1675            break;
1676        default:
1677            Z_LVAL_P(result) = 0;
1678            return FAILURE;
1679    }
1680    return SUCCESS;
1681}
1682/* }}} */
1683
1684ZEND_API int is_not_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1685{
1686    if (is_identical_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1687        return FAILURE;
1688    }
1689    Z_LVAL_P(result) = !Z_LVAL_P(result);
1690    return SUCCESS;
1691}
1692/* }}} */
1693
1694ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1695{
1696    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1697        return FAILURE;
1698    }
1699    ZVAL_BOOL(result, (Z_LVAL_P(result) == 0));
1700    return SUCCESS;
1701}
1702/* }}} */
1703
1704ZEND_API int is_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1705{
1706    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1707        return FAILURE;
1708    }
1709    ZVAL_BOOL(result, (Z_LVAL_P(result) != 0));
1710    return SUCCESS;
1711}
1712/* }}} */
1713
1714ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1715{
1716    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1717        return FAILURE;
1718    }
1719    ZVAL_BOOL(result, (Z_LVAL_P(result) < 0));
1720    return SUCCESS;
1721}
1722/* }}} */
1723
1724ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1725{
1726    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1727        return FAILURE;
1728    }
1729    ZVAL_BOOL(result, (Z_LVAL_P(result) <= 0));
1730    return SUCCESS;
1731}
1732/* }}} */
1733
1734ZEND_API zend_bool instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool interfaces_only TSRMLS_DC) /* {{{ */
1735{
1736    zend_uint i;
1737
1738    for (i=0; i<instance_ce->num_interfaces; i++) {
1739        if (instanceof_function(instance_ce->interfaces[i], ce TSRMLS_CC)) {
1740            return 1;
1741        }
1742    }
1743    if (!interfaces_only) {
1744        while (instance_ce) {
1745            if (instance_ce == ce) {
1746                return 1;
1747            }
1748            instance_ce = instance_ce->parent;
1749        }
1750    }
1751
1752    return 0;
1753}
1754/* }}} */
1755
1756ZEND_API zend_bool instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce TSRMLS_DC) /* {{{ */
1757{
1758    return instanceof_function_ex(instance_ce, ce, 0 TSRMLS_CC);
1759}
1760/* }}} */
1761
1762#define LOWER_CASE 1
1763#define UPPER_CASE 2
1764#define NUMERIC 3
1765
1766static void increment_string(zval *str) /* {{{ */
1767{
1768    int carry=0;
1769    int pos=Z_STRLEN_P(str)-1;
1770    char *s=Z_STRVAL_P(str);
1771    char *t;
1772    int last=0; /* Shut up the compiler warning */
1773    int ch;
1774
1775    if (Z_STRLEN_P(str) == 0) {
1776        STR_FREE(Z_STRVAL_P(str));
1777        Z_STRVAL_P(str) = estrndup("1", sizeof("1")-1);
1778        Z_STRLEN_P(str) = 1;
1779        return;
1780    }
1781
1782    if (IS_INTERNED(s)) {
1783        s = (char*) emalloc(Z_STRLEN_P(str) + 1);
1784        memcpy(s, Z_STRVAL_P(str), Z_STRLEN_P(str) + 1);
1785        Z_STRVAL_P(str) = s;
1786    }
1787
1788    while (pos >= 0) {
1789        ch = s[pos];
1790        if (ch >= 'a' && ch <= 'z') {
1791            if (ch == 'z') {
1792                s[pos] = 'a';
1793                carry=1;
1794            } else {
1795                s[pos]++;
1796                carry=0;
1797            }
1798            last=LOWER_CASE;
1799        } else if (ch >= 'A' && ch <= 'Z') {
1800            if (ch == 'Z') {
1801                s[pos] = 'A';
1802                carry=1;
1803            } else {
1804                s[pos]++;
1805                carry=0;
1806            }
1807            last=UPPER_CASE;
1808        } else if (ch >= '0' && ch <= '9') {
1809            if (ch == '9') {
1810                s[pos] = '0';
1811                carry=1;
1812            } else {
1813                s[pos]++;
1814                carry=0;
1815            }
1816            last = NUMERIC;
1817        } else {
1818            carry=0;
1819            break;
1820        }
1821        if (carry == 0) {
1822            break;
1823        }
1824        pos--;
1825    }
1826
1827    if (carry) {
1828        t = (char *) emalloc(Z_STRLEN_P(str)+1+1);
1829        memcpy(t+1, Z_STRVAL_P(str), Z_STRLEN_P(str));
1830        Z_STRLEN_P(str)++;
1831        t[Z_STRLEN_P(str)] = '\0';
1832        switch (last) {
1833            case NUMERIC:
1834                t[0] = '1';
1835                break;
1836            case UPPER_CASE:
1837                t[0] = 'A';
1838                break;
1839            case LOWER_CASE:
1840                t[0] = 'a';
1841                break;
1842        }
1843        STR_FREE(Z_STRVAL_P(str));
1844        Z_STRVAL_P(str) = t;
1845    }
1846}
1847/* }}} */
1848
1849ZEND_API int increment_function(zval *op1) /* {{{ */
1850{
1851    switch (Z_TYPE_P(op1)) {
1852        case IS_LONG:
1853            if (Z_LVAL_P(op1) == LONG_MAX) {
1854                /* switch to double */
1855                double d = (double)Z_LVAL_P(op1);
1856                ZVAL_DOUBLE(op1, d+1);
1857            } else {
1858            Z_LVAL_P(op1)++;
1859            }
1860            break;
1861        case IS_DOUBLE:
1862            Z_DVAL_P(op1) = Z_DVAL_P(op1) + 1;
1863            break;
1864        case IS_NULL:
1865            ZVAL_LONG(op1, 1);
1866            break;
1867        case IS_STRING: {
1868                long lval;
1869                double dval;
1870
1871                switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
1872                    case IS_LONG:
1873                        str_efree(Z_STRVAL_P(op1));
1874                        if (lval == LONG_MAX) {
1875                            /* switch to double */
1876                            double d = (double)lval;
1877                            ZVAL_DOUBLE(op1, d+1);
1878                        } else {
1879                            ZVAL_LONG(op1, lval+1);
1880                        }
1881                        break;
1882                    case IS_DOUBLE:
1883                        str_efree(Z_STRVAL_P(op1));
1884                        ZVAL_DOUBLE(op1, dval+1);
1885                        break;
1886                    default:
1887                        /* Perl style string increment */
1888                        increment_string(op1);
1889                        break;
1890                }
1891            }
1892            break;
1893        default:
1894            return FAILURE;
1895    }
1896    return SUCCESS;
1897}
1898/* }}} */
1899
1900ZEND_API int decrement_function(zval *op1) /* {{{ */
1901{
1902    long lval;
1903    double dval;
1904
1905    switch (Z_TYPE_P(op1)) {
1906        case IS_LONG:
1907            if (Z_LVAL_P(op1) == LONG_MIN) {
1908                double d = (double)Z_LVAL_P(op1);
1909                ZVAL_DOUBLE(op1, d-1);
1910            } else {
1911            Z_LVAL_P(op1)--;
1912            }
1913            break;
1914        case IS_DOUBLE:
1915            Z_DVAL_P(op1) = Z_DVAL_P(op1) - 1;
1916            break;
1917        case IS_STRING:     /* Like perl we only support string increment */
1918            if (Z_STRLEN_P(op1) == 0) { /* consider as 0 */
1919                STR_FREE(Z_STRVAL_P(op1));
1920                ZVAL_LONG(op1, -1);
1921                break;
1922            }
1923            switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
1924                case IS_LONG:
1925                    STR_FREE(Z_STRVAL_P(op1));
1926                    if (lval == LONG_MIN) {
1927                        double d = (double)lval;
1928                        ZVAL_DOUBLE(op1, d-1);
1929                    } else {
1930                        ZVAL_LONG(op1, lval-1);
1931                    }
1932                    break;
1933                case IS_DOUBLE:
1934                    STR_FREE(Z_STRVAL_P(op1));
1935                    ZVAL_DOUBLE(op1, dval - 1);
1936                    break;
1937            }
1938            break;
1939        default:
1940            return FAILURE;
1941    }
1942
1943    return SUCCESS;
1944}
1945/* }}} */
1946
1947ZEND_API int zval_is_true(zval *op) /* {{{ */
1948{
1949    convert_to_boolean(op);
1950    return (Z_LVAL_P(op) ? 1 : 0);
1951}
1952/* }}} */
1953
1954#ifdef ZEND_USE_TOLOWER_L
1955ZEND_API void zend_update_current_locale(void) /* {{{ */
1956{
1957    current_locale = _get_current_locale();
1958}
1959/* }}} */
1960#endif
1961
1962ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, unsigned int length) /* {{{ */
1963{
1964    register unsigned char *str = (unsigned char*)source;
1965    register unsigned char *result = (unsigned char*)dest;
1966    register unsigned char *end = str + length;
1967
1968    while (str < end) {
1969        *result++ = zend_tolower_ascii(*str++);
1970    }
1971    *result = '\0';
1972
1973    return dest;
1974}
1975/* }}} */
1976
1977ZEND_API char *zend_str_tolower_dup(const char *source, unsigned int length) /* {{{ */
1978{
1979    return zend_str_tolower_copy((char *)emalloc(length+1), source, length);
1980}
1981/* }}} */
1982
1983ZEND_API void zend_str_tolower(char *str, unsigned int length) /* {{{ */
1984{
1985    register unsigned char *p = (unsigned char*)str;
1986    register unsigned char *end = p + length;
1987
1988    while (p < end) {
1989        *p = zend_tolower_ascii(*p);
1990        p++;
1991    }
1992}
1993/* }}} */
1994
1995ZEND_API int zend_binary_strcmp(const char *s1, uint len1, const char *s2, uint len2) /* {{{ */
1996{
1997    int retval;
1998
1999    if (s1 == s2) {
2000        return 0;
2001    }
2002    retval = memcmp(s1, s2, MIN(len1, len2));
2003    if (!retval) {
2004        return (len1 - len2);
2005    } else {
2006        return retval;
2007    }
2008}
2009/* }}} */
2010
2011ZEND_API int zend_binary_strncmp(const char *s1, uint len1, const char *s2, uint len2, uint length) /* {{{ */
2012{
2013    int retval;
2014
2015    if (s1 == s2) {
2016        return 0;
2017    }
2018    retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
2019    if (!retval) {
2020        return (MIN(length, len1) - MIN(length, len2));
2021    } else {
2022        return retval;
2023    }
2024}
2025/* }}} */
2026
2027ZEND_API int zend_binary_strcasecmp(const char *s1, uint len1, const char *s2, uint len2) /* {{{ */
2028{
2029    int len;
2030    int c1, c2;
2031
2032    if (s1 == s2) {
2033        return 0;
2034    }
2035
2036    len = MIN(len1, len2);
2037    while (len--) {
2038        c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2039        c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2040        if (c1 != c2) {
2041            return c1 - c2;
2042        }
2043    }
2044
2045    return len1 - len2;
2046}
2047/* }}} */
2048
2049ZEND_API int zend_binary_strncasecmp(const char *s1, uint len1, const char *s2, uint len2, uint length) /* {{{ */
2050{
2051    int len;
2052    int c1, c2;
2053
2054    if (s1 == s2) {
2055        return 0;
2056    }
2057    len = MIN(length, MIN(len1, len2));
2058    while (len--) {
2059        c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2060        c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2061        if (c1 != c2) {
2062            return c1 - c2;
2063        }
2064    }
2065
2066    return MIN(length, len1) - MIN(length, len2);
2067}
2068/* }}} */
2069
2070ZEND_API int zend_binary_strcasecmp_l(const char *s1, uint len1, const char *s2, uint len2) /* {{{ */
2071{
2072    int len;
2073    int c1, c2;
2074
2075    if (s1 == s2) {
2076        return 0;
2077    }
2078
2079    len = MIN(len1, len2);
2080    while (len--) {
2081        c1 = zend_tolower((int)*(unsigned char *)s1++);
2082        c2 = zend_tolower((int)*(unsigned char *)s2++);
2083        if (c1 != c2) {
2084            return c1 - c2;
2085        }
2086    }
2087
2088    return len1 - len2;
2089}
2090/* }}} */
2091
2092ZEND_API int zend_binary_strncasecmp_l(const char *s1, uint len1, const char *s2, uint len2, uint length) /* {{{ */
2093{
2094    int len;
2095    int c1, c2;
2096
2097    if (s1 == s2) {
2098        return 0;
2099    }
2100    len = MIN(length, MIN(len1, len2));
2101    while (len--) {
2102        c1 = zend_tolower((int)*(unsigned char *)s1++);
2103        c2 = zend_tolower((int)*(unsigned char *)s2++);
2104        if (c1 != c2) {
2105            return c1 - c2;
2106        }
2107    }
2108
2109    return MIN(length, len1) - MIN(length, len2);
2110}
2111/* }}} */
2112
2113ZEND_API int zend_binary_zval_strcmp(zval *s1, zval *s2) /* {{{ */
2114{
2115    return zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2116}
2117/* }}} */
2118
2119ZEND_API int zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2120{
2121    return zend_binary_strncmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
2122}
2123/* }}} */
2124
2125ZEND_API int zend_binary_zval_strcasecmp(zval *s1, zval *s2) /* {{{ */
2126{
2127    return zend_binary_strcasecmp_l(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2128}
2129/* }}} */
2130
2131ZEND_API int zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2132{
2133    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));
2134}
2135/* }}} */
2136
2137ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2) /* {{{ */
2138{
2139    int ret1, ret2;
2140    int oflow1, oflow2;
2141    long lval1, lval2;
2142    double dval1, dval2;
2143
2144    if ((ret1=is_numeric_string_ex(Z_STRVAL_P(s1), Z_STRLEN_P(s1), &lval1, &dval1, 0, &oflow1)) &&
2145        (ret2=is_numeric_string_ex(Z_STRVAL_P(s2), Z_STRLEN_P(s2), &lval2, &dval2, 0, &oflow2))) {
2146#if ULONG_MAX == 0xFFFFFFFF
2147        if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
2148            ((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
2149            || (oflow1 == -1 && dval1 < -9007199254740991.))) {
2150#else
2151        if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
2152#endif
2153            /* both values are integers overflown to the same side, and the
2154             * double comparison may have resulted in crucial accuracy lost */
2155            goto string_cmp;
2156        }
2157        if ((ret1==IS_DOUBLE) || (ret2==IS_DOUBLE)) {
2158            if (ret1!=IS_DOUBLE) {
2159                if (oflow2) {
2160                    /* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
2161                    ZVAL_LONG(result, -1 * oflow2);
2162                    return;
2163                }
2164                dval1 = (double) lval1;
2165            } else if (ret2!=IS_DOUBLE) {
2166                if (oflow1) {
2167                    ZVAL_LONG(result, oflow1);
2168                    return;
2169                }
2170                dval2 = (double) lval2;
2171            } else if (dval1 == dval2 && !zend_finite(dval1)) {
2172                /* Both values overflowed and have the same sign,
2173                 * so a numeric comparison would be inaccurate */
2174                goto string_cmp;
2175            }
2176            Z_DVAL_P(result) = dval1 - dval2;
2177            ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
2178        } else { /* they both have to be long's */
2179            ZVAL_LONG(result, lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0));
2180        }
2181    } else {
2182string_cmp:
2183        Z_LVAL_P(result) = zend_binary_zval_strcmp(s1, s2);
2184        ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(result)));
2185    }
2186}
2187/* }}} */
2188
2189static int hash_zval_compare_function(const zval **z1, const zval **z2 TSRMLS_DC) /* {{{ */
2190{
2191    zval result;
2192
2193    if (compare_function(&result, (zval *) *z1, (zval *) *z2 TSRMLS_CC)==FAILURE) {
2194        return 1;
2195    }
2196    return Z_LVAL(result);
2197}
2198/* }}} */
2199
2200ZEND_API int zend_compare_symbol_tables_i(HashTable *ht1, HashTable *ht2 TSRMLS_DC) /* {{{ */
2201{
2202    return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0 TSRMLS_CC);
2203}
2204/* }}} */
2205
2206ZEND_API void zend_compare_symbol_tables(zval *result, HashTable *ht1, HashTable *ht2 TSRMLS_DC) /* {{{ */
2207{
2208    ZVAL_LONG(result, ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0 TSRMLS_CC));
2209}
2210/* }}} */
2211
2212ZEND_API void zend_compare_arrays(zval *result, zval *a1, zval *a2 TSRMLS_DC) /* {{{ */
2213{
2214    zend_compare_symbol_tables(result, Z_ARRVAL_P(a1), Z_ARRVAL_P(a2) TSRMLS_CC);
2215}
2216/* }}} */
2217
2218ZEND_API void zend_compare_objects(zval *result, zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
2219{
2220    Z_TYPE_P(result) = IS_LONG;
2221
2222    if (Z_OBJ_HANDLE_P(o1) == Z_OBJ_HANDLE_P(o2)) {
2223        Z_LVAL_P(result) = 0;
2224        return;
2225    }
2226
2227    if (Z_OBJ_HT_P(o1)->compare_objects == NULL) {
2228        Z_LVAL_P(result) = 1;
2229    } else {
2230        Z_LVAL_P(result) = Z_OBJ_HT_P(o1)->compare_objects(o1, o2 TSRMLS_CC);
2231    }
2232}
2233/* }}} */
2234
2235ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) /* {{{ */
2236{
2237    TSRMLS_FETCH();
2238
2239    Z_STRLEN_P(op) = zend_spprintf(&Z_STRVAL_P(op), 0, "%.*G", (int) EG(precision), (double)Z_DVAL_P(op));
2240}
2241/* }}} */
2242
2243/*
2244 * Local variables:
2245 * tab-width: 4
2246 * c-basic-offset: 4
2247 * indent-tabs-mode: t
2248 * End:
2249 */
2250