1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2014 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 NO_VERSION_YET,
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 ZEND_GET_MODULE(bcmath)
131 #endif
132
133 /* {{{ PHP_INI */
PHP_INI_BEGIN()134 PHP_INI_BEGIN()
135 STD_PHP_INI_ENTRY("bcmath.scale", "0", PHP_INI_ALL, OnUpdateLongGEZero, bc_precision, zend_bcmath_globals, bcmath_globals)
136 PHP_INI_END()
137 /* }}} */
138
139 /* {{{ PHP_GINIT_FUNCTION
140 */
141 static PHP_GINIT_FUNCTION(bcmath)
142 {
143 bcmath_globals->bc_precision = 0;
144 bc_init_numbers(TSRMLS_C);
145 }
146 /* }}} */
147
148 /* {{{ PHP_GSHUTDOWN_FUNCTION
149 */
PHP_GSHUTDOWN_FUNCTION(bcmath)150 static PHP_GSHUTDOWN_FUNCTION(bcmath)
151 {
152 _bc_free_num_ex(&bcmath_globals->_zero_, 1);
153 _bc_free_num_ex(&bcmath_globals->_one_, 1);
154 _bc_free_num_ex(&bcmath_globals->_two_, 1);
155 }
156 /* }}} */
157
158 /* {{{ PHP_MINIT_FUNCTION
159 */
PHP_MINIT_FUNCTION(bcmath)160 PHP_MINIT_FUNCTION(bcmath)
161 {
162 REGISTER_INI_ENTRIES();
163
164 return SUCCESS;
165 }
166 /* }}} */
167
168 /* {{{ PHP_MSHUTDOWN_FUNCTION
169 */
PHP_MSHUTDOWN_FUNCTION(bcmath)170 PHP_MSHUTDOWN_FUNCTION(bcmath)
171 {
172 UNREGISTER_INI_ENTRIES();
173
174 return SUCCESS;
175 }
176 /* }}} */
177
178 /* {{{ PHP_MINFO_FUNCTION
179 */
PHP_MINFO_FUNCTION(bcmath)180 PHP_MINFO_FUNCTION(bcmath)
181 {
182 php_info_print_table_start();
183 php_info_print_table_row(2, "BCMath support", "enabled");
184 php_info_print_table_end();
185 DISPLAY_INI_ENTRIES();
186 }
187 /* }}} */
188
189 /* {{{ php_str2num
190 Convert to bc_num detecting scale */
php_str2num(bc_num * num,char * str TSRMLS_DC)191 static void php_str2num(bc_num *num, char *str TSRMLS_DC)
192 {
193 char *p;
194
195 if (!(p = strchr(str, '.'))) {
196 bc_str2num(num, str, 0 TSRMLS_CC);
197 return;
198 }
199
200 bc_str2num(num, str, strlen(p+1) TSRMLS_CC);
201 }
202 /* }}} */
203
204 /* {{{ proto string bcadd(string left_operand, string right_operand [, int scale])
205 Returns the sum of two arbitrary precision numbers */
PHP_FUNCTION(bcadd)206 PHP_FUNCTION(bcadd)
207 {
208 char *left, *right;
209 long scale_param = 0;
210 bc_num first, second, result;
211 int left_len, right_len;
212 int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
213
214 if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
215 return;
216 }
217
218 if (argc == 3) {
219 scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
220 }
221
222 bc_init_num(&first TSRMLS_CC);
223 bc_init_num(&second TSRMLS_CC);
224 bc_init_num(&result TSRMLS_CC);
225 php_str2num(&first, left TSRMLS_CC);
226 php_str2num(&second, right TSRMLS_CC);
227 bc_add (first, second, &result, scale);
228
229 if (result->n_scale > scale) {
230 result->n_scale = scale;
231 }
232
233 Z_STRVAL_P(return_value) = bc_num2str(result);
234 Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
235 Z_TYPE_P(return_value) = IS_STRING;
236 bc_free_num(&first);
237 bc_free_num(&second);
238 bc_free_num(&result);
239 return;
240 }
241 /* }}} */
242
243 /* {{{ proto string bcsub(string left_operand, string right_operand [, int scale])
244 Returns the difference between two arbitrary precision numbers */
PHP_FUNCTION(bcsub)245 PHP_FUNCTION(bcsub)
246 {
247 char *left, *right;
248 int left_len, right_len;
249 long scale_param = 0;
250 bc_num first, second, result;
251 int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
252
253 if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
254 return;
255 }
256
257 if (argc == 3) {
258 scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
259 }
260
261 bc_init_num(&first TSRMLS_CC);
262 bc_init_num(&second TSRMLS_CC);
263 bc_init_num(&result TSRMLS_CC);
264 php_str2num(&first, left TSRMLS_CC);
265 php_str2num(&second, right TSRMLS_CC);
266 bc_sub (first, second, &result, scale);
267
268 if (result->n_scale > scale) {
269 result->n_scale = scale;
270 }
271
272 Z_STRVAL_P(return_value) = bc_num2str(result);
273 Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
274 Z_TYPE_P(return_value) = IS_STRING;
275 bc_free_num(&first);
276 bc_free_num(&second);
277 bc_free_num(&result);
278 return;
279 }
280 /* }}} */
281
282 /* {{{ proto string bcmul(string left_operand, string right_operand [, int scale])
283 Returns the multiplication of two arbitrary precision numbers */
PHP_FUNCTION(bcmul)284 PHP_FUNCTION(bcmul)
285 {
286 char *left, *right;
287 int left_len, right_len;
288 long scale_param = 0;
289 bc_num first, second, result;
290 int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
291
292 if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
293 return;
294 }
295
296 if (argc == 3) {
297 scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
298 }
299
300 bc_init_num(&first TSRMLS_CC);
301 bc_init_num(&second TSRMLS_CC);
302 bc_init_num(&result TSRMLS_CC);
303 php_str2num(&first, left TSRMLS_CC);
304 php_str2num(&second, right TSRMLS_CC);
305 bc_multiply (first, second, &result, scale TSRMLS_CC);
306
307 if (result->n_scale > scale) {
308 result->n_scale = scale;
309 }
310
311 Z_STRVAL_P(return_value) = bc_num2str(result);
312 Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
313 Z_TYPE_P(return_value) = IS_STRING;
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) */
PHP_FUNCTION(bcdiv)323 PHP_FUNCTION(bcdiv)
324 {
325 char *left, *right;
326 int left_len, right_len;
327 long scale_param = 0;
328 bc_num first, second, result;
329 int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
330
331 if (zend_parse_parameters(argc TSRMLS_CC, "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 TSRMLS_CC);
340 bc_init_num(&second TSRMLS_CC);
341 bc_init_num(&result TSRMLS_CC);
342 php_str2num(&first, left TSRMLS_CC);
343 php_str2num(&second, right TSRMLS_CC);
344
345 switch (bc_divide(first, second, &result, scale TSRMLS_CC)) {
346 case 0: /* OK */
347 if (result->n_scale > scale) {
348 result->n_scale = scale;
349 }
350 Z_STRVAL_P(return_value) = bc_num2str(result);
351 Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
352 Z_TYPE_P(return_value) = IS_STRING;
353 break;
354 case -1: /* division by zero */
355 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Division by zero");
356 break;
357 }
358
359 bc_free_num(&first);
360 bc_free_num(&second);
361 bc_free_num(&result);
362 return;
363 }
364 /* }}} */
365
366 /* {{{ proto string bcmod(string left_operand, string right_operand)
367 Returns the modulus of the two arbitrary precision operands */
PHP_FUNCTION(bcmod)368 PHP_FUNCTION(bcmod)
369 {
370 char *left, *right;
371 int left_len, right_len;
372 bc_num first, second, result;
373
374 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &left, &left_len, &right, &right_len) == FAILURE) {
375 return;
376 }
377
378 bc_init_num(&first TSRMLS_CC);
379 bc_init_num(&second TSRMLS_CC);
380 bc_init_num(&result TSRMLS_CC);
381 bc_str2num(&first, left, 0 TSRMLS_CC);
382 bc_str2num(&second, right, 0 TSRMLS_CC);
383
384 switch (bc_modulo(first, second, &result, 0 TSRMLS_CC)) {
385 case 0:
386 Z_STRVAL_P(return_value) = bc_num2str(result);
387 Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
388 Z_TYPE_P(return_value) = IS_STRING;
389 break;
390 case -1:
391 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Division by zero");
392 break;
393 }
394
395 bc_free_num(&first);
396 bc_free_num(&second);
397 bc_free_num(&result);
398 return;
399 }
400 /* }}} */
401
402 /* {{{ proto string bcpowmod(string x, string y, string mod [, int scale])
403 Returns the value of an arbitrary precision number raised to the power of another reduced by a modulous */
PHP_FUNCTION(bcpowmod)404 PHP_FUNCTION(bcpowmod)
405 {
406 char *left, *right, *modulous;
407 int left_len, right_len, modulous_len;
408 bc_num first, second, mod, result;
409 long scale = BCG(bc_precision);
410 int scale_int;
411
412 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|l", &left, &left_len, &right, &right_len, &modulous, &modulous_len, &scale) == FAILURE) {
413 return;
414 }
415
416 bc_init_num(&first TSRMLS_CC);
417 bc_init_num(&second TSRMLS_CC);
418 bc_init_num(&mod TSRMLS_CC);
419 bc_init_num(&result TSRMLS_CC);
420 php_str2num(&first, left TSRMLS_CC);
421 php_str2num(&second, right TSRMLS_CC);
422 php_str2num(&mod, modulous TSRMLS_CC);
423
424 scale_int = (int) ((int)scale < 0) ? 0 : scale;
425
426 if (bc_raisemod(first, second, mod, &result, scale_int TSRMLS_CC) != -1) {
427 if (result->n_scale > scale) {
428 result->n_scale = scale;
429 }
430 Z_STRVAL_P(return_value) = bc_num2str(result);
431 Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
432 Z_TYPE_P(return_value) = IS_STRING;
433 } else {
434 RETVAL_FALSE;
435 }
436
437 bc_free_num(&first);
438 bc_free_num(&second);
439 bc_free_num(&mod);
440 bc_free_num(&result);
441 return;
442 }
443 /* }}} */
444
445 /* {{{ proto string bcpow(string x, string y [, int scale])
446 Returns the value of an arbitrary precision number raised to the power of another */
PHP_FUNCTION(bcpow)447 PHP_FUNCTION(bcpow)
448 {
449 char *left, *right;
450 int left_len, right_len;
451 long scale_param = 0;
452 bc_num first, second, result;
453 int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
454
455 if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
456 return;
457 }
458
459 if (argc == 3) {
460 scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
461 }
462
463 bc_init_num(&first TSRMLS_CC);
464 bc_init_num(&second TSRMLS_CC);
465 bc_init_num(&result TSRMLS_CC);
466 php_str2num(&first, left TSRMLS_CC);
467 php_str2num(&second, right TSRMLS_CC);
468 bc_raise (first, second, &result, scale TSRMLS_CC);
469
470 if (result->n_scale > scale) {
471 result->n_scale = scale;
472 }
473
474 Z_STRVAL_P(return_value) = bc_num2str(result);
475 Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
476 Z_TYPE_P(return_value) = IS_STRING;
477 bc_free_num(&first);
478 bc_free_num(&second);
479 bc_free_num(&result);
480 return;
481 }
482 /* }}} */
483
484 /* {{{ proto string bcsqrt(string operand [, int scale])
485 Returns the square root of an arbitray precision number */
PHP_FUNCTION(bcsqrt)486 PHP_FUNCTION(bcsqrt)
487 {
488 char *left;
489 int left_len;
490 long scale_param = 0;
491 bc_num result;
492 int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
493
494 if (zend_parse_parameters(argc TSRMLS_CC, "s|l", &left, &left_len, &scale_param) == FAILURE) {
495 return;
496 }
497
498 if (argc == 2) {
499 scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
500 }
501
502 bc_init_num(&result TSRMLS_CC);
503 php_str2num(&result, left TSRMLS_CC);
504
505 if (bc_sqrt (&result, scale TSRMLS_CC) != 0) {
506 if (result->n_scale > scale) {
507 result->n_scale = scale;
508 }
509 Z_STRVAL_P(return_value) = bc_num2str(result);
510 Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
511 Z_TYPE_P(return_value) = IS_STRING;
512 } else {
513 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Square root of negative number");
514 }
515
516 bc_free_num(&result);
517 return;
518 }
519 /* }}} */
520
521 /* {{{ proto int bccomp(string left_operand, string right_operand [, int scale])
522 Compares two arbitrary precision numbers */
PHP_FUNCTION(bccomp)523 PHP_FUNCTION(bccomp)
524 {
525 char *left, *right;
526 int left_len, right_len;
527 long scale_param = 0;
528 bc_num first, second;
529 int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
530
531 if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
532 return;
533 }
534
535 if (argc == 3) {
536 scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
537 }
538
539 bc_init_num(&first TSRMLS_CC);
540 bc_init_num(&second TSRMLS_CC);
541
542 bc_str2num(&first, left, scale TSRMLS_CC);
543 bc_str2num(&second, right, scale TSRMLS_CC);
544 Z_LVAL_P(return_value) = bc_compare(first, second);
545 Z_TYPE_P(return_value) = IS_LONG;
546
547 bc_free_num(&first);
548 bc_free_num(&second);
549 return;
550 }
551 /* }}} */
552
553 /* {{{ proto bool bcscale(int scale)
554 Sets default scale parameter for all bc math functions */
PHP_FUNCTION(bcscale)555 PHP_FUNCTION(bcscale)
556 {
557 long new_scale;
558
559 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &new_scale) == FAILURE) {
560 return;
561 }
562
563 BCG(bc_precision) = ((int)new_scale < 0) ? 0 : new_scale;
564
565 RETURN_TRUE;
566 }
567 /* }}} */
568
569
570 #endif
571
572 /*
573 * Local variables:
574 * tab-width: 4
575 * c-basic-offset: 4
576 * End:
577 * vim600: sw=4 ts=4 fdm=marker
578 * vim<600: sw=4 ts=4
579 */
580