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