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

Generated by: LCOV version 1.10

Generated at Mon, 10 Nov 2014 22:46:39 +0000 (11 days ago)

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