Exemplo n.º 1
0
Arquivo: money.c Projeto: Peekmo/money
PHP_METHOD(Money, multiply)
{
	double factor;
	volatile double dresult;
	long rounding_mode = PHP_ROUND_HALF_UP, lresult;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "d|l", &factor, &rounding_mode) == FAILURE) {
		return;
	}

	if (UNEXPECTED(rounding_mode < 0 || rounding_mode > PHP_ROUND_HALF_ODD)) {
		zend_throw_exception(spl_ce_InvalidArgumentException, "$roundingMode must be a valid rounding mode (PHP_ROUND_*)", 0);
		return;
	}

	dresult = _php_math_round(factor * Z_LVAL_P(zend_read_property(money_ce, getThis(), MONEY_PROP_AMOUNT_WS, 0)), 0, rounding_mode);
	lresult = zend_dval_to_lval(dresult);

	if (UNEXPECTED(lresult & LONG_SIGN_MASK)) {
		zend_throw_exception(spl_ce_OverflowException, "Integer overflow", 0);
		return;
	}

	CREATE_NEW_MONEY_OBJ(return_value, lresult, zend_read_property(money_ce, getThis(), MONEY_PROP_CURRENCY_WS, 0));
}
Exemplo n.º 2
0
PHPAPI zend_string *_php_math_number_format_ex(double d, int dec, char *dec_point,
		size_t dec_point_len, char *thousand_sep, size_t thousand_sep_len)
{
	zend_string *res;
	zend_string *tmpbuf;
	char *s, *t;  /* source, target */
	char *dp;
	int integral;
	int reslen = 0;
	int count = 0;
	int is_negative=0;

	if (d < 0) {
		is_negative = 1;
		d = -d;
	}

	dec = MAX(0, dec);
	d = _php_math_round(d, dec, PHP_ROUND_HALF_UP);
	tmpbuf = strpprintf(0, "%.*F", dec, d);
	if (tmpbuf == NULL) {
		return NULL;
	} else if (!isdigit((int)ZSTR_VAL(tmpbuf)[0])) {
		return tmpbuf;
	}

	/* find decimal point, if expected */
	if (dec) {
		dp = strpbrk(ZSTR_VAL(tmpbuf), ".,");
	} else {
		dp = NULL;
	}

	/* calculate the length of the return buffer */
	if (dp) {
		integral = (int)(dp - ZSTR_VAL(tmpbuf));
	} else {
		/* no decimal point was found */
		integral = (int)ZSTR_LEN(tmpbuf);
	}

	/* allow for thousand separators */
	if (thousand_sep) {
		integral += (int)(thousand_sep_len * ((integral-1) / 3));
	}

	reslen = integral;

	if (dec) {
		reslen += dec;

		if (dec_point) {
			reslen += (int)dec_point_len;
		}
	}

	/* add a byte for minus sign */
	if (is_negative) {
		reslen++;
	}
	res = zend_string_alloc(reslen, 0);

	s = ZSTR_VAL(tmpbuf) + ZSTR_LEN(tmpbuf) - 1;
	t = ZSTR_VAL(res) + reslen;
	*t-- = '\0';

	/* copy the decimal places.
	 * Take care, as the sprintf implementation may return less places than
	 * we requested due to internal buffer limitations */
	if (dec) {
		int declen = (int)(dp ? s - dp : 0);
		int topad = dec > declen ? dec - declen : 0;

		/* pad with '0's */
		while (topad--) {
			*t-- = '0';
		}

		if (dp) {
			s -= declen + 1; /* +1 to skip the point */
			t -= declen;

			/* now copy the chars after the point */
			memcpy(t + 1, dp + 1, declen);
		}

		/* add decimal point */
		if (dec_point) {
			t -= dec_point_len;
			memcpy(t + 1, dec_point, dec_point_len);
		}
	}

	/* copy the numbers before the decimal point, adding thousand
	 * separator every three digits */
	while (s >= ZSTR_VAL(tmpbuf)) {
		*t-- = *s--;
		if (thousand_sep && (++count%3)==0 && s >= ZSTR_VAL(tmpbuf)) {
			t -= thousand_sep_len;
			memcpy(t + 1, thousand_sep, thousand_sep_len);
		}
	}

	/* and a minus sign, if needed */
	if (is_negative) {
		*t-- = '-';
	}

	ZSTR_LEN(res) = reslen;
	zend_string_release(tmpbuf);
	return res;
}
Exemplo n.º 3
0
/* {{{ _php_math_number_format
*/
PHPAPI char *_php_math_number_format(double d, int dec, char dec_point, char thousand_sep)
{
    char *tmpbuf = NULL, *resbuf;
    char *s, *t;  /* source, target */
    char *dp;
    int integral;
    int tmplen, reslen=0;
    int count=0;
    int is_negative=0;

    if (d < 0) {
        is_negative = 1;
        d = -d;
    }

    dec = MAX(0, dec);
    d = _php_math_round(d, dec, PHP_ROUND_HALF_UP);

    tmplen = spprintf(&tmpbuf, 0, "%.*F", dec, d);

    if (tmpbuf == NULL || !isdigit((int)tmpbuf[0])) {
        return tmpbuf;
    }

    /* find decimal point, if expected */
    if (dec) {
        dp = strpbrk(tmpbuf, ".,");
    } else {
        dp = NULL;
    }

    /* calculate the length of the return buffer */
    if (dp) {
        integral = dp - tmpbuf;
    } else {
        /* no decimal point was found */
        integral = tmplen;
    }

    /* allow for thousand separators */
    if (thousand_sep) {
        integral += (integral-1) / 3;
    }

    reslen = integral;

    if (dec) {
        reslen += dec;

        if (dec_point) {
            reslen++;
        }
    }

    /* add a byte for minus sign */
    if (is_negative) {
        reslen++;
    }
    resbuf = (char *) emalloc(reslen+1); /* +1 for NUL terminator */

    s = tmpbuf+tmplen-1;
    t = resbuf+reslen;
    *t-- = '\0';

    /* copy the decimal places.
     * Take care, as the sprintf implementation may return less places than
     * we requested due to internal buffer limitations */
    if (dec) {
        int declen = dp ? s - dp : 0;
        int topad = dec > declen ? dec - declen : 0;

        /* pad with '0's */
        while (topad--) {
            *t-- = '0';
        }

        if (dp) {
            s -= declen + 1; /* +1 to skip the point */
            t -= declen;

            /* now copy the chars after the point */
            memcpy(t + 1, dp + 1, declen);
        }

        /* add decimal point */
        if (dec_point) {
            *t-- = dec_point;
        }
    }

    /* copy the numbers before the decimal point, adding thousand
     * separator every three digits */
    while(s >= tmpbuf) {
        *t-- = *s--;
        if (thousand_sep && (++count%3)==0 && s>=tmpbuf) {
            *t-- = thousand_sep;
        }
    }

    /* and a minus sign, if needed */
    if (is_negative) {
        *t-- = '-';
    }

    efree(tmpbuf);

    return resbuf;
}