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

Generated by: LCOV version 1.10

Generated at Tue, 14 Oct 2014 07:25:40 +0000 (7 days ago)

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