File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / Zend / zend_operators.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:34:36 2012 UTC (12 years, 1 month ago) by misho
Branches: php, MAIN
CVS tags: v5_4_3elwix, v5_4_17p0, HEAD
php 5.4.3+patches

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>