PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/gmp - gmp.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 716 717 99.9 %
Date: 2014-12-13 Functions: 77 77 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sat, 13 Dec 2014 06:16:13 +0000 (7 days ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.