1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2013 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: Stanislav Malyshev <stas@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include "php.h"
24 #include "php_ini.h"
25 #include "php_gmp.h"
26 #include "ext/standard/info.h"
27
28 #if HAVE_GMP
29
30 #include <gmp.h>
31
32 /* Needed for gmp_random() */
33 #include "ext/standard/php_rand.h"
34 #include "ext/standard/php_lcg.h"
35 #define GMP_ABS(x) ((x) >= 0 ? (x) : -(x))
36
37 /* True global resources - no need for thread safety here */
38 static int le_gmp;
39
40 /* {{{ arginfo */
41 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_init, 0, 0, 1)
42 ZEND_ARG_INFO(0, number)
43 ZEND_ARG_INFO(0, base)
44 ZEND_END_ARG_INFO()
45
46 ZEND_BEGIN_ARG_INFO(arginfo_gmp_intval, 0)
47 ZEND_ARG_INFO(0, gmpnumber)
48 ZEND_END_ARG_INFO()
49
50 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_strval, 0, 0, 1)
51 ZEND_ARG_INFO(0, gmpnumber)
52 ZEND_ARG_INFO(0, base)
53 ZEND_END_ARG_INFO()
54
55 ZEND_BEGIN_ARG_INFO(arginfo_gmp_add, 0)
56 ZEND_ARG_INFO(0, a)
57 ZEND_ARG_INFO(0, b)
58 ZEND_END_ARG_INFO()
59
60 ZEND_BEGIN_ARG_INFO(arginfo_gmp_sub, 0)
61 ZEND_ARG_INFO(0, a)
62 ZEND_ARG_INFO(0, b)
63 ZEND_END_ARG_INFO()
64
65 ZEND_BEGIN_ARG_INFO(arginfo_gmp_mul, 0)
66 ZEND_ARG_INFO(0, a)
67 ZEND_ARG_INFO(0, b)
68 ZEND_END_ARG_INFO()
69
70 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_div_qr, 0, 0, 2)
71 ZEND_ARG_INFO(0, a)
72 ZEND_ARG_INFO(0, b)
73 ZEND_ARG_INFO(0, round)
74 ZEND_END_ARG_INFO()
75
76 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_div_r, 0, 0, 2)
77 ZEND_ARG_INFO(0, a)
78 ZEND_ARG_INFO(0, b)
79 ZEND_ARG_INFO(0, round)
80 ZEND_END_ARG_INFO()
81
82 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_div_q, 0, 0, 2)
83 ZEND_ARG_INFO(0, a)
84 ZEND_ARG_INFO(0, b)
85 ZEND_ARG_INFO(0, round)
86 ZEND_END_ARG_INFO()
87
88 ZEND_BEGIN_ARG_INFO(arginfo_gmp_mod, 0)
89 ZEND_ARG_INFO(0, a)
90 ZEND_ARG_INFO(0, b)
91 ZEND_END_ARG_INFO()
92
93 ZEND_BEGIN_ARG_INFO(arginfo_gmp_divexact, 0)
94 ZEND_ARG_INFO(0, a)
95 ZEND_ARG_INFO(0, b)
96 ZEND_END_ARG_INFO()
97
98 ZEND_BEGIN_ARG_INFO(arginfo_gmp_neg, 0)
99 ZEND_ARG_INFO(0, a)
100 ZEND_END_ARG_INFO()
101
102 ZEND_BEGIN_ARG_INFO(arginfo_gmp_abs, 0)
103 ZEND_ARG_INFO(0, a)
104 ZEND_END_ARG_INFO()
105
106 ZEND_BEGIN_ARG_INFO(arginfo_gmp_fact, 0)
107 ZEND_ARG_INFO(0, a)
108 ZEND_END_ARG_INFO()
109
110 ZEND_BEGIN_ARG_INFO(arginfo_gmp_pow, 0)
111 ZEND_ARG_INFO(0, base)
112 ZEND_ARG_INFO(0, exp)
113 ZEND_END_ARG_INFO()
114
115 ZEND_BEGIN_ARG_INFO(arginfo_gmp_powm, 0)
116 ZEND_ARG_INFO(0, base)
117 ZEND_ARG_INFO(0, exp)
118 ZEND_ARG_INFO(0, mod)
119 ZEND_END_ARG_INFO()
120
121 ZEND_BEGIN_ARG_INFO(arginfo_gmp_sqrt, 0)
122 ZEND_ARG_INFO(0, a)
123 ZEND_END_ARG_INFO()
124
125 ZEND_BEGIN_ARG_INFO(arginfo_gmp_sqrtrem, 0)
126 ZEND_ARG_INFO(0, a)
127 ZEND_END_ARG_INFO()
128
129 ZEND_BEGIN_ARG_INFO(arginfo_gmp_perfect_square, 0)
130 ZEND_ARG_INFO(0, a)
131 ZEND_END_ARG_INFO()
132
133 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_prob_prime, 0, 0, 1)
134 ZEND_ARG_INFO(0, a)
135 ZEND_ARG_INFO(0, reps)
136 ZEND_END_ARG_INFO()
137
138 ZEND_BEGIN_ARG_INFO(arginfo_gmp_gcd, 0)
139 ZEND_ARG_INFO(0, a)
140 ZEND_ARG_INFO(0, b)
141 ZEND_END_ARG_INFO()
142
143 ZEND_BEGIN_ARG_INFO(arginfo_gmp_gcdext, 0)
144 ZEND_ARG_INFO(0, a)
145 ZEND_ARG_INFO(0, b)
146 ZEND_END_ARG_INFO()
147
148 ZEND_BEGIN_ARG_INFO(arginfo_gmp_invert, 0)
149 ZEND_ARG_INFO(0, a)
150 ZEND_ARG_INFO(0, b)
151 ZEND_END_ARG_INFO()
152
153 ZEND_BEGIN_ARG_INFO(arginfo_gmp_jacobi, 0)
154 ZEND_ARG_INFO(0, a)
155 ZEND_ARG_INFO(0, b)
156 ZEND_END_ARG_INFO()
157
158 ZEND_BEGIN_ARG_INFO(arginfo_gmp_legendre, 0)
159 ZEND_ARG_INFO(0, a)
160 ZEND_ARG_INFO(0, b)
161 ZEND_END_ARG_INFO()
162
163 ZEND_BEGIN_ARG_INFO(arginfo_gmp_cmp, 0)
164 ZEND_ARG_INFO(0, a)
165 ZEND_ARG_INFO(0, b)
166 ZEND_END_ARG_INFO()
167
168 ZEND_BEGIN_ARG_INFO(arginfo_gmp_sign, 0)
169 ZEND_ARG_INFO(0, a)
170 ZEND_END_ARG_INFO()
171
172 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_random, 0, 0, 0)
173 ZEND_ARG_INFO(0, limiter)
174 ZEND_END_ARG_INFO()
175
176 ZEND_BEGIN_ARG_INFO(arginfo_gmp_and, 0)
177 ZEND_ARG_INFO(0, a)
178 ZEND_ARG_INFO(0, b)
179 ZEND_END_ARG_INFO()
180
181 ZEND_BEGIN_ARG_INFO(arginfo_gmp_or, 0)
182 ZEND_ARG_INFO(0, a)
183 ZEND_ARG_INFO(0, b)
184 ZEND_END_ARG_INFO()
185
186 ZEND_BEGIN_ARG_INFO(arginfo_gmp_com, 0)
187 ZEND_ARG_INFO(0, a)
188 ZEND_END_ARG_INFO()
189
190 ZEND_BEGIN_ARG_INFO(arginfo_gmp_xor, 0)
191 ZEND_ARG_INFO(0, a)
192 ZEND_ARG_INFO(0, b)
193 ZEND_END_ARG_INFO()
194
195 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_setbit, 0, 0, 2)
196 ZEND_ARG_INFO(1, a)
197 ZEND_ARG_INFO(0, index)
198 ZEND_ARG_INFO(0, set_clear)
199 ZEND_END_ARG_INFO()
200
201 ZEND_BEGIN_ARG_INFO(arginfo_gmp_clrbit, 0)
202 ZEND_ARG_INFO(1, a)
203 ZEND_ARG_INFO(0, index)
204 ZEND_END_ARG_INFO()
205
206 ZEND_BEGIN_ARG_INFO(arginfo_gmp_testbit, 0)
207 ZEND_ARG_INFO(0, a)
208 ZEND_ARG_INFO(0, index)
209 ZEND_END_ARG_INFO()
210
211 ZEND_BEGIN_ARG_INFO(arginfo_gmp_popcount, 0)
212 ZEND_ARG_INFO(0, a)
213 ZEND_END_ARG_INFO()
214
215 ZEND_BEGIN_ARG_INFO(arginfo_gmp_hamdist, 0)
216 ZEND_ARG_INFO(0, a)
217 ZEND_ARG_INFO(0, b)
218 ZEND_END_ARG_INFO()
219
220 ZEND_BEGIN_ARG_INFO(arginfo_gmp_scan0, 0)
221 ZEND_ARG_INFO(0, a)
222 ZEND_ARG_INFO(0, start)
223 ZEND_END_ARG_INFO()
224
225 ZEND_BEGIN_ARG_INFO(arginfo_gmp_scan1, 0)
226 ZEND_ARG_INFO(0, a)
227 ZEND_ARG_INFO(0, start)
228 ZEND_END_ARG_INFO()
229
230 ZEND_BEGIN_ARG_INFO(arginfo_gmp_nextprime, 0)
231 ZEND_ARG_INFO(0, a)
232 ZEND_END_ARG_INFO()
233
234 /* }}} */
235
236 ZEND_DECLARE_MODULE_GLOBALS(gmp)
237 static ZEND_GINIT_FUNCTION(gmp);
238
239 /* {{{ gmp_functions[]
240 */
241 const zend_function_entry gmp_functions[] = {
242 ZEND_FE(gmp_init, arginfo_gmp_init)
243 ZEND_FE(gmp_intval, arginfo_gmp_intval)
244 ZEND_FE(gmp_strval, arginfo_gmp_strval)
245 ZEND_FE(gmp_add, arginfo_gmp_add)
246 ZEND_FE(gmp_sub, arginfo_gmp_sub)
247 ZEND_FE(gmp_mul, arginfo_gmp_mul)
248 ZEND_FE(gmp_div_qr, arginfo_gmp_div_qr)
249 ZEND_FE(gmp_div_q, arginfo_gmp_div_q)
250 ZEND_FE(gmp_div_r, arginfo_gmp_div_r)
251 ZEND_FALIAS(gmp_div, gmp_div_q, arginfo_gmp_div_q)
252 ZEND_FE(gmp_mod, arginfo_gmp_mod)
253 ZEND_FE(gmp_divexact, arginfo_gmp_divexact)
254 ZEND_FE(gmp_neg, arginfo_gmp_neg)
255 ZEND_FE(gmp_abs, arginfo_gmp_abs)
256 ZEND_FE(gmp_fact, arginfo_gmp_fact)
257 ZEND_FE(gmp_sqrt, arginfo_gmp_sqrt)
258 ZEND_FE(gmp_sqrtrem, arginfo_gmp_sqrtrem)
259 ZEND_FE(gmp_pow, arginfo_gmp_pow)
260 ZEND_FE(gmp_powm, arginfo_gmp_powm)
261 ZEND_FE(gmp_perfect_square, arginfo_gmp_perfect_square)
262 ZEND_FE(gmp_prob_prime, arginfo_gmp_prob_prime)
263 ZEND_FE(gmp_gcd, arginfo_gmp_gcd)
264 ZEND_FE(gmp_gcdext, arginfo_gmp_gcdext)
265 ZEND_FE(gmp_invert, arginfo_gmp_invert)
266 ZEND_FE(gmp_jacobi, arginfo_gmp_jacobi)
267 ZEND_FE(gmp_legendre, arginfo_gmp_legendre)
268 ZEND_FE(gmp_cmp, arginfo_gmp_cmp)
269 ZEND_FE(gmp_sign, arginfo_gmp_sign)
270 ZEND_FE(gmp_random, arginfo_gmp_random)
271 ZEND_FE(gmp_and, arginfo_gmp_and)
272 ZEND_FE(gmp_or, arginfo_gmp_or)
273 ZEND_FE(gmp_com, arginfo_gmp_com)
274 ZEND_FE(gmp_xor, arginfo_gmp_xor)
275 ZEND_FE(gmp_setbit, arginfo_gmp_setbit)
276 ZEND_FE(gmp_clrbit, arginfo_gmp_clrbit)
277 ZEND_FE(gmp_scan0, arginfo_gmp_scan0)
278 ZEND_FE(gmp_scan1, arginfo_gmp_scan1)
279 ZEND_FE(gmp_testbit,arginfo_gmp_testbit)
280 ZEND_FE(gmp_popcount, arginfo_gmp_popcount)
281 ZEND_FE(gmp_hamdist, arginfo_gmp_hamdist)
282 ZEND_FE(gmp_nextprime, arginfo_gmp_nextprime)
283 PHP_FE_END
284 };
285 /* }}} */
286
287 /* {{{ gmp_module_entry
288 */
289 zend_module_entry gmp_module_entry = {
290 STANDARD_MODULE_HEADER,
291 "gmp",
292 gmp_functions,
293 ZEND_MODULE_STARTUP_N(gmp),
294 NULL,
295 NULL,
296 ZEND_MODULE_DEACTIVATE_N(gmp),
297 ZEND_MODULE_INFO_N(gmp),
298 NO_VERSION_YET,
299 ZEND_MODULE_GLOBALS(gmp),
300 ZEND_GINIT(gmp),
301 NULL,
302 NULL,
303 STANDARD_MODULE_PROPERTIES_EX
304 };
305 /* }}} */
306
307 #ifdef COMPILE_DL_GMP
308 ZEND_GET_MODULE(gmp)
309 #endif
310
311 static void _php_gmpnum_free(zend_rsrc_list_entry *rsrc TSRMLS_DC);
312
313 #define GMP_RESOURCE_NAME "GMP integer"
314
315 #define GMP_ROUND_ZERO 0
316 #define GMP_ROUND_PLUSINF 1
317 #define GMP_ROUND_MINUSINF 2
318
319 /* The maximum base for input and output conversions is 62 from GMP 4.2
320 * onwards. */
321 #if (__GNU_MP_VERSION >= 5) || (__GNU_MP_VERSION >= 4 && __GNU_MP_VERSION_MINOR >= 2)
322 # define MAX_BASE 62
323 #else
324 # define MAX_BASE 36
325 #endif
326
327 /* {{{ gmp_emalloc
328 */
gmp_emalloc(size_t size)329 static void *gmp_emalloc(size_t size)
330 {
331 return emalloc(size);
332 }
333 /* }}} */
334
335 /* {{{ gmp_erealloc
336 */
gmp_erealloc(void * ptr,size_t old_size,size_t new_size)337 static void *gmp_erealloc(void *ptr, size_t old_size, size_t new_size)
338 {
339 return erealloc(ptr, new_size);
340 }
341 /* }}} */
342
343 /* {{{ gmp_efree
344 */
gmp_efree(void * ptr,size_t size)345 static void gmp_efree(void *ptr, size_t size)
346 {
347 efree(ptr);
348 }
349 /* }}} */
350
351 /* {{{ ZEND_GINIT_FUNCTION
352 */
ZEND_GINIT_FUNCTION(gmp)353 static ZEND_GINIT_FUNCTION(gmp)
354 {
355 gmp_globals->rand_initialized = 0;
356 }
357 /* }}} */
358
359 /* {{{ ZEND_MINIT_FUNCTION
360 */
ZEND_MODULE_STARTUP_D(gmp)361 ZEND_MODULE_STARTUP_D(gmp)
362 {
363 le_gmp = zend_register_list_destructors_ex(_php_gmpnum_free, NULL, GMP_RESOURCE_NAME, module_number);
364 REGISTER_LONG_CONSTANT("GMP_ROUND_ZERO", GMP_ROUND_ZERO, CONST_CS | CONST_PERSISTENT);
365 REGISTER_LONG_CONSTANT("GMP_ROUND_PLUSINF", GMP_ROUND_PLUSINF, CONST_CS | CONST_PERSISTENT);
366 REGISTER_LONG_CONSTANT("GMP_ROUND_MINUSINF", GMP_ROUND_MINUSINF, CONST_CS | CONST_PERSISTENT);
367 #ifdef mpir_version
368 REGISTER_STRING_CONSTANT("GMP_MPIR_VERSION", (char *)mpir_version, CONST_CS | CONST_PERSISTENT);
369 #endif
370 REGISTER_STRING_CONSTANT("GMP_VERSION", (char *)gmp_version, CONST_CS | CONST_PERSISTENT);
371
372 mp_set_memory_functions(gmp_emalloc, gmp_erealloc, gmp_efree);
373
374 return SUCCESS;
375 }
376 /* }}} */
377
378 /* {{{ ZEND_RSHUTDOWN_FUNCTION
379 */
ZEND_MODULE_DEACTIVATE_D(gmp)380 ZEND_MODULE_DEACTIVATE_D(gmp)
381 {
382 if (GMPG(rand_initialized)) {
383 gmp_randclear(GMPG(rand_state));
384 GMPG(rand_initialized) = 0;
385 }
386
387 return SUCCESS;
388 }
389 /* }}} */
390
391 /* {{{ ZEND_MINFO_FUNCTION
392 */
ZEND_MODULE_INFO_D(gmp)393 ZEND_MODULE_INFO_D(gmp)
394 {
395 php_info_print_table_start();
396 php_info_print_table_row(2, "gmp support", "enabled");
397 #ifdef mpir_version
398 php_info_print_table_row(2, "MPIR version", mpir_version);
399 #else
400 php_info_print_table_row(2, "GMP version", gmp_version);
401 #endif
402 php_info_print_table_end();
403 }
404 /* }}} */
405
406 /* Fetch zval to be GMP number.
407 Initially, zval can be also number or string */
408 #define FETCH_GMP_ZVAL(gmpnumber, zval, tmp_resource) \
409 if (Z_TYPE_PP(zval) == IS_RESOURCE) { \
410 ZEND_FETCH_RESOURCE(gmpnumber, mpz_t *, zval, -1, GMP_RESOURCE_NAME, le_gmp); \
411 tmp_resource = 0; \
412 } else { \
413 if (convert_to_gmp(&gmpnumber, zval, 0 TSRMLS_CC) == FAILURE) { \
414 RETURN_FALSE; \
415 } \
416 tmp_resource = ZEND_REGISTER_RESOURCE(NULL, gmpnumber, le_gmp); \
417 }
418
419 #define FREE_GMP_TEMP(tmp_resource) \
420 if(tmp_resource) { \
421 zend_list_delete(tmp_resource); \
422 }
423
424
425 /* create a new initialized GMP number */
426 #define INIT_GMP_NUM(gmpnumber) { gmpnumber=emalloc(sizeof(mpz_t)); mpz_init(*gmpnumber); }
427 #define FREE_GMP_NUM(gmpnumber) { mpz_clear(*gmpnumber); efree(gmpnumber); }
428
429 /* {{{ convert_to_gmp
430 * Convert zval to be gmp number */
convert_to_gmp(mpz_t ** gmpnumber,zval ** val,int base TSRMLS_DC)431 static int convert_to_gmp(mpz_t * *gmpnumber, zval **val, int base TSRMLS_DC)
432 {
433 int ret = 0;
434 int skip_lead = 0;
435
436 *gmpnumber = emalloc(sizeof(mpz_t));
437
438 switch (Z_TYPE_PP(val)) {
439 case IS_LONG:
440 case IS_BOOL:
441 case IS_CONSTANT:
442 {
443 convert_to_long_ex(val);
444 mpz_init_set_si(**gmpnumber, Z_LVAL_PP(val));
445 }
446 break;
447 case IS_STRING:
448 {
449 char *numstr = Z_STRVAL_PP(val);
450
451 if (Z_STRLEN_PP(val) > 2) {
452 if (numstr[0] == '0') {
453 if (numstr[1] == 'x' || numstr[1] == 'X') {
454 base = 16;
455 skip_lead = 1;
456 } else if (base != 16 && (numstr[1] == 'b' || numstr[1] == 'B')) {
457 base = 2;
458 skip_lead = 1;
459 }
460 }
461 }
462 ret = mpz_init_set_str(**gmpnumber, (skip_lead ? &numstr[2] : numstr), base);
463 }
464 break;
465 default:
466 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Unable to convert variable to GMP - wrong type");
467 efree(*gmpnumber);
468 return FAILURE;
469 }
470
471 if (ret) {
472 FREE_GMP_NUM(*gmpnumber);
473 return FAILURE;
474 }
475
476 return SUCCESS;
477 }
478 /* }}} */
479
480 /* {{{ typedefs
481 */
482 typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr);
483 typedef int (*gmp_unary_opl_t)(mpz_srcptr);
484
485 typedef void (*gmp_unary_ui_op_t)(mpz_ptr, unsigned long);
486
487 typedef void (*gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr);
488 typedef int (*gmp_binary_opl_t)(mpz_srcptr, mpz_srcptr);
489
490 typedef unsigned long (*gmp_binary_ui_op_t)(mpz_ptr, mpz_srcptr, unsigned long);
491 typedef void (*gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
492 typedef unsigned long (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long);
493 /* }}} */
494
495 #define gmp_zval_binary_ui_op(r, a, b, o, u) gmp_zval_binary_ui_op_ex(r, a, b, o, u, 0, 0, 0 TSRMLS_CC)
496 #define gmp_zval_binary_ui_op2(r, a, b, o, u) gmp_zval_binary_ui_op2_ex(r, a, b, o, u, 0, 0, 0 TSRMLS_CC)
497
498 #define gmp_binary_ui_op(op, uop) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop)
499 #define gmp_binary_op(op) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, NULL)
500 #define gmp_binary_opl(op) _gmp_binary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
501
502 /* Unary operations */
503 #define gmp_unary_op(op) _gmp_unary_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
504 #define gmp_unary_opl(op) _gmp_unary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
505 #define gmp_unary_ui_op(op) _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
506
507 /* {{{ gmp_zval_binary_ui_op_ex
508 Execute GMP binary operation.
509 May return GMP resource or long if operation allows this
510 */
gmp_zval_binary_ui_op_ex(zval * return_value,zval ** a_arg,zval ** b_arg,gmp_binary_op_t gmp_op,gmp_binary_ui_op_t gmp_ui_op,int allow_ui_return,int check_b_zero,int use_sign TSRMLS_DC)511 static inline void gmp_zval_binary_ui_op_ex(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int allow_ui_return, int check_b_zero, int use_sign TSRMLS_DC)
512 {
513 mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result;
514 unsigned long long_result = 0;
515 int use_ui = 0;
516 int arga_tmp = 0, argb_tmp = 0;
517
518 FETCH_GMP_ZVAL(gmpnum_a, a_arg, arga_tmp);
519
520 if (gmp_ui_op && Z_TYPE_PP(b_arg) == IS_LONG && Z_LVAL_PP(b_arg) >= 0) {
521 use_ui = 1;
522 } else {
523 FETCH_GMP_ZVAL(gmpnum_b, b_arg, argb_tmp);
524 }
525
526 if(check_b_zero) {
527 int b_is_zero = 0;
528 if(use_ui) {
529 b_is_zero = (Z_LVAL_PP(b_arg) == 0);
530 } else {
531 b_is_zero = !mpz_cmp_ui(*gmpnum_b, 0);
532 }
533
534 if(b_is_zero) {
535 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero operand not allowed");
536 FREE_GMP_TEMP(arga_tmp);
537 FREE_GMP_TEMP(argb_tmp);
538 RETURN_FALSE;
539 }
540 }
541
542 INIT_GMP_NUM(gmpnum_result);
543
544 if (use_ui && gmp_ui_op) {
545 if (allow_ui_return) {
546 long_result = gmp_ui_op(*gmpnum_result, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg));
547 if (use_sign && mpz_sgn(*gmpnum_a) == -1) {
548 long_result = -long_result;
549 }
550 } else {
551 gmp_ui_op(*gmpnum_result, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg));
552 }
553 } else {
554 gmp_op(*gmpnum_result, *gmpnum_a, *gmpnum_b);
555 }
556
557 FREE_GMP_TEMP(arga_tmp);
558 FREE_GMP_TEMP(argb_tmp);
559
560 if (use_ui && allow_ui_return) {
561 FREE_GMP_NUM(gmpnum_result);
562 RETURN_LONG((long)long_result);
563 } else {
564 ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
565 }
566 }
567 /* }}} */
568
569 /* {{{ gmp_zval_binary_ui_op2_ex
570 Execute GMP binary operation which returns 2 values.
571 May return GMP resources or longs if operation allows this.
572 */
gmp_zval_binary_ui_op2_ex(zval * return_value,zval ** a_arg,zval ** b_arg,gmp_binary_op2_t gmp_op,gmp_binary_ui_op2_t gmp_ui_op,int allow_ui_return,int check_b_zero TSRMLS_DC)573 static inline void gmp_zval_binary_ui_op2_ex(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int allow_ui_return, int check_b_zero TSRMLS_DC)
574 {
575 mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result1, *gmpnum_result2;
576 zval r;
577 int use_ui = 0;
578 unsigned long long_result = 0;
579 int arga_tmp = 0, argb_tmp = 0;
580
581 FETCH_GMP_ZVAL(gmpnum_a, a_arg, arga_tmp);
582
583 if (gmp_ui_op && Z_TYPE_PP(b_arg) == IS_LONG && Z_LVAL_PP(b_arg) >= 0) {
584 /* use _ui function */
585 use_ui = 1;
586 } else {
587 FETCH_GMP_ZVAL(gmpnum_b, b_arg, argb_tmp);
588 }
589
590 if(check_b_zero) {
591 int b_is_zero = 0;
592 if(use_ui) {
593 b_is_zero = (Z_LVAL_PP(b_arg) == 0);
594 } else {
595 b_is_zero = !mpz_cmp_ui(*gmpnum_b, 0);
596 }
597
598 if(b_is_zero) {
599 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero operand not allowed");
600 FREE_GMP_TEMP(arga_tmp);
601 FREE_GMP_TEMP(argb_tmp);
602 RETURN_FALSE;
603 }
604 }
605
606 INIT_GMP_NUM(gmpnum_result1);
607 INIT_GMP_NUM(gmpnum_result2);
608
609 if (use_ui && gmp_ui_op) {
610 if (allow_ui_return) {
611 long_result = gmp_ui_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg));
612 } else {
613 gmp_ui_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg));
614 }
615 } else {
616 gmp_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, *gmpnum_b);
617 }
618
619 FREE_GMP_TEMP(arga_tmp);
620 FREE_GMP_TEMP(argb_tmp);
621
622 array_init(return_value);
623 ZEND_REGISTER_RESOURCE(&r, gmpnum_result1, le_gmp);
624 add_index_resource(return_value, 0, Z_LVAL(r));
625 if (use_ui && allow_ui_return) {
626 mpz_clear(*gmpnum_result2);
627 add_index_long(return_value, 1, long_result);
628 } else {
629 ZEND_REGISTER_RESOURCE(&r, gmpnum_result2, le_gmp);
630 add_index_resource(return_value, 1, Z_LVAL(r));
631 }
632 }
633 /* }}} */
634
635 /* {{{ _gmp_binary_ui_op
636 */
_gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS,gmp_binary_op_t gmp_op,gmp_binary_ui_op_t gmp_ui_op)637 static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op)
638 {
639 zval **a_arg, **b_arg;
640
641 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
642 return;
643 }
644
645 gmp_zval_binary_ui_op(return_value, a_arg, b_arg, gmp_op, gmp_ui_op);
646 }
647 /* }}} */
648
649 /* Unary operations */
650
651 /* {{{ gmp_zval_unary_op
652 */
gmp_zval_unary_op(zval * return_value,zval ** a_arg,gmp_unary_op_t gmp_op TSRMLS_DC)653 static inline void gmp_zval_unary_op(zval *return_value, zval **a_arg, gmp_unary_op_t gmp_op TSRMLS_DC)
654 {
655 mpz_t *gmpnum_a, *gmpnum_result;
656 int temp_a;
657
658 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
659
660 INIT_GMP_NUM(gmpnum_result);
661 gmp_op(*gmpnum_result, *gmpnum_a);
662
663 FREE_GMP_TEMP(temp_a);
664 ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
665 }
666 /* }}} */
667
668 /* {{{ gmp_zval_unary_ui_op
669 */
gmp_zval_unary_ui_op(zval * return_value,zval ** a_arg,gmp_unary_ui_op_t gmp_op)670 static inline void gmp_zval_unary_ui_op(zval *return_value, zval **a_arg, gmp_unary_ui_op_t gmp_op)
671 {
672 mpz_t *gmpnum_result;
673
674 convert_to_long_ex(a_arg);
675
676 INIT_GMP_NUM(gmpnum_result);
677 gmp_op(*gmpnum_result, Z_LVAL_PP(a_arg));
678
679 ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
680 }
681 /* }}} */
682
683 /* {{{ _gmp_unary_ui_op
684 Execute GMP unary operation.
685 */
_gmp_unary_ui_op(INTERNAL_FUNCTION_PARAMETERS,gmp_unary_ui_op_t gmp_op)686 static inline void _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_ui_op_t gmp_op)
687 {
688 zval **a_arg;
689
690 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
691 return;
692 }
693
694 gmp_zval_unary_ui_op(return_value, a_arg, gmp_op);
695 }
696 /* }}} */
697
698 /* {{{ _gmp_unary_op
699 */
_gmp_unary_op(INTERNAL_FUNCTION_PARAMETERS,gmp_unary_op_t gmp_op)700 static inline void _gmp_unary_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_op_t gmp_op)
701 {
702 zval **a_arg;
703
704 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
705 return;
706 }
707
708 gmp_zval_unary_op(return_value, a_arg, gmp_op TSRMLS_CC);
709 }
710 /* }}} */
711
712 /* {{{ _gmp_unary_opl
713 */
_gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS,gmp_unary_opl_t gmp_op)714 static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t gmp_op)
715 {
716 zval **a_arg;
717 mpz_t *gmpnum_a;
718 int temp_a;
719
720 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
721 return;
722 }
723
724 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
725 RETVAL_LONG(gmp_op(*gmpnum_a));
726 FREE_GMP_TEMP(temp_a);
727 }
728 /* }}} */
729
730 /* {{{ _gmp_binary_opl
731 */
_gmp_binary_opl(INTERNAL_FUNCTION_PARAMETERS,gmp_binary_opl_t gmp_op)732 static inline void _gmp_binary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_opl_t gmp_op)
733 {
734 zval **a_arg, **b_arg;
735 mpz_t *gmpnum_a, *gmpnum_b;
736 int temp_a, temp_b;
737
738 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
739 return;
740 }
741
742 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
743 FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b);
744
745 RETVAL_LONG(gmp_op(*gmpnum_a, *gmpnum_b));
746
747 FREE_GMP_TEMP(temp_a);
748 FREE_GMP_TEMP(temp_b);
749 }
750 /* }}} */
751
752 /* {{{ proto resource gmp_init(mixed number [, int base])
753 Initializes GMP number */
ZEND_FUNCTION(gmp_init)754 ZEND_FUNCTION(gmp_init)
755 {
756 zval **number_arg;
757 mpz_t * gmpnumber;
758 long base=0;
759
760 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &number_arg, &base) == FAILURE) {
761 return;
762 }
763
764 if (base && (base < 2 || base > MAX_BASE)) {
765 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad base for conversion: %ld (should be between 2 and %d)", base, MAX_BASE);
766 RETURN_FALSE;
767 }
768
769 if (convert_to_gmp(&gmpnumber, number_arg, base TSRMLS_CC) == FAILURE) {
770 RETURN_FALSE;
771 }
772
773 /* Write your own code here to handle argument number. */
774 ZEND_REGISTER_RESOURCE(return_value, gmpnumber, le_gmp);
775 }
776 /* }}} */
777
778 /* {{{ proto int gmp_intval(resource gmpnumber)
779 Gets signed long value of GMP number */
ZEND_FUNCTION(gmp_intval)780 ZEND_FUNCTION(gmp_intval)
781 {
782 zval **gmpnumber_arg;
783 mpz_t * gmpnum;
784
785 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &gmpnumber_arg) == FAILURE){
786 return;
787 }
788
789 if (Z_TYPE_PP(gmpnumber_arg) == IS_RESOURCE) {
790 ZEND_FETCH_RESOURCE(gmpnum, mpz_t *, gmpnumber_arg, -1, GMP_RESOURCE_NAME, le_gmp);
791 RETVAL_LONG(mpz_get_si(*gmpnum));
792 } else {
793 convert_to_long_ex(gmpnumber_arg);
794 RETVAL_LONG(Z_LVAL_PP(gmpnumber_arg));
795 }
796 }
797 /* }}} */
798
799 /* {{{ proto string gmp_strval(resource gmpnumber [, int base])
800 Gets string representation of GMP number */
ZEND_FUNCTION(gmp_strval)801 ZEND_FUNCTION(gmp_strval)
802 {
803 zval **gmpnumber_arg;
804 int num_len;
805 long base = 10;
806 mpz_t * gmpnum;
807 char *out_string;
808 int temp_a;
809
810 if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &gmpnumber_arg, &base ) == FAILURE ) {
811 return;
812 }
813
814 #if MAX_BASE == 62
815 /* Although the maximum base in general in GMP >= 4.2 is 62, mpz_get_str()
816 * is explicitly limited to -36 when dealing with negative bases. */
817 if ((base < 2 && base > -2) || base > MAX_BASE || base < -36) {
818 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad base for conversion: %ld (should be between 2 and %d or -2 and -36)", base, MAX_BASE);
819 #else
820 if (base < 2 || base > MAX_BASE) {
821 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad base for conversion: %ld (should be between 2 and %d)", base, MAX_BASE);
822 #endif
823 RETURN_FALSE;
824 }
825
826 FETCH_GMP_ZVAL(gmpnum, gmpnumber_arg, temp_a);
827
828 num_len = mpz_sizeinbase(*gmpnum, abs(base));
829 out_string = emalloc(num_len+2);
830 if (mpz_sgn(*gmpnum) < 0) {
831 num_len++;
832 }
833 mpz_get_str(out_string, base, *gmpnum);
834
835 FREE_GMP_TEMP(temp_a);
836
837 /*
838 From GMP documentation for mpz_sizeinbase():
839 The returned value will be exact or 1 too big. If base is a power of
840 2, the returned value will always be exact.
841
842 So let's check to see if we already have a \0 byte...
843 */
844
845 if (out_string[num_len-1] == '\0') {
846 num_len--;
847 } else {
848 out_string[num_len] = '\0';
849 }
850 RETVAL_STRINGL(out_string, num_len, 0);
851 }
852 /* }}} */
853
854 /* {{{ proto resource gmp_add(resource a, resource b)
855 Add a and b */
856 ZEND_FUNCTION(gmp_add)
857 {
858 gmp_binary_ui_op(mpz_add, (gmp_binary_ui_op_t)mpz_add_ui);
859 }
860 /* }}} */
861
862 /* {{{ proto resource gmp_sub(resource a, resource b)
863 Subtract b from a */
864 ZEND_FUNCTION(gmp_sub)
865 {
866 gmp_binary_ui_op(mpz_sub, (gmp_binary_ui_op_t)mpz_sub_ui);
867 }
868 /* }}} */
869
870 /* {{{ proto resource gmp_mul(resource a, resource b)
871 Multiply a and b */
872 ZEND_FUNCTION(gmp_mul)
873 {
874 gmp_binary_ui_op(mpz_mul, (gmp_binary_ui_op_t)mpz_mul_ui);
875 }
876 /* }}} */
877
878 /* {{{ proto array gmp_div_qr(resource a, resource b [, int round])
879 Divide a by b, returns quotient and reminder */
880 ZEND_FUNCTION(gmp_div_qr)
881 {
882 zval **a_arg, **b_arg;
883 long round = GMP_ROUND_ZERO;
884
885 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|l", &a_arg, &b_arg, &round) == FAILURE) {
886 return;
887 }
888
889 switch (round) {
890 case GMP_ROUND_ZERO:
891 gmp_zval_binary_ui_op2_ex(return_value, a_arg, b_arg, mpz_tdiv_qr, (gmp_binary_ui_op2_t)mpz_tdiv_qr_ui, 0, 1 TSRMLS_CC);
892 break;
893 case GMP_ROUND_PLUSINF:
894 gmp_zval_binary_ui_op2_ex(return_value, a_arg, b_arg, mpz_cdiv_qr, (gmp_binary_ui_op2_t)mpz_cdiv_qr_ui, 0, 1 TSRMLS_CC);
895 break;
896 case GMP_ROUND_MINUSINF:
897 gmp_zval_binary_ui_op2_ex(return_value, a_arg, b_arg, mpz_fdiv_qr, (gmp_binary_ui_op2_t)mpz_fdiv_qr_ui, 0, 1 TSRMLS_CC);
898 break;
899 }
900
901 }
902 /* }}} */
903
904 /* {{{ proto resource gmp_div_r(resource a, resource b [, int round])
905 Divide a by b, returns reminder only */
906 ZEND_FUNCTION(gmp_div_r)
907 {
908 zval **a_arg, **b_arg;
909 long round = GMP_ROUND_ZERO;
910
911 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|l", &a_arg, &b_arg, &round) == FAILURE) {
912 return;
913 }
914
915 switch (round) {
916 case GMP_ROUND_ZERO:
917 gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_tdiv_r, (gmp_binary_ui_op_t)mpz_tdiv_r_ui, 1, 1, 1 TSRMLS_CC);
918 break;
919 case GMP_ROUND_PLUSINF:
920 gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_cdiv_r, (gmp_binary_ui_op_t)mpz_cdiv_r_ui, 1, 1, 1 TSRMLS_CC);
921 break;
922 case GMP_ROUND_MINUSINF:
923 gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_fdiv_r, (gmp_binary_ui_op_t)mpz_fdiv_r_ui, 1, 1, 1 TSRMLS_CC);
924 break;
925 }
926 }
927 /* }}} */
928
929 /* {{{ proto resource gmp_div_q(resource a, resource b [, int round])
930 Divide a by b, returns quotient only */
931 ZEND_FUNCTION(gmp_div_q)
932 {
933 zval **a_arg, **b_arg;
934 long round = GMP_ROUND_ZERO;
935
936 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|l", &a_arg, &b_arg, &round) == FAILURE) {
937 return;
938 }
939
940 switch (round) {
941 case GMP_ROUND_ZERO:
942 gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_tdiv_q, (gmp_binary_ui_op_t)mpz_tdiv_q_ui, 0, 1, 1 TSRMLS_CC);
943 break;
944 case GMP_ROUND_PLUSINF:
945 gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_cdiv_q, (gmp_binary_ui_op_t)mpz_cdiv_q_ui, 0, 1, 1 TSRMLS_CC);
946 break;
947 case GMP_ROUND_MINUSINF:
948 gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_fdiv_q, (gmp_binary_ui_op_t)mpz_fdiv_q_ui, 0, 1, 1 TSRMLS_CC);
949 break;
950 }
951
952 }
953 /* }}} */
954
955 /* {{{ proto resource gmp_mod(resource a, resource b)
956 Computes a modulo b */
957 ZEND_FUNCTION(gmp_mod)
958 {
959 zval **a_arg, **b_arg;
960
961 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
962 return;
963 }
964
965 gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_mod, (gmp_binary_ui_op_t)mpz_mod_ui, 1, 1, 0 TSRMLS_CC);
966 }
967 /* }}} */
968
969 /* {{{ proto resource gmp_divexact(resource a, resource b)
970 Divide a by b using exact division algorithm */
971 ZEND_FUNCTION(gmp_divexact)
972 {
973 zval **a_arg, **b_arg;
974
975 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
976 return;
977 }
978
979 gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_divexact, NULL, 0, 1, 1 TSRMLS_CC);
980 }
981 /* }}} */
982
983 /* {{{ proto resource gmp_neg(resource a)
984 Negates a number */
985 ZEND_FUNCTION(gmp_neg)
986 {
987 gmp_unary_op(mpz_neg);
988 }
989 /* }}} */
990
991 /* {{{ proto resource gmp_abs(resource a)
992 Calculates absolute value */
993 ZEND_FUNCTION(gmp_abs)
994 {
995 gmp_unary_op(mpz_abs);
996 }
997 /* }}} */
998
999 /* {{{ proto resource gmp_fact(int a)
1000 Calculates factorial function */
1001 ZEND_FUNCTION(gmp_fact)
1002 {
1003 zval **a_arg;
1004 mpz_t *gmpnum_tmp;
1005 int temp_a;
1006
1007 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
1008 return;
1009 }
1010
1011 if (Z_TYPE_PP(a_arg) == IS_RESOURCE) {
1012 FETCH_GMP_ZVAL(gmpnum_tmp, a_arg, temp_a); /* no need to free this since it's IS_RESOURCE */
1013 if (mpz_sgn(*gmpnum_tmp) < 0) {
1014 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0");
1015 RETURN_FALSE;
1016 }
1017 } else {
1018 convert_to_long_ex(a_arg);
1019 if (Z_LVAL_PP(a_arg) < 0) {
1020 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0");
1021 RETURN_FALSE;
1022 }
1023 }
1024
1025 gmp_zval_unary_ui_op(return_value, a_arg, mpz_fac_ui);
1026 }
1027 /* }}} */
1028
1029 /* {{{ proto resource gmp_pow(resource base, int exp)
1030 Raise base to power exp */
1031 ZEND_FUNCTION(gmp_pow)
1032 {
1033 zval **base_arg;
1034 mpz_t *gmpnum_result, *gmpnum_base;
1035 int use_ui = 0;
1036 int temp_base;
1037 long exp;
1038
1039 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &base_arg, &exp) == FAILURE) {
1040 return;
1041 }
1042
1043 if (Z_TYPE_PP(base_arg) == IS_LONG && Z_LVAL_PP(base_arg) >= 0) {
1044 use_ui = 1;
1045 } else {
1046 FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base);
1047 }
1048
1049 if (exp < 0) {
1050 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Negative exponent not supported");
1051 RETURN_FALSE;
1052 }
1053
1054 INIT_GMP_NUM(gmpnum_result);
1055 if (use_ui) {
1056 mpz_ui_pow_ui(*gmpnum_result, Z_LVAL_PP(base_arg), exp);
1057 } else {
1058 mpz_pow_ui(*gmpnum_result, *gmpnum_base, exp);
1059 FREE_GMP_TEMP(temp_base);
1060 }
1061 ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
1062 }
1063 /* }}} */
1064
1065 /* {{{ proto resource gmp_powm(resource base, resource exp, resource mod)
1066 Raise base to power exp and take result modulo mod */
1067 ZEND_FUNCTION(gmp_powm)
1068 {
1069 zval **base_arg, **exp_arg, **mod_arg;
1070 mpz_t *gmpnum_base, *gmpnum_exp, *gmpnum_mod, *gmpnum_result;
1071 int use_ui = 0;
1072 int temp_base, temp_exp, temp_mod;
1073
1074 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ", &base_arg, &exp_arg, &mod_arg) == FAILURE){
1075 return;
1076 }
1077
1078 FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base);
1079
1080 if (Z_TYPE_PP(exp_arg) == IS_LONG && Z_LVAL_PP(exp_arg) >= 0) {
1081 use_ui = 1;
1082 } else {
1083 FETCH_GMP_ZVAL(gmpnum_exp, exp_arg, temp_exp);
1084 if (mpz_sgn(*gmpnum_exp) < 0) {
1085 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Second parameter cannot be less than 0");
1086 RETURN_FALSE;
1087 }
1088 }
1089 FETCH_GMP_ZVAL(gmpnum_mod, mod_arg, temp_mod);
1090
1091 if (!mpz_cmp_ui(*gmpnum_mod, 0)) {
1092 FREE_GMP_TEMP(temp_base);
1093 if (use_ui) {
1094 FREE_GMP_TEMP(temp_exp);
1095 }
1096 FREE_GMP_TEMP(temp_mod);
1097 RETURN_FALSE;
1098 }
1099
1100 INIT_GMP_NUM(gmpnum_result);
1101 if (use_ui) {
1102 mpz_powm_ui(*gmpnum_result, *gmpnum_base, (unsigned long)Z_LVAL_PP(exp_arg), *gmpnum_mod);
1103 } else {
1104 mpz_powm(*gmpnum_result, *gmpnum_base, *gmpnum_exp, *gmpnum_mod);
1105 FREE_GMP_TEMP(temp_exp);
1106 }
1107
1108 FREE_GMP_TEMP(temp_base);
1109 FREE_GMP_TEMP(temp_mod);
1110
1111 ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
1112
1113 }
1114 /* }}} */
1115
1116 /* {{{ proto resource gmp_sqrt(resource a)
1117 Takes integer part of square root of a */
1118 ZEND_FUNCTION(gmp_sqrt)
1119 {
1120 zval **a_arg;
1121 mpz_t *gmpnum_a, *gmpnum_result;
1122 int temp_a;
1123
1124 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
1125 return;
1126 }
1127
1128 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1129
1130 if (mpz_sgn(*gmpnum_a) < 0) {
1131 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0");
1132 FREE_GMP_TEMP(temp_a);
1133 RETURN_FALSE;
1134 }
1135
1136 INIT_GMP_NUM(gmpnum_result);
1137 mpz_sqrt(*gmpnum_result, *gmpnum_a);
1138 FREE_GMP_TEMP(temp_a);
1139
1140 ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
1141 }
1142 /* }}} */
1143
1144 /* {{{ proto array gmp_sqrtrem(resource a)
1145 Square root with remainder */
1146 ZEND_FUNCTION(gmp_sqrtrem)
1147 {
1148 zval **a_arg;
1149 mpz_t *gmpnum_a, *gmpnum_result1, *gmpnum_result2;
1150 zval r;
1151 int temp_a;
1152
1153 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
1154 return;
1155 }
1156
1157 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1158
1159 if (mpz_sgn(*gmpnum_a) < 0) {
1160 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Number has to be greater than or equal to 0");
1161 RETURN_FALSE;
1162 }
1163
1164 INIT_GMP_NUM(gmpnum_result1);
1165 INIT_GMP_NUM(gmpnum_result2);
1166
1167 mpz_sqrtrem(*gmpnum_result1, *gmpnum_result2, *gmpnum_a);
1168 FREE_GMP_TEMP(temp_a);
1169
1170 array_init(return_value);
1171 ZEND_REGISTER_RESOURCE(&r, gmpnum_result1, le_gmp);
1172 add_index_resource(return_value, 0, Z_LVAL(r));
1173 ZEND_REGISTER_RESOURCE(&r, gmpnum_result2, le_gmp);
1174 add_index_resource(return_value, 1, Z_LVAL(r));
1175 }
1176 /* }}} */
1177
1178 /* {{{ proto bool gmp_perfect_square(resource a)
1179 Checks if a is an exact square */
1180 ZEND_FUNCTION(gmp_perfect_square)
1181 {
1182 zval **a_arg;
1183 mpz_t *gmpnum_a;
1184 int temp_a;
1185
1186 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
1187 return;
1188 }
1189
1190 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1191
1192 RETVAL_BOOL((mpz_perfect_square_p(*gmpnum_a)!=0));
1193 FREE_GMP_TEMP(temp_a);
1194 }
1195 /* }}} */
1196
1197 /* {{{ proto int gmp_prob_prime(resource a[, int reps])
1198 Checks if a is "probably prime" */
1199 ZEND_FUNCTION(gmp_prob_prime)
1200 {
1201 zval **gmpnumber_arg;
1202 mpz_t *gmpnum_a;
1203 long reps = 10;
1204 int temp_a;
1205
1206 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &gmpnumber_arg, &reps) == FAILURE) {
1207 return;
1208 }
1209
1210 FETCH_GMP_ZVAL(gmpnum_a, gmpnumber_arg, temp_a);
1211
1212 RETVAL_LONG(mpz_probab_prime_p(*gmpnum_a, reps));
1213 FREE_GMP_TEMP(temp_a);
1214 }
1215 /* }}} */
1216
1217 /* {{{ proto resource gmp_gcd(resource a, resource b)
1218 Computes greatest common denominator (gcd) of a and b */
1219 ZEND_FUNCTION(gmp_gcd)
1220 {
1221 zval **a_arg, **b_arg;
1222
1223 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
1224 return;
1225 }
1226
1227 gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_gcd, (gmp_binary_ui_op_t)mpz_gcd_ui, 0, 0, 1 TSRMLS_CC);
1228 }
1229 /* }}} */
1230
1231 /* {{{ proto array gmp_gcdext(resource a, resource b)
1232 Computes G, S, and T, such that AS + BT = G = `gcd' (A, B) */
1233 ZEND_FUNCTION(gmp_gcdext)
1234 {
1235 zval **a_arg, **b_arg;
1236 mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_t, *gmpnum_s, *gmpnum_g;
1237 zval r;
1238 int temp_a, temp_b;
1239
1240 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
1241 return;
1242 }
1243
1244 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1245 FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b);
1246
1247 INIT_GMP_NUM(gmpnum_g);
1248 INIT_GMP_NUM(gmpnum_s);
1249 INIT_GMP_NUM(gmpnum_t);
1250
1251 mpz_gcdext(*gmpnum_g, *gmpnum_s, *gmpnum_t, *gmpnum_a, *gmpnum_b);
1252 FREE_GMP_TEMP(temp_a);
1253 FREE_GMP_TEMP(temp_b);
1254
1255 array_init(return_value);
1256
1257 ZEND_REGISTER_RESOURCE(&r, gmpnum_g, le_gmp);
1258 add_assoc_resource(return_value, "g", Z_LVAL(r));
1259 ZEND_REGISTER_RESOURCE(&r, gmpnum_s, le_gmp);
1260 add_assoc_resource(return_value, "s", Z_LVAL(r));
1261 ZEND_REGISTER_RESOURCE(&r, gmpnum_t, le_gmp);
1262 add_assoc_resource(return_value, "t", Z_LVAL(r));
1263 }
1264 /* }}} */
1265
1266 /* {{{ proto resource gmp_invert(resource a, resource b)
1267 Computes the inverse of a modulo b */
1268 ZEND_FUNCTION(gmp_invert)
1269 {
1270 zval **a_arg, **b_arg;
1271 mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result;
1272 int temp_a, temp_b;
1273 int res;
1274
1275 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
1276 return;
1277 }
1278
1279 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1280 FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b);
1281
1282 INIT_GMP_NUM(gmpnum_result);
1283 res=mpz_invert(*gmpnum_result, *gmpnum_a, *gmpnum_b);
1284 FREE_GMP_TEMP(temp_a);
1285 FREE_GMP_TEMP(temp_b);
1286 if (res) {
1287 ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
1288 } else {
1289 FREE_GMP_NUM(gmpnum_result);
1290 RETURN_FALSE;
1291 }
1292 }
1293 /* }}} */
1294
1295 /* {{{ proto int gmp_jacobi(resource a, resource b)
1296 Computes Jacobi symbol */
1297 ZEND_FUNCTION(gmp_jacobi)
1298 {
1299 gmp_binary_opl(mpz_jacobi);
1300 }
1301 /* }}} */
1302
1303 /* {{{ proto int gmp_legendre(resource a, resource b)
1304 Computes Legendre symbol */
1305 ZEND_FUNCTION(gmp_legendre)
1306 {
1307 gmp_binary_opl(mpz_legendre);
1308 }
1309 /* }}} */
1310
1311 /* {{{ proto int gmp_cmp(resource a, resource b)
1312 Compares two numbers */
1313 ZEND_FUNCTION(gmp_cmp)
1314 {
1315 zval **a_arg, **b_arg;
1316 mpz_t *gmpnum_a, *gmpnum_b;
1317 int use_si = 0, res;
1318 int temp_a, temp_b;
1319
1320 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
1321 return;
1322 }
1323
1324 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1325
1326 if (Z_TYPE_PP(b_arg) == IS_LONG) {
1327 use_si = 1;
1328 } else {
1329 FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b);
1330 }
1331
1332 if (use_si) {
1333 res = mpz_cmp_si(*gmpnum_a, Z_LVAL_PP(b_arg));
1334 } else {
1335 res = mpz_cmp(*gmpnum_a, *gmpnum_b);
1336 }
1337 FREE_GMP_TEMP(temp_a);
1338
1339 RETURN_LONG(res);
1340 }
1341 /* }}} */
1342
1343 /* {{{ proto int gmp_sign(resource a)
1344 Gets the sign of the number */
1345 ZEND_FUNCTION(gmp_sign)
1346 {
1347 zval **a_arg;
1348 mpz_t *gmpnum_a;
1349 int temp_a;
1350
1351 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
1352 return;
1353 }
1354
1355 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1356
1357 RETVAL_LONG(mpz_sgn(*gmpnum_a));
1358 FREE_GMP_TEMP(temp_a);
1359 }
1360 /* }}} */
1361
1362 /* {{{ proto resource gmp_random([int limiter])
1363 Gets random number */
1364 ZEND_FUNCTION(gmp_random)
1365 {
1366 long limiter = 20;
1367 mpz_t *gmpnum_result;
1368
1369 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &limiter) == FAILURE) {
1370 return;
1371 }
1372
1373 INIT_GMP_NUM(gmpnum_result);
1374
1375 if (!GMPG(rand_initialized)) {
1376 /* Initialize */
1377 gmp_randinit_lc_2exp_size(GMPG(rand_state), 32L);
1378
1379 /* Seed */
1380 gmp_randseed_ui(GMPG(rand_state), GENERATE_SEED());
1381
1382 GMPG(rand_initialized) = 1;
1383 }
1384 #ifdef GMP_LIMB_BITS
1385 mpz_urandomb(*gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * GMP_LIMB_BITS);
1386 #else
1387 mpz_urandomb(*gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * __GMP_BITS_PER_MP_LIMB);
1388 #endif
1389 ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
1390 }
1391 /* }}} */
1392
1393 /* {{{ proto resource gmp_and(resource a, resource b)
1394 Calculates logical AND of a and b */
1395 ZEND_FUNCTION(gmp_and)
1396 {
1397 gmp_binary_op(mpz_and);
1398 }
1399 /* }}} */
1400
1401 /* {{{ proto resource gmp_or(resource a, resource b)
1402 Calculates logical OR of a and b */
1403 ZEND_FUNCTION(gmp_or)
1404 {
1405 gmp_binary_op(mpz_ior);
1406 }
1407 /* }}} */
1408
1409 /* {{{ proto resource gmp_com(resource a)
1410 Calculates one's complement of a */
1411 ZEND_FUNCTION(gmp_com)
1412 {
1413 gmp_unary_op(mpz_com);
1414 }
1415 /* }}} */
1416
1417 /* {{{ proto resource gmp_nextprime(resource a)
1418 Finds next prime of a */
1419 ZEND_FUNCTION(gmp_nextprime)
1420 {
1421 gmp_unary_op(mpz_nextprime);
1422 }
1423 /* }}} */
1424
1425 /* {{{ proto resource gmp_xor(resource a, resource b)
1426 Calculates logical exclusive OR of a and b */
1427 ZEND_FUNCTION(gmp_xor)
1428 {
1429 /* use formula: a^b = (a|b)&^(a&b) */
1430 zval **a_arg, **b_arg;
1431 mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result, *gmpnum_t;
1432 int temp_a, temp_b;
1433
1434 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
1435 return;
1436 }
1437
1438 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1439 FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b);
1440
1441 INIT_GMP_NUM(gmpnum_result);
1442 INIT_GMP_NUM(gmpnum_t);
1443
1444 mpz_and(*gmpnum_t, *gmpnum_a, *gmpnum_b);
1445 mpz_com(*gmpnum_t, *gmpnum_t);
1446
1447 mpz_ior(*gmpnum_result, *gmpnum_a, *gmpnum_b);
1448 mpz_and(*gmpnum_result, *gmpnum_result, *gmpnum_t);
1449
1450 FREE_GMP_NUM(gmpnum_t);
1451
1452 FREE_GMP_TEMP(temp_a);
1453 FREE_GMP_TEMP(temp_b);
1454 ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
1455 }
1456 /* }}} */
1457
1458 /* {{{ proto void gmp_setbit(resource &a, int index[, bool set_clear])
1459 Sets or clear bit in a */
1460 ZEND_FUNCTION(gmp_setbit)
1461 {
1462 zval **a_arg;
1463 long index;
1464 zend_bool set = 1;
1465 mpz_t *gmpnum_a;
1466
1467 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl|b", &a_arg, &index, &set) == FAILURE) {
1468 return;
1469 }
1470
1471 ZEND_FETCH_RESOURCE(gmpnum_a, mpz_t *, a_arg, -1, GMP_RESOURCE_NAME, le_gmp);
1472
1473 if (index < 0) {
1474 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero");
1475 return;
1476 }
1477
1478 if (set) {
1479 mpz_setbit(*gmpnum_a, index);
1480 } else {
1481 mpz_clrbit(*gmpnum_a, index);
1482 }
1483 }
1484 /* }}} */
1485
1486 /* {{{ proto void gmp_clrbit(resource &a, int index)
1487 Clears bit in a */
1488 ZEND_FUNCTION(gmp_clrbit)
1489 {
1490 zval **a_arg;
1491 long index;
1492 mpz_t *gmpnum_a;
1493
1494 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &index) == FAILURE){
1495 return;
1496 }
1497
1498 ZEND_FETCH_RESOURCE(gmpnum_a, mpz_t *, a_arg, -1, GMP_RESOURCE_NAME, le_gmp);
1499
1500 if (index < 0) {
1501 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero");
1502 return;
1503 }
1504
1505 mpz_clrbit(*gmpnum_a, index);
1506 }
1507 /* }}} */
1508
1509 /* {{{ proto bool gmp_testbit(resource a, int index)
1510 Tests if bit is set in a */
1511 ZEND_FUNCTION(gmp_testbit)
1512 {
1513 zval **a_arg;
1514 long index;
1515 mpz_t *gmpnum_a;
1516
1517 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &index) == FAILURE){
1518 return;
1519 }
1520
1521 ZEND_FETCH_RESOURCE(gmpnum_a, mpz_t *, a_arg, -1, GMP_RESOURCE_NAME, le_gmp);
1522
1523 if (index < 0) {
1524 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero");
1525 RETURN_FALSE;
1526 }
1527
1528 if (mpz_tstbit(*gmpnum_a, index)) {
1529 RETURN_TRUE;
1530 }
1531 RETURN_FALSE;
1532 }
1533 /* }}} */
1534
1535 /* {{{ proto int gmp_popcount(resource a)
1536 Calculates the population count of a */
1537 ZEND_FUNCTION(gmp_popcount)
1538 {
1539 zval **a_arg;
1540 mpz_t *gmpnum_a;
1541 int temp_a;
1542
1543 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
1544 return;
1545 }
1546
1547 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1548
1549 RETVAL_LONG(mpz_popcount(*gmpnum_a));
1550 FREE_GMP_TEMP(temp_a);
1551 }
1552 /* }}} */
1553
1554 /* {{{ proto int gmp_hamdist(resource a, resource b)
1555 Calculates hamming distance between a and b */
1556 ZEND_FUNCTION(gmp_hamdist)
1557 {
1558 zval **a_arg, **b_arg;
1559 mpz_t *gmpnum_a, *gmpnum_b;
1560 int temp_a, temp_b;
1561
1562 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
1563 return;
1564 }
1565
1566 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1567 FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b);
1568
1569 RETVAL_LONG(mpz_hamdist(*gmpnum_a, *gmpnum_b));
1570 FREE_GMP_TEMP(temp_a);
1571 FREE_GMP_TEMP(temp_b);
1572 }
1573 /* }}} */
1574
1575 /* {{{ proto int gmp_scan0(resource a, int start)
1576 Finds first zero bit */
1577 ZEND_FUNCTION(gmp_scan0)
1578 {
1579 zval **a_arg;
1580 mpz_t *gmpnum_a;
1581 int temp_a;
1582 long start;
1583
1584 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &start) == FAILURE){
1585 return;
1586 }
1587
1588 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1589
1590 if (start < 0) {
1591 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Starting index must be greater than or equal to zero");
1592 RETURN_FALSE;
1593 }
1594
1595 RETVAL_LONG(mpz_scan0(*gmpnum_a, start));
1596 FREE_GMP_TEMP(temp_a);
1597 }
1598 /* }}} */
1599
1600 /* {{{ proto int gmp_scan1(resource a, int start)
1601 Finds first non-zero bit */
1602 ZEND_FUNCTION(gmp_scan1)
1603 {
1604 zval **a_arg;
1605 mpz_t *gmpnum_a;
1606 int temp_a;
1607 long start;
1608
1609 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &start) == FAILURE){
1610 return;
1611 }
1612
1613 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1614 if (start < 0) {
1615 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Starting index must be greater than or equal to zero");
1616 RETURN_FALSE;
1617 }
1618
1619 RETVAL_LONG(mpz_scan1(*gmpnum_a, start));
1620 FREE_GMP_TEMP(temp_a);
1621 }
1622 /* }}} */
1623
1624 /* {{{ _php_gmpnum_free
1625 */
1626 static void _php_gmpnum_free(zend_rsrc_list_entry *rsrc TSRMLS_DC)
1627 {
1628 mpz_t *gmpnum = (mpz_t *)rsrc->ptr;
1629
1630 FREE_GMP_NUM(gmpnum);
1631 }
1632 /* }}} */
1633
1634 #endif /* HAVE_GMP */
1635
1636 /*
1637 * Local variables:
1638 * tab-width: 4
1639 * c-basic-offset: 4
1640 * End:
1641 * vim600: noet sw=4 ts=4 fdm=marker
1642 * vim<600: noet sw=4 ts=4
1643 */
1644