This source file includes following definitions.
- ZEND_TSRMLS_CACHE_DEFINE
- gmp_free_object_storage
- gmp_create_object_ex
- gmp_create_object
- gmp_create
- gmp_cast_object
- gmp_get_debug_info
- gmp_clone_obj
- shift_operator_helper
- gmp_do_operation_ex
- gmp_do_operation
- gmp_compare
- gmp_serialize
- gmp_unserialize
- ZEND_GINIT_FUNCTION
- ZEND_MINIT_FUNCTION
- ZEND_MODULE_DEACTIVATE_D
- ZEND_MODULE_INFO_D
- convert_to_gmp
- gmp_strval
- gmp_cmp
- gmp_zval_binary_ui_op
- gmp_zval_binary_ui_op2
- _gmp_binary_ui_op
- gmp_zval_unary_op
- gmp_zval_unary_ui_op
- _gmp_unary_ui_op
- _gmp_unary_op
- _gmp_unary_opl
- _gmp_binary_opl
- ZEND_FUNCTION
- gmp_import_export_validate
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- gmp_init_random
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
- ZEND_FUNCTION
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 #include "ext/standard/php_var.h"
28 #include "zend_smart_str_public.h"
29 #include "zend_exceptions.h"
30
31 #if HAVE_GMP
32
33 #include <gmp.h>
34
35
36 #include "ext/standard/php_rand.h"
37 #include "ext/standard/php_lcg.h"
38 #define GMP_ABS(x) ((x) >= 0 ? (x) : -(x))
39
40
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_EX(arginfo_gmp_import, 0, 0, 1)
47 ZEND_ARG_INFO(0, data)
48 ZEND_ARG_INFO(0, word_size)
49 ZEND_ARG_INFO(0, options)
50 ZEND_END_ARG_INFO()
51
52 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_export, 0, 0, 1)
53 ZEND_ARG_INFO(0, gmpnumber)
54 ZEND_ARG_INFO(0, word_size)
55 ZEND_ARG_INFO(0, options)
56 ZEND_END_ARG_INFO()
57
58 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_intval, 0, 0, 1)
59 ZEND_ARG_INFO(0, gmpnumber)
60 ZEND_END_ARG_INFO()
61
62 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_strval, 0, 0, 1)
63 ZEND_ARG_INFO(0, gmpnumber)
64 ZEND_ARG_INFO(0, base)
65 ZEND_END_ARG_INFO()
66
67 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_unary, 0, 0, 1)
68 ZEND_ARG_INFO(0, a)
69 ZEND_END_ARG_INFO()
70
71 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_binary, 0, 0, 2)
72 ZEND_ARG_INFO(0, a)
73 ZEND_ARG_INFO(0, b)
74 ZEND_END_ARG_INFO()
75
76 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_div, 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_pow, 0, 0, 2)
83 ZEND_ARG_INFO(0, base)
84 ZEND_ARG_INFO(0, exp)
85 ZEND_END_ARG_INFO()
86
87 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_powm, 0, 0, 3)
88 ZEND_ARG_INFO(0, base)
89 ZEND_ARG_INFO(0, exp)
90 ZEND_ARG_INFO(0, mod)
91 ZEND_END_ARG_INFO()
92
93 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_root, 0, 0, 2)
94 ZEND_ARG_INFO(0, a)
95 ZEND_ARG_INFO(0, nth)
96 ZEND_END_ARG_INFO()
97
98 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_prob_prime, 0, 0, 1)
99 ZEND_ARG_INFO(0, a)
100 ZEND_ARG_INFO(0, reps)
101 ZEND_END_ARG_INFO()
102
103 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_random, 0, 0, 0)
104 ZEND_ARG_INFO(0, limiter)
105 ZEND_END_ARG_INFO()
106
107 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_random_seed, 0, 0, 1)
108 ZEND_ARG_INFO(0, seed)
109 ZEND_END_ARG_INFO()
110
111 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_random_bits, 0, 0, 1)
112 ZEND_ARG_INFO(0, bits)
113 ZEND_END_ARG_INFO()
114
115 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_random_range, 0, 0, 2)
116 ZEND_ARG_INFO(0, min)
117 ZEND_ARG_INFO(0, max)
118 ZEND_END_ARG_INFO()
119
120 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_setbit, 0, 0, 2)
121 ZEND_ARG_INFO(0, a)
122 ZEND_ARG_INFO(0, index)
123 ZEND_ARG_INFO(0, set_clear)
124 ZEND_END_ARG_INFO()
125
126 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_bit, 0, 0, 2)
127 ZEND_ARG_INFO(0, a)
128 ZEND_ARG_INFO(0, index)
129 ZEND_END_ARG_INFO()
130
131 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_scan, 0, 0, 2)
132 ZEND_ARG_INFO(0, a)
133 ZEND_ARG_INFO(0, start)
134 ZEND_END_ARG_INFO()
135
136
137
138 ZEND_DECLARE_MODULE_GLOBALS(gmp)
139 static ZEND_GINIT_FUNCTION(gmp);
140
141
142
143 const zend_function_entry gmp_functions[] = {
144 ZEND_FE(gmp_init, arginfo_gmp_init)
145 ZEND_FE(gmp_import, arginfo_gmp_import)
146 ZEND_FE(gmp_export, arginfo_gmp_export)
147 ZEND_FE(gmp_intval, arginfo_gmp_intval)
148 ZEND_FE(gmp_strval, arginfo_gmp_strval)
149 ZEND_FE(gmp_add, arginfo_gmp_binary)
150 ZEND_FE(gmp_sub, arginfo_gmp_binary)
151 ZEND_FE(gmp_mul, arginfo_gmp_binary)
152 ZEND_FE(gmp_div_qr, arginfo_gmp_div)
153 ZEND_FE(gmp_div_q, arginfo_gmp_div)
154 ZEND_FE(gmp_div_r, arginfo_gmp_div)
155 ZEND_FALIAS(gmp_div, gmp_div_q, arginfo_gmp_div)
156 ZEND_FE(gmp_mod, arginfo_gmp_binary)
157 ZEND_FE(gmp_divexact, arginfo_gmp_binary)
158 ZEND_FE(gmp_neg, arginfo_gmp_unary)
159 ZEND_FE(gmp_abs, arginfo_gmp_unary)
160 ZEND_FE(gmp_fact, arginfo_gmp_unary)
161 ZEND_FE(gmp_sqrt, arginfo_gmp_unary)
162 ZEND_FE(gmp_sqrtrem, arginfo_gmp_unary)
163 ZEND_FE(gmp_root, arginfo_gmp_root)
164 ZEND_FE(gmp_rootrem, arginfo_gmp_root)
165 ZEND_FE(gmp_pow, arginfo_gmp_pow)
166 ZEND_FE(gmp_powm, arginfo_gmp_powm)
167 ZEND_FE(gmp_perfect_square, arginfo_gmp_unary)
168 ZEND_FE(gmp_prob_prime, arginfo_gmp_prob_prime)
169 ZEND_FE(gmp_gcd, arginfo_gmp_binary)
170 ZEND_FE(gmp_gcdext, arginfo_gmp_binary)
171 ZEND_FE(gmp_invert, arginfo_gmp_binary)
172 ZEND_FE(gmp_jacobi, arginfo_gmp_binary)
173 ZEND_FE(gmp_legendre, arginfo_gmp_binary)
174 ZEND_FE(gmp_cmp, arginfo_gmp_binary)
175 ZEND_FE(gmp_sign, arginfo_gmp_unary)
176 ZEND_FE(gmp_random, arginfo_gmp_random)
177 ZEND_FE(gmp_random_seed, arginfo_gmp_random_seed)
178 ZEND_FE(gmp_random_bits, arginfo_gmp_random_bits)
179 ZEND_FE(gmp_random_range, arginfo_gmp_random_range)
180 ZEND_FE(gmp_and, arginfo_gmp_binary)
181 ZEND_FE(gmp_or, arginfo_gmp_binary)
182 ZEND_FE(gmp_com, arginfo_gmp_unary)
183 ZEND_FE(gmp_xor, arginfo_gmp_binary)
184 ZEND_FE(gmp_setbit, arginfo_gmp_setbit)
185 ZEND_FE(gmp_clrbit, arginfo_gmp_bit)
186 ZEND_FE(gmp_testbit, arginfo_gmp_bit)
187 ZEND_FE(gmp_scan0, arginfo_gmp_scan)
188 ZEND_FE(gmp_scan1, arginfo_gmp_scan)
189 ZEND_FE(gmp_popcount, arginfo_gmp_unary)
190 ZEND_FE(gmp_hamdist, arginfo_gmp_binary)
191 ZEND_FE(gmp_nextprime, arginfo_gmp_unary)
192 PHP_FE_END
193 };
194
195
196
197
198 zend_module_entry gmp_module_entry = {
199 STANDARD_MODULE_HEADER,
200 "gmp",
201 gmp_functions,
202 ZEND_MODULE_STARTUP_N(gmp),
203 NULL,
204 NULL,
205 ZEND_MODULE_DEACTIVATE_N(gmp),
206 ZEND_MODULE_INFO_N(gmp),
207 PHP_GMP_VERSION,
208 ZEND_MODULE_GLOBALS(gmp),
209 ZEND_GINIT(gmp),
210 NULL,
211 NULL,
212 STANDARD_MODULE_PROPERTIES_EX
213 };
214
215
216 #ifdef COMPILE_DL_GMP
217 #ifdef ZTS
218 ZEND_TSRMLS_CACHE_DEFINE()
219 #endif
220 ZEND_GET_MODULE(gmp)
221 #endif
222
223 zend_class_entry *gmp_ce;
224 static zend_object_handlers gmp_object_handlers;
225
226 typedef struct _gmp_object {
227 mpz_t num;
228 zend_object std;
229 } gmp_object;
230
231 typedef struct _gmp_temp {
232 mpz_t num;
233 zend_bool is_used;
234 } gmp_temp_t;
235
236 #define GMP_ROUND_ZERO 0
237 #define GMP_ROUND_PLUSINF 1
238 #define GMP_ROUND_MINUSINF 2
239
240 #define GMP_MSW_FIRST (1 << 0)
241 #define GMP_LSW_FIRST (1 << 1)
242 #define GMP_LITTLE_ENDIAN (1 << 2)
243 #define GMP_BIG_ENDIAN (1 << 3)
244 #define GMP_NATIVE_ENDIAN (1 << 4)
245
246 #define GMP_MAX_BASE 62
247
248 #define GMP_51_OR_NEWER \
249 ((__GNU_MP_VERSION >= 6) || (__GNU_MP_VERSION >= 5 && __GNU_MP_VERSION_MINOR >= 1))
250
251 #define IS_GMP(zval) \
252 (Z_TYPE_P(zval) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zval), gmp_ce))
253
254 #define GET_GMP_OBJECT_FROM_OBJ(obj) \
255 ((gmp_object *) ((char *) (obj) - XtOffsetOf(gmp_object, std)))
256 #define GET_GMP_OBJECT_FROM_ZVAL(zv) \
257 GET_GMP_OBJECT_FROM_OBJ(Z_OBJ_P(zv))
258
259 #define GET_GMP_FROM_ZVAL(zval) \
260 GET_GMP_OBJECT_FROM_OBJ(Z_OBJ_P(zval))->num
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281 #define FREE_GMP_TEMP(temp) \
282 if (temp.is_used) { \
283 mpz_clear(temp.num); \
284 }
285
286 #define FETCH_GMP_ZVAL_DEP_DEP(gmpnumber, zval, temp, dep1, dep2) \
287 if (IS_GMP(zval)) { \
288 gmpnumber = GET_GMP_FROM_ZVAL(zval); \
289 temp.is_used = 0; \
290 } else { \
291 mpz_init(temp.num); \
292 if (convert_to_gmp(temp.num, zval, 0) == FAILURE) { \
293 mpz_clear(temp.num); \
294 FREE_GMP_TEMP(dep1); \
295 FREE_GMP_TEMP(dep2); \
296 RETURN_FALSE; \
297 } \
298 temp.is_used = 1; \
299 gmpnumber = temp.num; \
300 }
301
302 #define FETCH_GMP_ZVAL_DEP(gmpnumber, zval, temp, dep) \
303 if (IS_GMP(zval)) { \
304 gmpnumber = GET_GMP_FROM_ZVAL(zval); \
305 temp.is_used = 0; \
306 } else { \
307 mpz_init(temp.num); \
308 if (convert_to_gmp(temp.num, zval, 0) == FAILURE) { \
309 mpz_clear(temp.num); \
310 FREE_GMP_TEMP(dep); \
311 RETURN_FALSE; \
312 } \
313 temp.is_used = 1; \
314 gmpnumber = temp.num; \
315 }
316
317 #define FETCH_GMP_ZVAL(gmpnumber, zval, temp) \
318 if (IS_GMP(zval)) { \
319 gmpnumber = GET_GMP_FROM_ZVAL(zval); \
320 temp.is_used = 0; \
321 } else { \
322 mpz_init(temp.num); \
323 if (convert_to_gmp(temp.num, zval, 0) == FAILURE) { \
324 mpz_clear(temp.num); \
325 RETURN_FALSE; \
326 } \
327 temp.is_used = 1; \
328 gmpnumber = temp.num; \
329 }
330
331 #define INIT_GMP_RETVAL(gmpnumber) \
332 gmp_create(return_value, &gmpnumber)
333
334 static void gmp_strval(zval *result, mpz_t gmpnum, int base);
335 static int convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base);
336 static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg);
337
338
339
340
341
342
343
344 typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr);
345 typedef int (*gmp_unary_opl_t)(mpz_srcptr);
346
347 typedef void (*gmp_unary_ui_op_t)(mpz_ptr, gmp_ulong);
348
349 typedef void (*gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr);
350 typedef int (*gmp_binary_opl_t)(mpz_srcptr, mpz_srcptr);
351
352 typedef void (*gmp_binary_ui_op_t)(mpz_ptr, mpz_srcptr, gmp_ulong);
353 typedef void (*gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
354 typedef void (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, gmp_ulong);
355
356 static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero);
357 static inline void gmp_zval_binary_ui_op2(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int check_b_zero);
358 static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_op_t gmp_op);
359 static inline void gmp_zval_unary_ui_op(zval *return_value, zval *a_arg, gmp_unary_ui_op_t gmp_op);
360
361
362 #define gmp_binary_ui_op(op, uop) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop, 0)
363 #define gmp_binary_op(op) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, NULL, 0)
364 #define gmp_binary_opl(op) _gmp_binary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
365 #define gmp_binary_ui_op_no_zero(op, uop) \
366 _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop, 1)
367
368
369 #define gmp_unary_op(op) _gmp_unary_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
370 #define gmp_unary_opl(op) _gmp_unary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
371 #define gmp_unary_ui_op(op) _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
372
373 static void gmp_free_object_storage(zend_object *obj)
374 {
375 gmp_object *intern = GET_GMP_OBJECT_FROM_OBJ(obj);
376
377 mpz_clear(intern->num);
378 zend_object_std_dtor(&intern->std);
379 }
380
381
382 static inline zend_object *gmp_create_object_ex(zend_class_entry *ce, mpz_ptr *gmpnum_target)
383 {
384 gmp_object *intern = emalloc(sizeof(gmp_object) + zend_object_properties_size(ce));
385
386 zend_object_std_init(&intern->std, ce);
387 object_properties_init(&intern->std, ce);
388
389 mpz_init(intern->num);
390 *gmpnum_target = intern->num;
391 intern->std.handlers = &gmp_object_handlers;
392
393 return &intern->std;
394 }
395
396
397 static zend_object *gmp_create_object(zend_class_entry *ce)
398 {
399 mpz_ptr gmpnum_dummy;
400 return gmp_create_object_ex(ce, &gmpnum_dummy);
401 }
402
403
404 static inline void gmp_create(zval *target, mpz_ptr *gmpnum_target)
405 {
406 ZVAL_OBJ(target, gmp_create_object_ex(gmp_ce, gmpnum_target));
407 }
408
409
410 static int gmp_cast_object(zval *readobj, zval *writeobj, int type)
411 {
412 mpz_ptr gmpnum;
413 switch (type) {
414 case IS_STRING:
415 gmpnum = GET_GMP_FROM_ZVAL(readobj);
416 gmp_strval(writeobj, gmpnum, 10);
417 return SUCCESS;
418 case IS_LONG:
419 gmpnum = GET_GMP_FROM_ZVAL(readobj);
420 ZVAL_LONG(writeobj, mpz_get_si(gmpnum));
421 return SUCCESS;
422 case IS_DOUBLE:
423 gmpnum = GET_GMP_FROM_ZVAL(readobj);
424 ZVAL_DOUBLE(writeobj, mpz_get_d(gmpnum));
425 return SUCCESS;
426 default:
427 return FAILURE;
428 }
429 }
430
431
432 static HashTable *gmp_get_debug_info(zval *obj, int *is_temp)
433 {
434 HashTable *ht, *props = zend_std_get_properties(obj);
435 mpz_ptr gmpnum = GET_GMP_FROM_ZVAL(obj);
436 zval zv;
437
438 *is_temp = 1;
439 ht = zend_array_dup(props);
440
441 gmp_strval(&zv, gmpnum, 10);
442 zend_hash_str_update(ht, "num", sizeof("num")-1, &zv);
443
444 return ht;
445 }
446
447
448 static zend_object *gmp_clone_obj(zval *obj)
449 {
450 gmp_object *old_object = GET_GMP_OBJECT_FROM_ZVAL(obj);
451 gmp_object *new_object = GET_GMP_OBJECT_FROM_OBJ(gmp_create_object(Z_OBJCE_P(obj)));
452
453 zend_objects_clone_members( &new_object->std, &old_object->std);
454
455 mpz_set(new_object->num, old_object->num);
456
457 return &new_object->std;
458 }
459
460
461 static void shift_operator_helper(gmp_binary_ui_op_t op, zval *return_value, zval *op1, zval *op2) {
462 zend_long shift = zval_get_long(op2);
463
464 if (shift < 0) {
465 php_error_docref(NULL, E_WARNING, "Shift cannot be negative");
466 RETVAL_FALSE;
467 } else {
468 mpz_ptr gmpnum_op, gmpnum_result;
469 gmp_temp_t temp;
470
471 FETCH_GMP_ZVAL(gmpnum_op, op1, temp);
472 INIT_GMP_RETVAL(gmpnum_result);
473 op(gmpnum_result, gmpnum_op, (gmp_ulong) shift);
474 FREE_GMP_TEMP(temp);
475 }
476 }
477
478 #define DO_BINARY_UI_OP_EX(op, uop, check_b_zero) \
479 gmp_zval_binary_ui_op( \
480 result, op1, op2, op, (gmp_binary_ui_op_t) uop, \
481 check_b_zero \
482 ); \
483 return SUCCESS;
484
485 #define DO_BINARY_UI_OP(op) DO_BINARY_UI_OP_EX(op, op ## _ui, 0)
486 #define DO_BINARY_OP(op) DO_BINARY_UI_OP_EX(op, NULL, 0)
487
488 #define DO_UNARY_OP(op) \
489 gmp_zval_unary_op(result, op1, op); \
490 return SUCCESS;
491
492 static int gmp_do_operation_ex(zend_uchar opcode, zval *result, zval *op1, zval *op2)
493 {
494 switch (opcode) {
495 case ZEND_ADD:
496 DO_BINARY_UI_OP(mpz_add);
497 case ZEND_SUB:
498 DO_BINARY_UI_OP(mpz_sub);
499 case ZEND_MUL:
500 DO_BINARY_UI_OP(mpz_mul);
501 case ZEND_POW:
502 shift_operator_helper(mpz_pow_ui, result, op1, op2);
503 return SUCCESS;
504 case ZEND_DIV:
505 DO_BINARY_UI_OP_EX(mpz_tdiv_q, mpz_tdiv_q_ui, 1);
506 case ZEND_MOD:
507 DO_BINARY_UI_OP_EX(mpz_mod, mpz_mod_ui, 1);
508 case ZEND_SL:
509 shift_operator_helper(mpz_mul_2exp, result, op1, op2);
510 return SUCCESS;
511 case ZEND_SR:
512 shift_operator_helper(mpz_fdiv_q_2exp, result, op1, op2);
513 return SUCCESS;
514 case ZEND_BW_OR:
515 DO_BINARY_OP(mpz_ior);
516 case ZEND_BW_AND:
517 DO_BINARY_OP(mpz_and);
518 case ZEND_BW_XOR:
519 DO_BINARY_OP(mpz_xor);
520 case ZEND_BW_NOT:
521 DO_UNARY_OP(mpz_com);
522
523 default:
524 return FAILURE;
525 }
526 }
527
528
529 static int gmp_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op2)
530 {
531 zval op1_copy;
532 int retval;
533
534 if (result == op1) {
535 ZVAL_COPY_VALUE(&op1_copy, op1);
536 op1 = &op1_copy;
537 }
538
539 retval = gmp_do_operation_ex(opcode, result, op1, op2);
540
541 if (retval == SUCCESS && op1 == &op1_copy) {
542 zval_dtor(op1);
543 }
544
545 return retval;
546 }
547
548
549 static int gmp_compare(zval *result, zval *op1, zval *op2)
550 {
551 gmp_cmp(result, op1, op2);
552 if (Z_TYPE_P(result) == IS_FALSE) {
553 ZVAL_LONG(result, 1);
554 }
555 return SUCCESS;
556 }
557
558
559 static int gmp_serialize(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data)
560 {
561 mpz_ptr gmpnum = GET_GMP_FROM_ZVAL(object);
562 smart_str buf = {0};
563 zval zv;
564 php_serialize_data_t serialize_data = (php_serialize_data_t) data;
565
566 PHP_VAR_SERIALIZE_INIT(serialize_data);
567
568 gmp_strval(&zv, gmpnum, 10);
569 php_var_serialize(&buf, &zv, &serialize_data);
570 zval_dtor(&zv);
571
572 ZVAL_ARR(&zv, zend_std_get_properties(object));
573 php_var_serialize(&buf, &zv, &serialize_data);
574
575 PHP_VAR_SERIALIZE_DESTROY(serialize_data);
576 *buffer = (unsigned char *) estrndup(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s));
577 *buf_len = ZSTR_LEN(buf.s);
578 zend_string_release(buf.s);
579
580 return SUCCESS;
581 }
582
583
584 static int gmp_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data)
585 {
586 mpz_ptr gmpnum;
587 const unsigned char *p, *max;
588 zval *zv;
589 int retval = FAILURE;
590 php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data;
591
592 PHP_VAR_UNSERIALIZE_INIT(unserialize_data);
593 gmp_create(object, &gmpnum);
594
595 p = buf;
596 max = buf + buf_len;
597
598 zv = var_tmp_var(&unserialize_data);
599 if (!php_var_unserialize(zv, &p, max, &unserialize_data)
600 || Z_TYPE_P(zv) != IS_STRING
601 || convert_to_gmp(gmpnum, zv, 10) == FAILURE
602 ) {
603 zend_throw_exception(NULL, "Could not unserialize number", 0);
604 goto exit;
605 }
606
607 zv = var_tmp_var(&unserialize_data);
608 if (!php_var_unserialize(zv, &p, max, &unserialize_data)
609 || Z_TYPE_P(zv) != IS_ARRAY
610 ) {
611 zend_throw_exception(NULL, "Could not unserialize properties", 0);
612 goto exit;
613 }
614
615 if (zend_hash_num_elements(Z_ARRVAL_P(zv)) != 0) {
616 zend_hash_copy(
617 zend_std_get_properties(object), Z_ARRVAL_P(zv),
618 (copy_ctor_func_t) zval_add_ref
619 );
620 }
621
622 retval = SUCCESS;
623 exit:
624 PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
625 return retval;
626 }
627
628
629
630
631 static ZEND_GINIT_FUNCTION(gmp)
632 {
633 #if defined(COMPILE_DL_GMP) && defined(ZTS)
634 ZEND_TSRMLS_CACHE_UPDATE();
635 #endif
636 gmp_globals->rand_initialized = 0;
637 }
638
639
640
641
642 ZEND_MINIT_FUNCTION(gmp)
643 {
644 zend_class_entry tmp_ce;
645 INIT_CLASS_ENTRY(tmp_ce, "GMP", NULL);
646 gmp_ce = zend_register_internal_class(&tmp_ce);
647 gmp_ce->create_object = gmp_create_object;
648 gmp_ce->serialize = gmp_serialize;
649 gmp_ce->unserialize = gmp_unserialize;
650
651 memcpy(&gmp_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
652 gmp_object_handlers.offset = XtOffsetOf(gmp_object, std);
653 gmp_object_handlers.free_obj = gmp_free_object_storage;
654 gmp_object_handlers.cast_object = gmp_cast_object;
655 gmp_object_handlers.get_debug_info = gmp_get_debug_info;
656 gmp_object_handlers.clone_obj = gmp_clone_obj;
657 gmp_object_handlers.do_operation = gmp_do_operation;
658 gmp_object_handlers.compare = gmp_compare;
659
660 REGISTER_LONG_CONSTANT("GMP_ROUND_ZERO", GMP_ROUND_ZERO, CONST_CS | CONST_PERSISTENT);
661 REGISTER_LONG_CONSTANT("GMP_ROUND_PLUSINF", GMP_ROUND_PLUSINF, CONST_CS | CONST_PERSISTENT);
662 REGISTER_LONG_CONSTANT("GMP_ROUND_MINUSINF", GMP_ROUND_MINUSINF, CONST_CS | CONST_PERSISTENT);
663 #ifdef mpir_version
664 REGISTER_STRING_CONSTANT("GMP_MPIR_VERSION", (char *)mpir_version, CONST_CS | CONST_PERSISTENT);
665 #endif
666 REGISTER_STRING_CONSTANT("GMP_VERSION", (char *)gmp_version, CONST_CS | CONST_PERSISTENT);
667
668 REGISTER_LONG_CONSTANT("GMP_MSW_FIRST", GMP_MSW_FIRST, CONST_CS | CONST_PERSISTENT);
669 REGISTER_LONG_CONSTANT("GMP_LSW_FIRST", GMP_LSW_FIRST, CONST_CS | CONST_PERSISTENT);
670 REGISTER_LONG_CONSTANT("GMP_LITTLE_ENDIAN", GMP_LITTLE_ENDIAN, CONST_CS | CONST_PERSISTENT);
671 REGISTER_LONG_CONSTANT("GMP_BIG_ENDIAN", GMP_BIG_ENDIAN, CONST_CS | CONST_PERSISTENT);
672 REGISTER_LONG_CONSTANT("GMP_NATIVE_ENDIAN", GMP_NATIVE_ENDIAN, CONST_CS | CONST_PERSISTENT);
673
674 return SUCCESS;
675 }
676
677
678
679
680 ZEND_MODULE_DEACTIVATE_D(gmp)
681 {
682 if (GMPG(rand_initialized)) {
683 gmp_randclear(GMPG(rand_state));
684 GMPG(rand_initialized) = 0;
685 }
686
687 return SUCCESS;
688 }
689
690
691
692
693 ZEND_MODULE_INFO_D(gmp)
694 {
695 php_info_print_table_start();
696 php_info_print_table_row(2, "gmp support", "enabled");
697 #ifdef mpir_version
698 php_info_print_table_row(2, "MPIR version", mpir_version);
699 #else
700 php_info_print_table_row(2, "GMP version", gmp_version);
701 #endif
702 php_info_print_table_end();
703 }
704
705
706
707
708
709 static int convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base)
710 {
711 switch (Z_TYPE_P(val)) {
712 case IS_LONG:
713 case IS_FALSE:
714 case IS_TRUE: {
715 mpz_set_si(gmpnumber, zval_get_long(val));
716 return SUCCESS;
717 }
718 case IS_STRING: {
719 char *numstr = Z_STRVAL_P(val);
720 zend_bool skip_lead = 0;
721 int ret;
722
723 if (Z_STRLEN_P(val) > 2 && numstr[0] == '0') {
724 if ((base == 0 || base == 16) && (numstr[1] == 'x' || numstr[1] == 'X')) {
725 base = 16;
726 skip_lead = 1;
727 } else if ((base == 0 || base == 2) && (numstr[1] == 'b' || numstr[1] == 'B')) {
728 base = 2;
729 skip_lead = 1;
730 }
731 }
732
733 ret = mpz_set_str(gmpnumber, (skip_lead ? &numstr[2] : numstr), (int) base);
734 if (-1 == ret) {
735 php_error_docref(NULL, E_WARNING,
736 "Unable to convert variable to GMP - string is not an integer");
737 return FAILURE;
738 }
739
740 return SUCCESS;
741 }
742 default:
743 php_error_docref(NULL, E_WARNING,
744 "Unable to convert variable to GMP - wrong type");
745 return FAILURE;
746 }
747 }
748
749
750 static void gmp_strval(zval *result, mpz_t gmpnum, int base)
751 {
752 size_t num_len;
753 zend_string *str;
754
755 num_len = mpz_sizeinbase(gmpnum, abs(base));
756 if (mpz_sgn(gmpnum) < 0) {
757 num_len++;
758 }
759
760 str = zend_string_alloc(num_len, 0);
761 mpz_get_str(ZSTR_VAL(str), base, gmpnum);
762
763
764
765
766
767
768
769
770
771 if (ZSTR_VAL(str)[ZSTR_LEN(str) - 1] == '\0') {
772 ZSTR_LEN(str)--;
773 } else {
774 ZSTR_VAL(str)[ZSTR_LEN(str)] = '\0';
775 }
776
777 ZVAL_NEW_STR(result, str);
778 }
779
780
781 static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg)
782 {
783 mpz_ptr gmpnum_a, gmpnum_b;
784 gmp_temp_t temp_a, temp_b;
785 zend_bool use_si = 0;
786 zend_long res;
787
788 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
789
790 if (Z_TYPE_P(b_arg) == IS_LONG) {
791 use_si = 1;
792 temp_b.is_used = 0;
793 } else {
794 FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
795 }
796
797 if (use_si) {
798 res = mpz_cmp_si(gmpnum_a, Z_LVAL_P(b_arg));
799 } else {
800 res = mpz_cmp(gmpnum_a, gmpnum_b);
801 }
802
803 FREE_GMP_TEMP(temp_a);
804 FREE_GMP_TEMP(temp_b);
805
806 RETURN_LONG(res);
807 }
808
809
810
811
812
813 static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero)
814 {
815 mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result;
816 int use_ui = 0;
817 gmp_temp_t temp_a, temp_b;
818
819 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
820
821 if (gmp_ui_op && Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) >= 0) {
822 use_ui = 1;
823 temp_b.is_used = 0;
824 } else {
825 FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
826 }
827
828 if (check_b_zero) {
829 int b_is_zero = 0;
830 if (use_ui) {
831 b_is_zero = (Z_LVAL_P(b_arg) == 0);
832 } else {
833 b_is_zero = !mpz_cmp_ui(gmpnum_b, 0);
834 }
835
836 if (b_is_zero) {
837 php_error_docref(NULL, E_WARNING, "Zero operand not allowed");
838 FREE_GMP_TEMP(temp_a);
839 FREE_GMP_TEMP(temp_b);
840 RETURN_FALSE;
841 }
842 }
843
844 INIT_GMP_RETVAL(gmpnum_result);
845
846 if (use_ui) {
847 gmp_ui_op(gmpnum_result, gmpnum_a, (gmp_ulong) Z_LVAL_P(b_arg));
848 } else {
849 gmp_op(gmpnum_result, gmpnum_a, gmpnum_b);
850 }
851
852 FREE_GMP_TEMP(temp_a);
853 FREE_GMP_TEMP(temp_b);
854 }
855
856
857
858
859
860 static inline void gmp_zval_binary_ui_op2(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int check_b_zero)
861 {
862 mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result1, gmpnum_result2;
863 int use_ui = 0;
864 gmp_temp_t temp_a, temp_b;
865 zval result1, result2;
866
867 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
868
869 if (gmp_ui_op && Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) >= 0) {
870
871 use_ui = 1;
872 temp_b.is_used = 0;
873 } else {
874 FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
875 }
876
877 if (check_b_zero) {
878 int b_is_zero = 0;
879 if (use_ui) {
880 b_is_zero = (Z_LVAL_P(b_arg) == 0);
881 } else {
882 b_is_zero = !mpz_cmp_ui(gmpnum_b, 0);
883 }
884
885 if (b_is_zero) {
886 php_error_docref(NULL, E_WARNING, "Zero operand not allowed");
887 FREE_GMP_TEMP(temp_a);
888 FREE_GMP_TEMP(temp_b);
889 RETURN_FALSE;
890 }
891 }
892
893 gmp_create(&result1, &gmpnum_result1);
894 gmp_create(&result2, &gmpnum_result2);
895
896 array_init(return_value);
897 add_next_index_zval(return_value, &result1);
898 add_next_index_zval(return_value, &result2);
899
900 if (use_ui) {
901 gmp_ui_op(gmpnum_result1, gmpnum_result2, gmpnum_a, (gmp_ulong) Z_LVAL_P(b_arg));
902 } else {
903 gmp_op(gmpnum_result1, gmpnum_result2, gmpnum_a, gmpnum_b);
904 }
905
906 FREE_GMP_TEMP(temp_a);
907 FREE_GMP_TEMP(temp_b);
908 }
909
910
911
912
913 static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero)
914 {
915 zval *a_arg, *b_arg;
916
917 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
918 return;
919 }
920
921 gmp_zval_binary_ui_op(return_value, a_arg, b_arg, gmp_op, gmp_ui_op, check_b_zero);
922 }
923
924
925
926
927
928
929 static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_op_t gmp_op)
930 {
931 mpz_ptr gmpnum_a, gmpnum_result;
932 gmp_temp_t temp_a;
933
934 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
935
936 INIT_GMP_RETVAL(gmpnum_result);
937 gmp_op(gmpnum_result, gmpnum_a);
938
939 FREE_GMP_TEMP(temp_a);
940 }
941
942
943
944
945 static inline void gmp_zval_unary_ui_op(zval *return_value, zval *a_arg, gmp_unary_ui_op_t gmp_op)
946 {
947 mpz_ptr gmpnum_result;
948
949 INIT_GMP_RETVAL(gmpnum_result);
950 gmp_op(gmpnum_result, zval_get_long(a_arg));
951 }
952
953
954
955
956
957 static inline void _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_ui_op_t gmp_op)
958 {
959 zval *a_arg;
960
961 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
962 return;
963 }
964
965 gmp_zval_unary_ui_op(return_value, a_arg, gmp_op);
966 }
967
968
969
970
971 static inline void _gmp_unary_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_op_t gmp_op)
972 {
973 zval *a_arg;
974
975 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
976 return;
977 }
978
979 gmp_zval_unary_op(return_value, a_arg, gmp_op);
980 }
981
982
983
984
985 static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t gmp_op)
986 {
987 zval *a_arg;
988 mpz_ptr gmpnum_a;
989 gmp_temp_t temp_a;
990
991 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
992 return;
993 }
994
995 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
996 RETVAL_LONG(gmp_op(gmpnum_a));
997 FREE_GMP_TEMP(temp_a);
998 }
999
1000
1001
1002
1003 static inline void _gmp_binary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_opl_t gmp_op)
1004 {
1005 zval *a_arg, *b_arg;
1006 mpz_ptr gmpnum_a, gmpnum_b;
1007 gmp_temp_t temp_a, temp_b;
1008
1009 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
1010 return;
1011 }
1012
1013 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1014 FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
1015
1016 RETVAL_LONG(gmp_op(gmpnum_a, gmpnum_b));
1017
1018 FREE_GMP_TEMP(temp_a);
1019 FREE_GMP_TEMP(temp_b);
1020 }
1021
1022
1023
1024
1025 ZEND_FUNCTION(gmp_init)
1026 {
1027 zval *number_arg;
1028 mpz_ptr gmpnumber;
1029 zend_long base = 0;
1030
1031 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &number_arg, &base) == FAILURE) {
1032 return;
1033 }
1034
1035 if (base && (base < 2 || base > GMP_MAX_BASE)) {
1036 php_error_docref(NULL, E_WARNING, "Bad base for conversion: %pd (should be between 2 and %d)", base, GMP_MAX_BASE);
1037 RETURN_FALSE;
1038 }
1039
1040 INIT_GMP_RETVAL(gmpnumber);
1041 if (convert_to_gmp(gmpnumber, number_arg, base) == FAILURE) {
1042 zval_dtor(return_value);
1043 RETURN_FALSE;
1044 }
1045 }
1046
1047
1048 int gmp_import_export_validate(zend_long size, zend_long options, int *order, int *endian)
1049 {
1050 if (size < 1) {
1051 php_error_docref(NULL, E_WARNING,
1052 "Word size must be positive, %pd given", size);
1053 return FAILURE;
1054 }
1055
1056 switch (options & (GMP_LSW_FIRST | GMP_MSW_FIRST)) {
1057 case GMP_LSW_FIRST:
1058 *order = -1;
1059 break;
1060 case GMP_MSW_FIRST:
1061 case 0:
1062 *order = 1;
1063 break;
1064 default:
1065 php_error_docref(NULL, E_WARNING,
1066 "Invalid options: Conflicting word orders");
1067 return FAILURE;
1068 }
1069
1070 switch (options & (GMP_LITTLE_ENDIAN | GMP_BIG_ENDIAN | GMP_NATIVE_ENDIAN)) {
1071 case GMP_LITTLE_ENDIAN:
1072 *endian = -1;
1073 break;
1074 case GMP_BIG_ENDIAN:
1075 *endian = 1;
1076 break;
1077 case GMP_NATIVE_ENDIAN:
1078 case 0:
1079 *endian = 0;
1080 break;
1081 default:
1082 php_error_docref(NULL, E_WARNING,
1083 "Invalid options: Conflicting word endianness");
1084 return FAILURE;
1085 }
1086
1087 return SUCCESS;
1088 }
1089
1090
1091
1092 ZEND_FUNCTION(gmp_import)
1093 {
1094 char *data;
1095 size_t data_len;
1096 zend_long size = 1;
1097 zend_long options = GMP_MSW_FIRST | GMP_NATIVE_ENDIAN;
1098 int order, endian;
1099 mpz_ptr gmpnumber;
1100
1101 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|ll", &data, &data_len, &size, &options) == FAILURE) {
1102 return;
1103 }
1104
1105 if (gmp_import_export_validate(size, options, &order, &endian) == FAILURE) {
1106 RETURN_FALSE;
1107 }
1108
1109 if ((data_len % size) != 0) {
1110 php_error_docref(NULL, E_WARNING,
1111 "Input length must be a multiple of word size");
1112 RETURN_FALSE;
1113 }
1114
1115 INIT_GMP_RETVAL(gmpnumber);
1116
1117 mpz_import(gmpnumber, data_len / size, order, size, endian, 0, data);
1118 }
1119
1120
1121
1122
1123 ZEND_FUNCTION(gmp_export)
1124 {
1125 zval *gmpnumber_arg;
1126 zend_long size = 1;
1127 zend_long options = GMP_MSW_FIRST | GMP_NATIVE_ENDIAN;
1128 int order, endian;
1129 mpz_ptr gmpnumber;
1130 gmp_temp_t temp_a;
1131
1132 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|ll", &gmpnumber_arg, &size, &options) == FAILURE) {
1133 return;
1134 }
1135
1136 if (gmp_import_export_validate(size, options, &order, &endian) == FAILURE) {
1137 RETURN_FALSE;
1138 }
1139
1140 FETCH_GMP_ZVAL(gmpnumber, gmpnumber_arg, temp_a);
1141
1142 if (mpz_sgn(gmpnumber) == 0) {
1143 RETURN_EMPTY_STRING();
1144 } else {
1145 size_t bits_per_word = size * 8;
1146 size_t count = (mpz_sizeinbase(gmpnumber, 2) + bits_per_word - 1) / bits_per_word;
1147 size_t out_len = count * size;
1148
1149 zend_string *out_string = zend_string_alloc(out_len, 0);
1150 mpz_export(ZSTR_VAL(out_string), NULL, order, size, endian, 0, gmpnumber);
1151 ZSTR_VAL(out_string)[out_len] = '\0';
1152
1153 RETURN_NEW_STR(out_string);
1154 }
1155
1156 FREE_GMP_TEMP(temp_a);
1157 }
1158
1159
1160
1161
1162 ZEND_FUNCTION(gmp_intval)
1163 {
1164 zval *gmpnumber_arg;
1165
1166 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &gmpnumber_arg) == FAILURE){
1167 return;
1168 }
1169
1170 if (IS_GMP(gmpnumber_arg)) {
1171 RETVAL_LONG(mpz_get_si(GET_GMP_FROM_ZVAL(gmpnumber_arg)));
1172 } else {
1173 RETVAL_LONG(zval_get_long(gmpnumber_arg));
1174 }
1175 }
1176
1177
1178
1179
1180 ZEND_FUNCTION(gmp_strval)
1181 {
1182 zval *gmpnumber_arg;
1183 zend_long base = 10;
1184 mpz_ptr gmpnum;
1185 gmp_temp_t temp_a;
1186
1187 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &gmpnumber_arg, &base) == FAILURE) {
1188 return;
1189 }
1190
1191
1192
1193 if ((base < 2 && base > -2) || base > GMP_MAX_BASE || base < -36) {
1194 php_error_docref(NULL, E_WARNING, "Bad base for conversion: %pd (should be between 2 and %d or -2 and -36)", base, GMP_MAX_BASE);
1195 RETURN_FALSE;
1196 }
1197
1198 FETCH_GMP_ZVAL(gmpnum, gmpnumber_arg, temp_a);
1199
1200 gmp_strval(return_value, gmpnum, (int)base);
1201
1202 FREE_GMP_TEMP(temp_a);
1203 }
1204
1205
1206
1207
1208 ZEND_FUNCTION(gmp_add)
1209 {
1210 gmp_binary_ui_op(mpz_add, mpz_add_ui);
1211 }
1212
1213
1214
1215
1216 ZEND_FUNCTION(gmp_sub)
1217 {
1218 gmp_binary_ui_op(mpz_sub, mpz_sub_ui);
1219 }
1220
1221
1222
1223
1224 ZEND_FUNCTION(gmp_mul)
1225 {
1226 gmp_binary_ui_op(mpz_mul, mpz_mul_ui);
1227 }
1228
1229
1230
1231
1232 ZEND_FUNCTION(gmp_div_qr)
1233 {
1234 zval *a_arg, *b_arg;
1235 zend_long round = GMP_ROUND_ZERO;
1236
1237 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|l", &a_arg, &b_arg, &round) == FAILURE) {
1238 return;
1239 }
1240
1241 switch (round) {
1242 case GMP_ROUND_ZERO:
1243 gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_tdiv_qr, (gmp_binary_ui_op2_t) mpz_tdiv_qr_ui, 1);
1244 break;
1245 case GMP_ROUND_PLUSINF:
1246 gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_cdiv_qr, (gmp_binary_ui_op2_t) mpz_cdiv_qr_ui, 1);
1247 break;
1248 case GMP_ROUND_MINUSINF:
1249 gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_fdiv_qr, (gmp_binary_ui_op2_t) mpz_fdiv_qr_ui, 1);
1250 break;
1251 default:
1252 php_error_docref(NULL, E_WARNING, "Invalid rounding mode");
1253 RETURN_FALSE;
1254 }
1255 }
1256
1257
1258
1259
1260 ZEND_FUNCTION(gmp_div_r)
1261 {
1262 zval *a_arg, *b_arg;
1263 zend_long round = GMP_ROUND_ZERO;
1264
1265 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|l", &a_arg, &b_arg, &round) == FAILURE) {
1266 return;
1267 }
1268
1269 switch (round) {
1270 case GMP_ROUND_ZERO:
1271 gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_tdiv_r, (gmp_binary_ui_op_t) mpz_tdiv_r_ui, 1);
1272 break;
1273 case GMP_ROUND_PLUSINF:
1274 gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_cdiv_r, (gmp_binary_ui_op_t) mpz_cdiv_r_ui, 1);
1275 break;
1276 case GMP_ROUND_MINUSINF:
1277 gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_fdiv_r, (gmp_binary_ui_op_t) mpz_fdiv_r_ui, 1);
1278 break;
1279 default:
1280 php_error_docref(NULL, E_WARNING, "Invalid rounding mode");
1281 RETURN_FALSE;
1282 }
1283 }
1284
1285
1286
1287
1288 ZEND_FUNCTION(gmp_div_q)
1289 {
1290 zval *a_arg, *b_arg;
1291 zend_long round = GMP_ROUND_ZERO;
1292
1293 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|l", &a_arg, &b_arg, &round) == FAILURE) {
1294 return;
1295 }
1296
1297 switch (round) {
1298 case GMP_ROUND_ZERO:
1299 gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_tdiv_q, (gmp_binary_ui_op_t) mpz_tdiv_q_ui, 1);
1300 break;
1301 case GMP_ROUND_PLUSINF:
1302 gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_cdiv_q, (gmp_binary_ui_op_t) mpz_cdiv_q_ui, 1);
1303 break;
1304 case GMP_ROUND_MINUSINF:
1305 gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_fdiv_q, (gmp_binary_ui_op_t) mpz_fdiv_q_ui, 1);
1306 break;
1307 default:
1308 php_error_docref(NULL, E_WARNING, "Invalid rounding mode");
1309 RETURN_FALSE;
1310 }
1311
1312 }
1313
1314
1315
1316
1317 ZEND_FUNCTION(gmp_mod)
1318 {
1319 gmp_binary_ui_op_no_zero(mpz_mod, (gmp_binary_ui_op_t) mpz_mod_ui);
1320 }
1321
1322
1323
1324
1325 ZEND_FUNCTION(gmp_divexact)
1326 {
1327 gmp_binary_ui_op_no_zero(mpz_divexact, NULL);
1328 }
1329
1330
1331
1332
1333 ZEND_FUNCTION(gmp_neg)
1334 {
1335 gmp_unary_op(mpz_neg);
1336 }
1337
1338
1339
1340
1341 ZEND_FUNCTION(gmp_abs)
1342 {
1343 gmp_unary_op(mpz_abs);
1344 }
1345
1346
1347
1348
1349 ZEND_FUNCTION(gmp_fact)
1350 {
1351 zval *a_arg;
1352
1353 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
1354 return;
1355 }
1356
1357 if (IS_GMP(a_arg)) {
1358 mpz_ptr gmpnum_tmp = GET_GMP_FROM_ZVAL(a_arg);
1359 if (mpz_sgn(gmpnum_tmp) < 0) {
1360 php_error_docref(NULL, E_WARNING, "Number has to be greater than or equal to 0");
1361 RETURN_FALSE;
1362 }
1363 } else {
1364 if (zval_get_long(a_arg) < 0) {
1365 php_error_docref(NULL, E_WARNING, "Number has to be greater than or equal to 0");
1366 RETURN_FALSE;
1367 }
1368 }
1369
1370 gmp_zval_unary_ui_op(return_value, a_arg, mpz_fac_ui);
1371 }
1372
1373
1374
1375
1376 ZEND_FUNCTION(gmp_pow)
1377 {
1378 zval *base_arg;
1379 mpz_ptr gmpnum_result, gmpnum_base;
1380 gmp_temp_t temp_base;
1381 zend_long exp;
1382
1383 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &base_arg, &exp) == FAILURE) {
1384 return;
1385 }
1386
1387 if (exp < 0) {
1388 php_error_docref(NULL, E_WARNING, "Negative exponent not supported");
1389 RETURN_FALSE;
1390 }
1391
1392 if (Z_TYPE_P(base_arg) == IS_LONG && Z_LVAL_P(base_arg) >= 0) {
1393 INIT_GMP_RETVAL(gmpnum_result);
1394 mpz_ui_pow_ui(gmpnum_result, Z_LVAL_P(base_arg), exp);
1395 } else {
1396 FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base);
1397 INIT_GMP_RETVAL(gmpnum_result);
1398 mpz_pow_ui(gmpnum_result, gmpnum_base, exp);
1399 FREE_GMP_TEMP(temp_base);
1400 }
1401 }
1402
1403
1404
1405
1406 ZEND_FUNCTION(gmp_powm)
1407 {
1408 zval *base_arg, *exp_arg, *mod_arg;
1409 mpz_ptr gmpnum_base, gmpnum_exp, gmpnum_mod, gmpnum_result;
1410 int use_ui = 0;
1411 gmp_temp_t temp_base, temp_exp, temp_mod;
1412
1413 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzz", &base_arg, &exp_arg, &mod_arg) == FAILURE){
1414 return;
1415 }
1416
1417 FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base);
1418
1419 if (Z_TYPE_P(exp_arg) == IS_LONG && Z_LVAL_P(exp_arg) >= 0) {
1420 use_ui = 1;
1421 temp_exp.is_used = 0;
1422 } else {
1423 FETCH_GMP_ZVAL_DEP(gmpnum_exp, exp_arg, temp_exp, temp_base);
1424 if (mpz_sgn(gmpnum_exp) < 0) {
1425 php_error_docref(NULL, E_WARNING, "Second parameter cannot be less than 0");
1426 FREE_GMP_TEMP(temp_base);
1427 FREE_GMP_TEMP(temp_exp);
1428 RETURN_FALSE;
1429 }
1430 }
1431 FETCH_GMP_ZVAL_DEP_DEP(gmpnum_mod, mod_arg, temp_mod, temp_exp, temp_base);
1432
1433 if (!mpz_cmp_ui(gmpnum_mod, 0)) {
1434 php_error_docref(NULL, E_WARNING, "Modulus may not be zero");
1435 FREE_GMP_TEMP(temp_base);
1436 FREE_GMP_TEMP(temp_exp);
1437 FREE_GMP_TEMP(temp_mod);
1438 RETURN_FALSE;
1439 }
1440
1441 INIT_GMP_RETVAL(gmpnum_result);
1442 if (use_ui) {
1443 mpz_powm_ui(gmpnum_result, gmpnum_base, (zend_ulong) Z_LVAL_P(exp_arg), gmpnum_mod);
1444 } else {
1445 mpz_powm(gmpnum_result, gmpnum_base, gmpnum_exp, gmpnum_mod);
1446 FREE_GMP_TEMP(temp_exp);
1447 }
1448
1449 FREE_GMP_TEMP(temp_base);
1450 FREE_GMP_TEMP(temp_mod);
1451 }
1452
1453
1454
1455
1456 ZEND_FUNCTION(gmp_sqrt)
1457 {
1458 zval *a_arg;
1459 mpz_ptr gmpnum_a, gmpnum_result;
1460 gmp_temp_t temp_a;
1461
1462 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
1463 return;
1464 }
1465
1466 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1467
1468 if (mpz_sgn(gmpnum_a) < 0) {
1469 php_error_docref(NULL, E_WARNING, "Number has to be greater than or equal to 0");
1470 FREE_GMP_TEMP(temp_a);
1471 RETURN_FALSE;
1472 }
1473
1474 INIT_GMP_RETVAL(gmpnum_result);
1475 mpz_sqrt(gmpnum_result, gmpnum_a);
1476 FREE_GMP_TEMP(temp_a);
1477 }
1478
1479
1480
1481
1482 ZEND_FUNCTION(gmp_sqrtrem)
1483 {
1484 zval *a_arg;
1485 mpz_ptr gmpnum_a, gmpnum_result1, gmpnum_result2;
1486 gmp_temp_t temp_a;
1487 zval result1, result2;
1488
1489 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
1490 return;
1491 }
1492
1493 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1494
1495 if (mpz_sgn(gmpnum_a) < 0) {
1496 php_error_docref(NULL, E_WARNING, "Number has to be greater than or equal to 0");
1497 FREE_GMP_TEMP(temp_a);
1498 RETURN_FALSE;
1499 }
1500
1501 gmp_create(&result1, &gmpnum_result1);
1502 gmp_create(&result2, &gmpnum_result2);
1503
1504 array_init(return_value);
1505 add_next_index_zval(return_value, &result1);
1506 add_next_index_zval(return_value, &result2);
1507
1508 mpz_sqrtrem(gmpnum_result1, gmpnum_result2, gmpnum_a);
1509 FREE_GMP_TEMP(temp_a);
1510 }
1511
1512
1513
1514
1515 ZEND_FUNCTION(gmp_root)
1516 {
1517 zval *a_arg;
1518 zend_long nth;
1519 mpz_ptr gmpnum_a, gmpnum_result;
1520 gmp_temp_t temp_a;
1521
1522 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &nth) == FAILURE) {
1523 return;
1524 }
1525
1526 if (nth <= 0) {
1527 php_error_docref(NULL, E_WARNING, "The root must be positive");
1528 RETURN_FALSE;
1529 }
1530
1531 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1532
1533 if (nth % 2 == 0 && mpz_sgn(gmpnum_a) < 0) {
1534 php_error_docref(NULL, E_WARNING, "Can't take even root of negative number");
1535 FREE_GMP_TEMP(temp_a);
1536 RETURN_FALSE;
1537 }
1538
1539 INIT_GMP_RETVAL(gmpnum_result);
1540 mpz_root(gmpnum_result, gmpnum_a, (gmp_ulong) nth);
1541 FREE_GMP_TEMP(temp_a);
1542 }
1543
1544
1545
1546
1547 ZEND_FUNCTION(gmp_rootrem)
1548 {
1549 zval *a_arg;
1550 zend_long nth;
1551 mpz_ptr gmpnum_a, gmpnum_result1, gmpnum_result2;
1552 gmp_temp_t temp_a;
1553 zval result1, result2;
1554
1555 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &nth) == FAILURE) {
1556 return;
1557 }
1558
1559 if (nth <= 0) {
1560 php_error_docref(NULL, E_WARNING, "The root must be positive");
1561 RETURN_FALSE;
1562 }
1563
1564 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1565
1566 if (nth % 2 == 0 && mpz_sgn(gmpnum_a) < 0) {
1567 php_error_docref(NULL, E_WARNING, "Can't take even root of negative number");
1568 FREE_GMP_TEMP(temp_a);
1569 RETURN_FALSE;
1570 }
1571
1572 gmp_create(&result1, &gmpnum_result1);
1573 gmp_create(&result2, &gmpnum_result2);
1574
1575 array_init(return_value);
1576 add_next_index_zval(return_value, &result1);
1577 add_next_index_zval(return_value, &result2);
1578
1579 #if GMP_51_OR_NEWER
1580
1581
1582 mpz_rootrem(gmpnum_result1, gmpnum_result2, gmpnum_a, (gmp_ulong) nth);
1583 #else
1584 mpz_root(gmpnum_result1, gmpnum_a, (gmp_ulong) nth);
1585 mpz_pow_ui(gmpnum_result2, gmpnum_result1, (gmp_ulong) nth);
1586 mpz_sub(gmpnum_result2, gmpnum_a, gmpnum_result2);
1587 #endif
1588
1589 FREE_GMP_TEMP(temp_a);
1590 }
1591
1592
1593
1594
1595 ZEND_FUNCTION(gmp_perfect_square)
1596 {
1597 zval *a_arg;
1598 mpz_ptr gmpnum_a;
1599 gmp_temp_t temp_a;
1600
1601 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
1602 return;
1603 }
1604
1605 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1606
1607 RETVAL_BOOL((mpz_perfect_square_p(gmpnum_a) != 0));
1608 FREE_GMP_TEMP(temp_a);
1609 }
1610
1611
1612
1613
1614 ZEND_FUNCTION(gmp_prob_prime)
1615 {
1616 zval *gmpnumber_arg;
1617 mpz_ptr gmpnum_a;
1618 zend_long reps = 10;
1619 gmp_temp_t temp_a;
1620
1621 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &gmpnumber_arg, &reps) == FAILURE) {
1622 return;
1623 }
1624
1625 FETCH_GMP_ZVAL(gmpnum_a, gmpnumber_arg, temp_a);
1626
1627 RETVAL_LONG(mpz_probab_prime_p(gmpnum_a, reps));
1628 FREE_GMP_TEMP(temp_a);
1629 }
1630
1631
1632
1633
1634 ZEND_FUNCTION(gmp_gcd)
1635 {
1636 gmp_binary_ui_op(mpz_gcd, (gmp_binary_ui_op_t) mpz_gcd_ui);
1637 }
1638
1639
1640
1641
1642 ZEND_FUNCTION(gmp_gcdext)
1643 {
1644 zval *a_arg, *b_arg;
1645 mpz_ptr gmpnum_a, gmpnum_b, gmpnum_t, gmpnum_s, gmpnum_g;
1646 gmp_temp_t temp_a, temp_b;
1647 zval result_g, result_s, result_t;
1648
1649 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
1650 return;
1651 }
1652
1653 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1654 FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
1655
1656 gmp_create(&result_g, &gmpnum_g);
1657 gmp_create(&result_s, &gmpnum_s);
1658 gmp_create(&result_t, &gmpnum_t);
1659
1660 array_init(return_value);
1661 add_assoc_zval(return_value, "g", &result_g);
1662 add_assoc_zval(return_value, "s", &result_s);
1663 add_assoc_zval(return_value, "t", &result_t);
1664
1665 mpz_gcdext(gmpnum_g, gmpnum_s, gmpnum_t, gmpnum_a, gmpnum_b);
1666 FREE_GMP_TEMP(temp_a);
1667 FREE_GMP_TEMP(temp_b);
1668 }
1669
1670
1671
1672
1673 ZEND_FUNCTION(gmp_invert)
1674 {
1675 zval *a_arg, *b_arg;
1676 mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result;
1677 gmp_temp_t temp_a, temp_b;
1678 int res;
1679
1680 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
1681 return;
1682 }
1683
1684 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1685 FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
1686
1687 INIT_GMP_RETVAL(gmpnum_result);
1688 res = mpz_invert(gmpnum_result, gmpnum_a, gmpnum_b);
1689 FREE_GMP_TEMP(temp_a);
1690 FREE_GMP_TEMP(temp_b);
1691 if (!res) {
1692 zval_dtor(return_value);
1693 RETURN_FALSE;
1694 }
1695 }
1696
1697
1698
1699
1700 ZEND_FUNCTION(gmp_jacobi)
1701 {
1702 gmp_binary_opl(mpz_jacobi);
1703 }
1704
1705
1706
1707
1708 ZEND_FUNCTION(gmp_legendre)
1709 {
1710 gmp_binary_opl(mpz_legendre);
1711 }
1712
1713
1714
1715
1716 ZEND_FUNCTION(gmp_cmp)
1717 {
1718 zval *a_arg, *b_arg;
1719
1720 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
1721 return;
1722 }
1723
1724 gmp_cmp(return_value, a_arg, b_arg);
1725 }
1726
1727
1728
1729
1730 ZEND_FUNCTION(gmp_sign)
1731 {
1732
1733 zval *a_arg;
1734 mpz_ptr gmpnum_a;
1735 gmp_temp_t temp_a;
1736
1737 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
1738 return;
1739 }
1740
1741 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
1742
1743 RETVAL_LONG(mpz_sgn(gmpnum_a));
1744 FREE_GMP_TEMP(temp_a);
1745 }
1746
1747
1748 static void gmp_init_random(void)
1749 {
1750 if (!GMPG(rand_initialized)) {
1751
1752 gmp_randinit_mt(GMPG(rand_state));
1753
1754 gmp_randseed_ui(GMPG(rand_state), GENERATE_SEED());
1755
1756 GMPG(rand_initialized) = 1;
1757 }
1758 }
1759
1760
1761
1762 ZEND_FUNCTION(gmp_random)
1763 {
1764 zend_long limiter = 20;
1765 mpz_ptr gmpnum_result;
1766
1767 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &limiter) == FAILURE) {
1768 return;
1769 }
1770
1771 INIT_GMP_RETVAL(gmpnum_result);
1772 gmp_init_random();
1773
1774 #ifdef GMP_LIMB_BITS
1775 mpz_urandomb(gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * GMP_LIMB_BITS);
1776 #else
1777 mpz_urandomb(gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * __GMP_BITS_PER_MP_LIMB);
1778 #endif
1779 }
1780
1781
1782
1783
1784 ZEND_FUNCTION(gmp_random_seed)
1785 {
1786 zval *seed;
1787 mpz_ptr gmpnum_seed;
1788 gmp_temp_t temp_a;
1789
1790 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &seed) == FAILURE) {
1791 return;
1792 }
1793
1794 gmp_init_random();
1795
1796 if (Z_TYPE_P(seed) == IS_LONG && Z_LVAL_P(seed) >= 0) {
1797 gmp_randseed_ui(GMPG(rand_state), Z_LVAL_P(seed));
1798 }
1799 else {
1800 FETCH_GMP_ZVAL(gmpnum_seed, seed, temp_a);
1801
1802 gmp_randseed(GMPG(rand_state), gmpnum_seed);
1803
1804 FREE_GMP_TEMP(temp_a);
1805 }
1806 }
1807
1808
1809
1810
1811 ZEND_FUNCTION(gmp_random_bits)
1812 {
1813 zend_long bits;
1814 mpz_ptr gmpnum_result;
1815
1816 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &bits) == FAILURE) {
1817 return;
1818 }
1819
1820 if (bits <= 0) {
1821 php_error_docref(NULL, E_WARNING, "The number of bits must be positive");
1822 RETURN_FALSE;
1823 }
1824
1825 INIT_GMP_RETVAL(gmpnum_result);
1826 gmp_init_random();
1827
1828 mpz_urandomb(gmpnum_result, GMPG(rand_state), bits);
1829 }
1830
1831
1832
1833
1834 ZEND_FUNCTION(gmp_random_range)
1835 {
1836 zval *min_arg, *max_arg;
1837 mpz_ptr gmpnum_min, gmpnum_max, gmpnum_result;
1838 mpz_t gmpnum_range;
1839 gmp_temp_t temp_a, temp_b;
1840
1841 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &min_arg, &max_arg) == FAILURE) {
1842 return;
1843 }
1844
1845 gmp_init_random();
1846
1847 FETCH_GMP_ZVAL(gmpnum_max, max_arg, temp_a);
1848
1849 if (Z_TYPE_P(min_arg) == IS_LONG && Z_LVAL_P(min_arg) >= 0) {
1850 if (mpz_cmp_ui(gmpnum_max, Z_LVAL_P(min_arg)) <= 0) {
1851 FREE_GMP_TEMP(temp_a);
1852 php_error_docref(NULL, E_WARNING, "The minimum value must be less than the maximum value");
1853 RETURN_FALSE;
1854 }
1855
1856 INIT_GMP_RETVAL(gmpnum_result);
1857 mpz_init(gmpnum_range);
1858
1859 if (Z_LVAL_P(min_arg) != 0) {
1860 mpz_sub_ui(gmpnum_range, gmpnum_max, Z_LVAL_P(min_arg) - 1);
1861 } else {
1862 mpz_add_ui(gmpnum_range, gmpnum_max, 1);
1863 }
1864
1865 mpz_urandomm(gmpnum_result, GMPG(rand_state), gmpnum_range);
1866
1867 if (Z_LVAL_P(min_arg) != 0) {
1868 mpz_add_ui(gmpnum_result, gmpnum_result, Z_LVAL_P(min_arg));
1869 }
1870
1871 mpz_clear(gmpnum_range);
1872 FREE_GMP_TEMP(temp_a);
1873 } else {
1874 FETCH_GMP_ZVAL_DEP(gmpnum_min, min_arg, temp_b, temp_a);
1875
1876 if (mpz_cmp(gmpnum_max, gmpnum_min) <= 0) {
1877 FREE_GMP_TEMP(temp_b);
1878 FREE_GMP_TEMP(temp_a);
1879 php_error_docref(NULL, E_WARNING, "The minimum value must be less than the maximum value");
1880 RETURN_FALSE;
1881 }
1882
1883 INIT_GMP_RETVAL(gmpnum_result);
1884 mpz_init(gmpnum_range);
1885
1886 mpz_sub(gmpnum_range, gmpnum_max, gmpnum_min);
1887 mpz_add_ui(gmpnum_range, gmpnum_range, 1);
1888 mpz_urandomm(gmpnum_result, GMPG(rand_state), gmpnum_range);
1889 mpz_add(gmpnum_result, gmpnum_result, gmpnum_min);
1890
1891 mpz_clear(gmpnum_range);
1892 FREE_GMP_TEMP(temp_b);
1893 FREE_GMP_TEMP(temp_a);
1894 }
1895 }
1896
1897
1898
1899
1900 ZEND_FUNCTION(gmp_and)
1901 {
1902 gmp_binary_op(mpz_and);
1903 }
1904
1905
1906
1907
1908 ZEND_FUNCTION(gmp_or)
1909 {
1910 gmp_binary_op(mpz_ior);
1911 }
1912
1913
1914
1915
1916 ZEND_FUNCTION(gmp_com)
1917 {
1918 gmp_unary_op(mpz_com);
1919 }
1920
1921
1922
1923
1924 ZEND_FUNCTION(gmp_nextprime)
1925 {
1926 gmp_unary_op(mpz_nextprime);
1927 }
1928
1929
1930
1931
1932 ZEND_FUNCTION(gmp_xor)
1933 {
1934 gmp_binary_op(mpz_xor);
1935 }
1936
1937
1938
1939
1940 ZEND_FUNCTION(gmp_setbit)
1941 {
1942 zval *a_arg;
1943 zend_long index;
1944 zend_bool set = 1;
1945 mpz_ptr gmpnum_a;
1946
1947 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol|b", &a_arg, gmp_ce, &index, &set) == FAILURE) {
1948 return;
1949 }
1950
1951 if (index < 0) {
1952 php_error_docref(NULL, E_WARNING, "Index must be greater than or equal to zero");
1953 RETURN_FALSE;
1954 }
1955
1956 gmpnum_a = GET_GMP_FROM_ZVAL(a_arg);
1957
1958 if (set) {
1959 mpz_setbit(gmpnum_a, index);
1960 } else {
1961 mpz_clrbit(gmpnum_a, index);
1962 }
1963 }
1964
1965
1966
1967
1968 ZEND_FUNCTION(gmp_clrbit)
1969 {
1970 zval *a_arg;
1971 zend_long index;
1972 mpz_ptr gmpnum_a;
1973
1974 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &a_arg, gmp_ce, &index) == FAILURE){
1975 return;
1976 }
1977
1978 if (index < 0) {
1979 php_error_docref(NULL, E_WARNING, "Index must be greater than or equal to zero");
1980 RETURN_FALSE;
1981 }
1982
1983 gmpnum_a = GET_GMP_FROM_ZVAL(a_arg);
1984 mpz_clrbit(gmpnum_a, index);
1985 }
1986
1987
1988
1989
1990 ZEND_FUNCTION(gmp_testbit)
1991 {
1992 zval *a_arg;
1993 zend_long index;
1994 mpz_ptr gmpnum_a;
1995 gmp_temp_t temp_a;
1996
1997 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &index) == FAILURE){
1998 return;
1999 }
2000
2001 if (index < 0) {
2002 php_error_docref(NULL, E_WARNING, "Index must be greater than or equal to zero");
2003 RETURN_FALSE;
2004 }
2005
2006 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
2007 RETVAL_BOOL(mpz_tstbit(gmpnum_a, index));
2008 FREE_GMP_TEMP(temp_a);
2009 }
2010
2011
2012
2013
2014 ZEND_FUNCTION(gmp_popcount)
2015 {
2016 gmp_unary_opl((gmp_unary_opl_t) mpz_popcount);
2017 }
2018
2019
2020
2021
2022 ZEND_FUNCTION(gmp_hamdist)
2023 {
2024 gmp_binary_opl((gmp_binary_opl_t) mpz_hamdist);
2025 }
2026
2027
2028
2029
2030 ZEND_FUNCTION(gmp_scan0)
2031 {
2032 zval *a_arg;
2033 mpz_ptr gmpnum_a;
2034 gmp_temp_t temp_a;
2035 zend_long start;
2036
2037 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &start) == FAILURE){
2038 return;
2039 }
2040
2041 if (start < 0) {
2042 php_error_docref(NULL, E_WARNING, "Starting index must be greater than or equal to zero");
2043 RETURN_FALSE;
2044 }
2045
2046 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
2047
2048 RETVAL_LONG(mpz_scan0(gmpnum_a, start));
2049 FREE_GMP_TEMP(temp_a);
2050 }
2051
2052
2053
2054
2055 ZEND_FUNCTION(gmp_scan1)
2056 {
2057 zval *a_arg;
2058 mpz_ptr gmpnum_a;
2059 gmp_temp_t temp_a;
2060 zend_long start;
2061
2062 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &start) == FAILURE){
2063 return;
2064 }
2065
2066 if (start < 0) {
2067 php_error_docref(NULL, E_WARNING, "Starting index must be greater than or equal to zero");
2068 RETURN_FALSE;
2069 }
2070
2071 FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
2072
2073 RETVAL_LONG(mpz_scan1(gmpnum_a, start));
2074 FREE_GMP_TEMP(temp_a);
2075 }
2076
2077
2078 #endif
2079
2080
2081
2082
2083
2084
2085
2086
2087