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