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: 0 628 0.0 %
Date: 2014-04-16 Functions: 0 74 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Wed, 16 Apr 2014 12:47:47 +0000 (53 minutes ago)

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