root/ext/bcmath/bcmath.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ZEND_TSRMLS_CACHE_DEFINE
  2. PHP_GSHUTDOWN_FUNCTION
  3. PHP_MINIT_FUNCTION
  4. PHP_MSHUTDOWN_FUNCTION
  5. PHP_MINFO_FUNCTION
  6. php_str2num
  7. PHP_FUNCTION
  8. PHP_FUNCTION
  9. PHP_FUNCTION
  10. PHP_FUNCTION
  11. PHP_FUNCTION
  12. PHP_FUNCTION
  13. PHP_FUNCTION
  14. PHP_FUNCTION
  15. PHP_FUNCTION
  16. PHP_FUNCTION

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Author: Andi Gutmans <andi@zend.com>                                 |
  16    +----------------------------------------------------------------------+
  17 */
  18 
  19 /* $Id$ */
  20 
  21 #ifdef HAVE_CONFIG_H
  22 #include "config.h"
  23 #endif
  24 
  25 #include "php.h"
  26 
  27 #if HAVE_BCMATH
  28 
  29 #include "php_ini.h"
  30 #include "ext/standard/info.h"
  31 #include "php_bcmath.h"
  32 #include "libbcmath/src/bcmath.h"
  33 
  34 ZEND_DECLARE_MODULE_GLOBALS(bcmath)
  35 static PHP_GINIT_FUNCTION(bcmath);
  36 static PHP_GSHUTDOWN_FUNCTION(bcmath);
  37 
  38 /* {{{ arginfo */
  39 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcadd, 0, 0, 2)
  40         ZEND_ARG_INFO(0, left_operand)
  41         ZEND_ARG_INFO(0, right_operand)
  42         ZEND_ARG_INFO(0, scale)
  43 ZEND_END_ARG_INFO()
  44 
  45 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcsub, 0, 0, 2)
  46         ZEND_ARG_INFO(0, left_operand)
  47         ZEND_ARG_INFO(0, right_operand)
  48         ZEND_ARG_INFO(0, scale)
  49 ZEND_END_ARG_INFO()
  50 
  51 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcmul, 0, 0, 2)
  52         ZEND_ARG_INFO(0, left_operand)
  53         ZEND_ARG_INFO(0, right_operand)
  54         ZEND_ARG_INFO(0, scale)
  55 ZEND_END_ARG_INFO()
  56 
  57 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcdiv, 0, 0, 2)
  58         ZEND_ARG_INFO(0, left_operand)
  59         ZEND_ARG_INFO(0, right_operand)
  60         ZEND_ARG_INFO(0, scale)
  61 ZEND_END_ARG_INFO()
  62 
  63 ZEND_BEGIN_ARG_INFO(arginfo_bcmod, 0)
  64         ZEND_ARG_INFO(0, left_operand)
  65         ZEND_ARG_INFO(0, right_operand)
  66 ZEND_END_ARG_INFO()
  67 
  68 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcpowmod, 0, 0, 3)
  69         ZEND_ARG_INFO(0, x)
  70         ZEND_ARG_INFO(0, y)
  71         ZEND_ARG_INFO(0, mod)
  72         ZEND_ARG_INFO(0, scale)
  73 ZEND_END_ARG_INFO()
  74 
  75 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcpow, 0, 0, 2)
  76         ZEND_ARG_INFO(0, x)
  77         ZEND_ARG_INFO(0, y)
  78         ZEND_ARG_INFO(0, scale)
  79 ZEND_END_ARG_INFO()
  80 
  81 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcsqrt, 0, 0, 1)
  82         ZEND_ARG_INFO(0, operand)
  83         ZEND_ARG_INFO(0, scale)
  84 ZEND_END_ARG_INFO()
  85 
  86 ZEND_BEGIN_ARG_INFO_EX(arginfo_bccomp, 0, 0, 2)
  87         ZEND_ARG_INFO(0, left_operand)
  88         ZEND_ARG_INFO(0, right_operand)
  89         ZEND_ARG_INFO(0, scale)
  90 ZEND_END_ARG_INFO()
  91 
  92 ZEND_BEGIN_ARG_INFO(arginfo_bcscale, 0)
  93         ZEND_ARG_INFO(0, scale)
  94 ZEND_END_ARG_INFO()
  95 
  96 /* }}} */
  97 
  98 const zend_function_entry bcmath_functions[] = {
  99         PHP_FE(bcadd,                                                                   arginfo_bcadd)
 100         PHP_FE(bcsub,                                                                   arginfo_bcsub)
 101         PHP_FE(bcmul,                                                                   arginfo_bcmul)
 102         PHP_FE(bcdiv,                                                                   arginfo_bcdiv)
 103         PHP_FE(bcmod,                                                                   arginfo_bcmod)
 104         PHP_FE(bcpow,                                                                   arginfo_bcpow)
 105         PHP_FE(bcsqrt,                                                                  arginfo_bcsqrt)
 106         PHP_FE(bcscale,                                                                 arginfo_bcscale)
 107         PHP_FE(bccomp,                                                                  arginfo_bccomp)
 108         PHP_FE(bcpowmod,                                                                arginfo_bcpowmod)
 109         PHP_FE_END
 110 };
 111 
 112 zend_module_entry bcmath_module_entry = {
 113         STANDARD_MODULE_HEADER,
 114         "bcmath",
 115         bcmath_functions,
 116         PHP_MINIT(bcmath),
 117         PHP_MSHUTDOWN(bcmath),
 118         NULL,
 119         NULL,
 120         PHP_MINFO(bcmath),
 121         PHP_BCMATH_VERSION,
 122         PHP_MODULE_GLOBALS(bcmath),
 123         PHP_GINIT(bcmath),
 124     PHP_GSHUTDOWN(bcmath),
 125         NULL,
 126         STANDARD_MODULE_PROPERTIES_EX
 127 };
 128 
 129 #ifdef COMPILE_DL_BCMATH
 130 #ifdef ZTS
 131 ZEND_TSRMLS_CACHE_DEFINE()
 132 #endif
 133 ZEND_GET_MODULE(bcmath)
 134 #endif
 135 
 136 /* {{{ PHP_INI */
 137 PHP_INI_BEGIN()
 138         STD_PHP_INI_ENTRY("bcmath.scale", "0", PHP_INI_ALL, OnUpdateLongGEZero, bc_precision, zend_bcmath_globals, bcmath_globals)
 139 PHP_INI_END()
 140 /* }}} */
 141 
 142 /* {{{ PHP_GINIT_FUNCTION
 143  */
 144 static PHP_GINIT_FUNCTION(bcmath)
 145 {
 146 #if defined(COMPILE_DL_BCMATH) && defined(ZTS)
 147         ZEND_TSRMLS_CACHE_UPDATE();
 148 #endif
 149         bcmath_globals->bc_precision = 0;
 150         bc_init_numbers();
 151 }
 152 /* }}} */
 153 
 154 /* {{{ PHP_GSHUTDOWN_FUNCTION
 155  */
 156 static PHP_GSHUTDOWN_FUNCTION(bcmath)
 157 {
 158         _bc_free_num_ex(&bcmath_globals->_zero_, 1);
 159         _bc_free_num_ex(&bcmath_globals->_one_, 1);
 160         _bc_free_num_ex(&bcmath_globals->_two_, 1);
 161 }
 162 /* }}} */
 163 
 164 /* {{{ PHP_MINIT_FUNCTION
 165  */
 166 PHP_MINIT_FUNCTION(bcmath)
 167 {
 168         REGISTER_INI_ENTRIES();
 169 
 170         return SUCCESS;
 171 }
 172 /* }}} */
 173 
 174 /* {{{ PHP_MSHUTDOWN_FUNCTION
 175  */
 176 PHP_MSHUTDOWN_FUNCTION(bcmath)
 177 {
 178         UNREGISTER_INI_ENTRIES();
 179 
 180         return SUCCESS;
 181 }
 182 /* }}} */
 183 
 184 /* {{{ PHP_MINFO_FUNCTION
 185  */
 186 PHP_MINFO_FUNCTION(bcmath)
 187 {
 188         php_info_print_table_start();
 189         php_info_print_table_row(2, "BCMath support", "enabled");
 190         php_info_print_table_end();
 191         DISPLAY_INI_ENTRIES();
 192 }
 193 /* }}} */
 194 
 195 /* {{{ php_str2num
 196    Convert to bc_num detecting scale */
 197 static void php_str2num(bc_num *num, char *str)
 198 {
 199         char *p;
 200 
 201         if (!(p = strchr(str, '.'))) {
 202                 bc_str2num(num, str, 0);
 203                 return;
 204         }
 205 
 206         bc_str2num(num, str, strlen(p+1));
 207 }
 208 /* }}} */
 209 
 210 /* {{{ proto string bcadd(string left_operand, string right_operand [, int scale])
 211    Returns the sum of two arbitrary precision numbers */
 212 PHP_FUNCTION(bcadd)
 213 {
 214         char *left, *right;
 215         zend_long scale_param = 0;
 216         bc_num first, second, result;
 217         size_t left_len, right_len;
 218         int scale = (int)BCG(bc_precision), argc = ZEND_NUM_ARGS();
 219 
 220         if (zend_parse_parameters(argc, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
 221                 return;
 222         }
 223 
 224         if (argc == 3) {
 225                 scale = (int) (scale_param < 0 ? 0 : scale_param);
 226         }
 227 
 228         bc_init_num(&first);
 229         bc_init_num(&second);
 230         bc_init_num(&result);
 231         php_str2num(&first, left);
 232         php_str2num(&second, right);
 233         bc_add (first, second, &result, scale);
 234 
 235         if (result->n_scale > scale) {
 236                 result->n_scale = scale;
 237         }
 238 
 239         RETVAL_STR(bc_num2str(result));
 240         bc_free_num(&first);
 241         bc_free_num(&second);
 242         bc_free_num(&result);
 243         return;
 244 }
 245 /* }}} */
 246 
 247 /* {{{ proto string bcsub(string left_operand, string right_operand [, int scale])
 248    Returns the difference between two arbitrary precision numbers */
 249 PHP_FUNCTION(bcsub)
 250 {
 251         char *left, *right;
 252         size_t left_len, right_len;
 253         zend_long scale_param = 0;
 254         bc_num first, second, result;
 255         int scale = (int)BCG(bc_precision), argc = ZEND_NUM_ARGS();
 256 
 257         if (zend_parse_parameters(argc, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
 258                 return;
 259         }
 260 
 261         if (argc == 3) {
 262                 scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
 263         }
 264 
 265         bc_init_num(&first);
 266         bc_init_num(&second);
 267         bc_init_num(&result);
 268         php_str2num(&first, left);
 269         php_str2num(&second, right);
 270         bc_sub (first, second, &result, scale);
 271 
 272         if (result->n_scale > scale) {
 273                 result->n_scale = scale;
 274         }
 275 
 276         RETVAL_STR(bc_num2str(result));
 277         bc_free_num(&first);
 278         bc_free_num(&second);
 279         bc_free_num(&result);
 280         return;
 281 }
 282 /* }}} */
 283 
 284 /* {{{ proto string bcmul(string left_operand, string right_operand [, int scale])
 285    Returns the multiplication of two arbitrary precision numbers */
 286 PHP_FUNCTION(bcmul)
 287 {
 288         char *left, *right;
 289         size_t left_len, right_len;
 290         zend_long scale_param = 0;
 291         bc_num first, second, result;
 292         int scale = (int)BCG(bc_precision), argc = ZEND_NUM_ARGS();
 293 
 294         if (zend_parse_parameters(argc, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
 295                 return;
 296         }
 297 
 298         if (argc == 3) {
 299                 scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
 300         }
 301 
 302         bc_init_num(&first);
 303         bc_init_num(&second);
 304         bc_init_num(&result);
 305         php_str2num(&first, left);
 306         php_str2num(&second, right);
 307         bc_multiply (first, second, &result, scale);
 308 
 309         if (result->n_scale > scale) {
 310                 result->n_scale = scale;
 311         }
 312 
 313         RETVAL_STR(bc_num2str(result));
 314         bc_free_num(&first);
 315         bc_free_num(&second);
 316         bc_free_num(&result);
 317         return;
 318 }
 319 /* }}} */
 320 
 321 /* {{{ proto string bcdiv(string left_operand, string right_operand [, int scale])
 322    Returns the quotient of two arbitrary precision numbers (division) */
 323 PHP_FUNCTION(bcdiv)
 324 {
 325         char *left, *right;
 326         size_t left_len, right_len;
 327         zend_long scale_param = 0;
 328         bc_num first, second, result;
 329         int scale = (int)BCG(bc_precision), argc = ZEND_NUM_ARGS();
 330 
 331         if (zend_parse_parameters(argc, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
 332                 return;
 333         }
 334 
 335         if (argc == 3) {
 336                 scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
 337         }
 338 
 339         bc_init_num(&first);
 340         bc_init_num(&second);
 341         bc_init_num(&result);
 342         php_str2num(&first, left);
 343         php_str2num(&second, right);
 344 
 345         switch (bc_divide(first, second, &result, scale)) {
 346                 case 0: /* OK */
 347                         if (result->n_scale > scale) {
 348                                 result->n_scale = scale;
 349                         }
 350                         RETVAL_STR(bc_num2str(result));
 351                         break;
 352                 case -1: /* division by zero */
 353                         php_error_docref(NULL, E_WARNING, "Division by zero");
 354                         break;
 355         }
 356 
 357         bc_free_num(&first);
 358         bc_free_num(&second);
 359         bc_free_num(&result);
 360         return;
 361 }
 362 /* }}} */
 363 
 364 /* {{{ proto string bcmod(string left_operand, string right_operand)
 365    Returns the modulus of the two arbitrary precision operands */
 366 PHP_FUNCTION(bcmod)
 367 {
 368         char *left, *right;
 369         size_t left_len, right_len;
 370         bc_num first, second, result;
 371 
 372         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &left, &left_len, &right, &right_len) == FAILURE) {
 373                 return;
 374         }
 375 
 376         bc_init_num(&first);
 377         bc_init_num(&second);
 378         bc_init_num(&result);
 379         bc_str2num(&first, left, 0);
 380         bc_str2num(&second, right, 0);
 381 
 382         switch (bc_modulo(first, second, &result, 0)) {
 383                 case 0:
 384                         RETVAL_STR(bc_num2str(result));
 385                         break;
 386                 case -1:
 387                         php_error_docref(NULL, E_WARNING, "Division by zero");
 388                         break;
 389         }
 390 
 391         bc_free_num(&first);
 392         bc_free_num(&second);
 393         bc_free_num(&result);
 394         return;
 395 }
 396 /* }}} */
 397 
 398 /* {{{ proto string bcpowmod(string x, string y, string mod [, int scale])
 399    Returns the value of an arbitrary precision number raised to the power of another reduced by a modulous */
 400 PHP_FUNCTION(bcpowmod)
 401 {
 402         char *left, *right, *modulous;
 403         size_t left_len, right_len, modulous_len;
 404         bc_num first, second, mod, result;
 405         zend_long scale = BCG(bc_precision);
 406         int scale_int;
 407 
 408         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|l", &left, &left_len, &right, &right_len, &modulous, &modulous_len, &scale) == FAILURE) {
 409                 return;
 410         }
 411 
 412         bc_init_num(&first);
 413         bc_init_num(&second);
 414         bc_init_num(&mod);
 415         bc_init_num(&result);
 416         php_str2num(&first, left);
 417         php_str2num(&second, right);
 418         php_str2num(&mod, modulous);
 419 
 420         scale_int = (int) ((int)scale < 0 ? 0 : scale);
 421 
 422         if (bc_raisemod(first, second, mod, &result, scale_int) != -1) {
 423                 if (result->n_scale > scale) {
 424                         result->n_scale = (int)scale;
 425                 }
 426                 RETVAL_STR(bc_num2str(result));
 427         } else {
 428                 RETVAL_FALSE;
 429         }
 430 
 431         bc_free_num(&first);
 432         bc_free_num(&second);
 433         bc_free_num(&mod);
 434         bc_free_num(&result);
 435         return;
 436 }
 437 /* }}} */
 438 
 439 /* {{{ proto string bcpow(string x, string y [, int scale])
 440    Returns the value of an arbitrary precision number raised to the power of another */
 441 PHP_FUNCTION(bcpow)
 442 {
 443         char *left, *right;
 444         size_t left_len, right_len;
 445         zend_long scale_param = 0;
 446         bc_num first, second, result;
 447         int scale = (int)BCG(bc_precision), argc = ZEND_NUM_ARGS();
 448 
 449         if (zend_parse_parameters(argc, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
 450                 return;
 451         }
 452 
 453         if (argc == 3) {
 454                 scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
 455         }
 456 
 457         bc_init_num(&first);
 458         bc_init_num(&second);
 459         bc_init_num(&result);
 460         php_str2num(&first, left);
 461         php_str2num(&second, right);
 462         bc_raise (first, second, &result, scale);
 463 
 464         if (result->n_scale > scale) {
 465                 result->n_scale = scale;
 466         }
 467 
 468         RETVAL_STR(bc_num2str(result));
 469         bc_free_num(&first);
 470         bc_free_num(&second);
 471         bc_free_num(&result);
 472         return;
 473 }
 474 /* }}} */
 475 
 476 /* {{{ proto string bcsqrt(string operand [, int scale])
 477    Returns the square root of an arbitray precision number */
 478 PHP_FUNCTION(bcsqrt)
 479 {
 480         char *left;
 481         size_t left_len;
 482         zend_long scale_param = 0;
 483         bc_num result;
 484         int scale = (int)BCG(bc_precision), argc = ZEND_NUM_ARGS();
 485 
 486         if (zend_parse_parameters(argc, "s|l", &left, &left_len, &scale_param) == FAILURE) {
 487                 return;
 488         }
 489 
 490         if (argc == 2) {
 491                 scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
 492         }
 493 
 494         bc_init_num(&result);
 495         php_str2num(&result, left);
 496 
 497         if (bc_sqrt (&result, scale) != 0) {
 498                 if (result->n_scale > scale) {
 499                         result->n_scale = scale;
 500                 }
 501                 RETVAL_STR(bc_num2str(result));
 502         } else {
 503                 php_error_docref(NULL, E_WARNING, "Square root of negative number");
 504         }
 505 
 506         bc_free_num(&result);
 507         return;
 508 }
 509 /* }}} */
 510 
 511 /* {{{ proto int bccomp(string left_operand, string right_operand [, int scale])
 512    Compares two arbitrary precision numbers */
 513 PHP_FUNCTION(bccomp)
 514 {
 515         char *left, *right;
 516         size_t left_len, right_len;
 517         zend_long scale_param = 0;
 518         bc_num first, second;
 519         int scale = (int)BCG(bc_precision), argc = ZEND_NUM_ARGS();
 520 
 521         if (zend_parse_parameters(argc, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
 522                 return;
 523         }
 524 
 525         if (argc == 3) {
 526                 scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
 527         }
 528 
 529         bc_init_num(&first);
 530         bc_init_num(&second);
 531 
 532         bc_str2num(&first, left, scale);
 533         bc_str2num(&second, right, scale);
 534         RETVAL_LONG(bc_compare(first, second));
 535 
 536         bc_free_num(&first);
 537         bc_free_num(&second);
 538         return;
 539 }
 540 /* }}} */
 541 
 542 /* {{{ proto bool bcscale(int scale)
 543    Sets default scale parameter for all bc math functions */
 544 PHP_FUNCTION(bcscale)
 545 {
 546         zend_long new_scale;
 547 
 548         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &new_scale) == FAILURE) {
 549                 return;
 550         }
 551 
 552         BCG(bc_precision) = ((int)new_scale < 0) ? 0 : new_scale;
 553 
 554         RETURN_TRUE;
 555 }
 556 /* }}} */
 557 
 558 
 559 #endif
 560 
 561 /*
 562  * Local variables:
 563  * tab-width: 4
 564  * c-basic-offset: 4
 565  * End:
 566  * vim600: sw=4 ts=4 fdm=marker
 567  * vim<600: sw=4 ts=4
 568  */

/* [<][>][^][v][top][bottom][index][help] */