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