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