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