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: 479 492 97.4 %
Date: 2015-06-29 Functions: 53 53 100.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             : 
      28             : #if HAVE_GMP
      29             : 
      30             : #include <gmp.h>
      31             : 
      32             : /* Needed for gmp_random() */
      33             : #include "ext/standard/php_rand.h"
      34             : #include "ext/standard/php_lcg.h"
      35             : #define GMP_ABS(x) ((x) >= 0 ? (x) : -(x))
      36             : 
      37             : /* True global resources - no need for thread safety here */
      38             : static int le_gmp;
      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(arginfo_gmp_intval, 0)
      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(arginfo_gmp_add, 0)
      56             :         ZEND_ARG_INFO(0, a)
      57             :         ZEND_ARG_INFO(0, b)
      58             : ZEND_END_ARG_INFO()
      59             : 
      60             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_sub, 0)
      61             :         ZEND_ARG_INFO(0, a)
      62             :         ZEND_ARG_INFO(0, b)
      63             : ZEND_END_ARG_INFO()
      64             : 
      65             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_mul, 0)
      66             :         ZEND_ARG_INFO(0, a)
      67             :         ZEND_ARG_INFO(0, b)
      68             : ZEND_END_ARG_INFO()
      69             : 
      70             : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_div_qr, 0, 0, 2)
      71             :         ZEND_ARG_INFO(0, a)
      72             :         ZEND_ARG_INFO(0, b)
      73             :         ZEND_ARG_INFO(0, round)
      74             : ZEND_END_ARG_INFO()
      75             : 
      76             : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_div_r, 0, 0, 2)
      77             :         ZEND_ARG_INFO(0, a)
      78             :         ZEND_ARG_INFO(0, b)
      79             :         ZEND_ARG_INFO(0, round)
      80             : ZEND_END_ARG_INFO()
      81             : 
      82             : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_div_q, 0, 0, 2)
      83             :         ZEND_ARG_INFO(0, a)
      84             :         ZEND_ARG_INFO(0, b)
      85             :         ZEND_ARG_INFO(0, round)
      86             : ZEND_END_ARG_INFO()
      87             : 
      88             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_mod, 0)
      89             :         ZEND_ARG_INFO(0, a)
      90             :         ZEND_ARG_INFO(0, b)
      91             : ZEND_END_ARG_INFO()
      92             : 
      93             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_divexact, 0)
      94             :         ZEND_ARG_INFO(0, a)
      95             :         ZEND_ARG_INFO(0, b)
      96             : ZEND_END_ARG_INFO()
      97             : 
      98             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_neg, 0)
      99             :         ZEND_ARG_INFO(0, a)
     100             : ZEND_END_ARG_INFO()
     101             : 
     102             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_abs, 0)
     103             :         ZEND_ARG_INFO(0, a)
     104             : ZEND_END_ARG_INFO()
     105             : 
     106             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_fact, 0)
     107             :         ZEND_ARG_INFO(0, a)
     108             : ZEND_END_ARG_INFO()
     109             : 
     110             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_pow, 0)
     111             :         ZEND_ARG_INFO(0, base)
     112             :         ZEND_ARG_INFO(0, exp)
     113             : ZEND_END_ARG_INFO()
     114             : 
     115             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_powm, 0)
     116             :         ZEND_ARG_INFO(0, base)
     117             :         ZEND_ARG_INFO(0, exp)
     118             :         ZEND_ARG_INFO(0, mod)
     119             : ZEND_END_ARG_INFO()
     120             : 
     121             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_sqrt, 0)
     122             :         ZEND_ARG_INFO(0, a)
     123             : ZEND_END_ARG_INFO()
     124             : 
     125             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_sqrtrem, 0)
     126             :         ZEND_ARG_INFO(0, a)
     127             : ZEND_END_ARG_INFO()
     128             : 
     129             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_perfect_square, 0)
     130             :         ZEND_ARG_INFO(0, a)
     131             : ZEND_END_ARG_INFO()
     132             : 
     133             : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_prob_prime, 0, 0, 1)
     134             :         ZEND_ARG_INFO(0, a)
     135             :         ZEND_ARG_INFO(0, reps)
     136             : ZEND_END_ARG_INFO()
     137             : 
     138             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_gcd, 0)
     139             :         ZEND_ARG_INFO(0, a)
     140             :         ZEND_ARG_INFO(0, b)
     141             : ZEND_END_ARG_INFO()
     142             : 
     143             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_gcdext, 0)
     144             :         ZEND_ARG_INFO(0, a)
     145             :         ZEND_ARG_INFO(0, b)
     146             : ZEND_END_ARG_INFO()
     147             : 
     148             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_invert, 0)
     149             :         ZEND_ARG_INFO(0, a)
     150             :         ZEND_ARG_INFO(0, b)
     151             : ZEND_END_ARG_INFO()
     152             : 
     153             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_jacobi, 0)
     154             :         ZEND_ARG_INFO(0, a)
     155             :         ZEND_ARG_INFO(0, b)
     156             : ZEND_END_ARG_INFO()
     157             : 
     158             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_legendre, 0)
     159             :         ZEND_ARG_INFO(0, a)
     160             :         ZEND_ARG_INFO(0, b)
     161             : ZEND_END_ARG_INFO()
     162             : 
     163             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_cmp, 0)
     164             :         ZEND_ARG_INFO(0, a)
     165             :         ZEND_ARG_INFO(0, b)
     166             : ZEND_END_ARG_INFO()
     167             : 
     168             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_sign, 0)
     169             :         ZEND_ARG_INFO(0, a)
     170             : ZEND_END_ARG_INFO()
     171             : 
     172             : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_random, 0, 0, 0)
     173             :         ZEND_ARG_INFO(0, limiter)
     174             : ZEND_END_ARG_INFO()
     175             : 
     176             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_and, 0)
     177             :         ZEND_ARG_INFO(0, a)
     178             :         ZEND_ARG_INFO(0, b)
     179             : ZEND_END_ARG_INFO()
     180             : 
     181             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_or, 0)
     182             :         ZEND_ARG_INFO(0, a)
     183             :         ZEND_ARG_INFO(0, b)
     184             : ZEND_END_ARG_INFO()
     185             : 
     186             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_com, 0)
     187             :         ZEND_ARG_INFO(0, a)
     188             : ZEND_END_ARG_INFO()
     189             : 
     190             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_xor, 0)
     191             :         ZEND_ARG_INFO(0, a)
     192             :         ZEND_ARG_INFO(0, b)
     193             : ZEND_END_ARG_INFO()
     194             : 
     195             : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_setbit, 0, 0, 2)
     196             :         ZEND_ARG_INFO(1, a)
     197             :         ZEND_ARG_INFO(0, index)
     198             :         ZEND_ARG_INFO(0, set_clear)
     199             : ZEND_END_ARG_INFO()
     200             : 
     201             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_clrbit, 0)
     202             :         ZEND_ARG_INFO(1, a)
     203             :         ZEND_ARG_INFO(0, index)
     204             : ZEND_END_ARG_INFO()
     205             : 
     206             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_testbit, 0)
     207             :         ZEND_ARG_INFO(0, a)
     208             :         ZEND_ARG_INFO(0, index)
     209             : ZEND_END_ARG_INFO()
     210             : 
     211             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_popcount, 0)
     212             :         ZEND_ARG_INFO(0, a)
     213             : ZEND_END_ARG_INFO()
     214             : 
     215             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_hamdist, 0)
     216             :         ZEND_ARG_INFO(0, a)
     217             :         ZEND_ARG_INFO(0, b)
     218             : ZEND_END_ARG_INFO()
     219             : 
     220             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_scan0, 0)
     221             :         ZEND_ARG_INFO(0, a)
     222             :         ZEND_ARG_INFO(0, start)
     223             : ZEND_END_ARG_INFO()
     224             : 
     225             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_scan1, 0)
     226             :         ZEND_ARG_INFO(0, a)
     227             :         ZEND_ARG_INFO(0, start)
     228             : ZEND_END_ARG_INFO()
     229             : 
     230             : ZEND_BEGIN_ARG_INFO(arginfo_gmp_nextprime, 0)
     231             :         ZEND_ARG_INFO(0, a)
     232             : ZEND_END_ARG_INFO()
     233             : 
     234             : /* }}} */
     235             : 
     236             : ZEND_DECLARE_MODULE_GLOBALS(gmp)
     237             : static ZEND_GINIT_FUNCTION(gmp);
     238             : 
     239             : /* {{{ gmp_functions[]
     240             :  */
     241             : const zend_function_entry gmp_functions[] = {
     242             :         ZEND_FE(gmp_init,       arginfo_gmp_init)
     243             :         ZEND_FE(gmp_intval,     arginfo_gmp_intval)
     244             :         ZEND_FE(gmp_strval,     arginfo_gmp_strval)
     245             :         ZEND_FE(gmp_add,            arginfo_gmp_add)
     246             :         ZEND_FE(gmp_sub,            arginfo_gmp_sub)
     247             :         ZEND_FE(gmp_mul,            arginfo_gmp_mul)
     248             :         ZEND_FE(gmp_div_qr,     arginfo_gmp_div_qr)
     249             :         ZEND_FE(gmp_div_q,      arginfo_gmp_div_q)
     250             :         ZEND_FE(gmp_div_r,      arginfo_gmp_div_r)
     251             :         ZEND_FALIAS(gmp_div,    gmp_div_q, arginfo_gmp_div_q)
     252             :         ZEND_FE(gmp_mod,        arginfo_gmp_mod)
     253             :         ZEND_FE(gmp_divexact,   arginfo_gmp_divexact)
     254             :         ZEND_FE(gmp_neg,        arginfo_gmp_neg)
     255             :         ZEND_FE(gmp_abs,        arginfo_gmp_abs)
     256             :         ZEND_FE(gmp_fact,       arginfo_gmp_fact)
     257             :         ZEND_FE(gmp_sqrt,       arginfo_gmp_sqrt)
     258             :         ZEND_FE(gmp_sqrtrem,    arginfo_gmp_sqrtrem)
     259             :         ZEND_FE(gmp_pow,        arginfo_gmp_pow)
     260             :         ZEND_FE(gmp_powm,       arginfo_gmp_powm)
     261             :         ZEND_FE(gmp_perfect_square,     arginfo_gmp_perfect_square)
     262             :         ZEND_FE(gmp_prob_prime, arginfo_gmp_prob_prime)
     263             :         ZEND_FE(gmp_gcd,        arginfo_gmp_gcd)
     264             :         ZEND_FE(gmp_gcdext,     arginfo_gmp_gcdext)
     265             :         ZEND_FE(gmp_invert,     arginfo_gmp_invert)
     266             :         ZEND_FE(gmp_jacobi,     arginfo_gmp_jacobi)
     267             :         ZEND_FE(gmp_legendre,   arginfo_gmp_legendre)
     268             :         ZEND_FE(gmp_cmp,        arginfo_gmp_cmp)
     269             :         ZEND_FE(gmp_sign,       arginfo_gmp_sign)
     270             :         ZEND_FE(gmp_random,     arginfo_gmp_random)
     271             :         ZEND_FE(gmp_and,        arginfo_gmp_and)
     272             :         ZEND_FE(gmp_or, arginfo_gmp_or)
     273             :         ZEND_FE(gmp_com,        arginfo_gmp_com)
     274             :         ZEND_FE(gmp_xor,        arginfo_gmp_xor)
     275             :         ZEND_FE(gmp_setbit,     arginfo_gmp_setbit)
     276             :         ZEND_FE(gmp_clrbit,     arginfo_gmp_clrbit)
     277             :         ZEND_FE(gmp_scan0,  arginfo_gmp_scan0)
     278             :         ZEND_FE(gmp_scan1,  arginfo_gmp_scan1)
     279             :         ZEND_FE(gmp_testbit,arginfo_gmp_testbit)
     280             :         ZEND_FE(gmp_popcount, arginfo_gmp_popcount)
     281             :         ZEND_FE(gmp_hamdist, arginfo_gmp_hamdist)
     282             :         ZEND_FE(gmp_nextprime, arginfo_gmp_nextprime)
     283             :         PHP_FE_END
     284             : };
     285             : /* }}} */
     286             : 
     287             : /* {{{ gmp_module_entry
     288             :  */
     289             : zend_module_entry gmp_module_entry = {
     290             :         STANDARD_MODULE_HEADER,
     291             :         "gmp",
     292             :         gmp_functions,
     293             :         ZEND_MODULE_STARTUP_N(gmp),
     294             :         NULL,
     295             :         NULL,
     296             :         ZEND_MODULE_DEACTIVATE_N(gmp),
     297             :         ZEND_MODULE_INFO_N(gmp),
     298             :         NO_VERSION_YET,
     299             :         ZEND_MODULE_GLOBALS(gmp),
     300             :         ZEND_GINIT(gmp),
     301             :         NULL,
     302             :         NULL,
     303             :         STANDARD_MODULE_PROPERTIES_EX
     304             : };
     305             : /* }}} */
     306             : 
     307             : #ifdef COMPILE_DL_GMP
     308             : ZEND_GET_MODULE(gmp)
     309             : #endif
     310             : 
     311             : static void _php_gmpnum_free(zend_rsrc_list_entry *rsrc TSRMLS_DC);
     312             : 
     313             : #define GMP_RESOURCE_NAME "GMP integer"
     314             : 
     315             : #define GMP_ROUND_ZERO      0
     316             : #define GMP_ROUND_PLUSINF   1
     317             : #define GMP_ROUND_MINUSINF  2
     318             : 
     319             : /* The maximum base for input and output conversions is 62 from GMP 4.2
     320             :  * onwards. */
     321             : #if (__GNU_MP_VERSION >= 5) || (__GNU_MP_VERSION >= 4 && __GNU_MP_VERSION_MINOR >= 2)
     322             : #       define MAX_BASE 62
     323             : #else
     324             : #       define MAX_BASE 36
     325             : #endif
     326             : 
     327             : /* {{{ ZEND_GINIT_FUNCTION
     328             :  */
     329       20270 : static ZEND_GINIT_FUNCTION(gmp)
     330             : {
     331       20270 :         gmp_globals->rand_initialized = 0;
     332       20270 : }
     333             : /* }}} */
     334             : 
     335             : /* {{{ ZEND_MINIT_FUNCTION
     336             :  */
     337       20270 : ZEND_MODULE_STARTUP_D(gmp)
     338             : {
     339       20270 :         le_gmp = zend_register_list_destructors_ex(_php_gmpnum_free, NULL, GMP_RESOURCE_NAME, module_number);
     340       20270 :         REGISTER_LONG_CONSTANT("GMP_ROUND_ZERO", GMP_ROUND_ZERO, CONST_CS | CONST_PERSISTENT);
     341       20270 :         REGISTER_LONG_CONSTANT("GMP_ROUND_PLUSINF", GMP_ROUND_PLUSINF, CONST_CS | CONST_PERSISTENT);
     342       20270 :         REGISTER_LONG_CONSTANT("GMP_ROUND_MINUSINF", GMP_ROUND_MINUSINF, CONST_CS | CONST_PERSISTENT);
     343             : #ifdef mpir_version
     344             :         REGISTER_STRING_CONSTANT("GMP_MPIR_VERSION", (char *)mpir_version, CONST_CS | CONST_PERSISTENT);
     345             : #endif
     346       20270 :         REGISTER_STRING_CONSTANT("GMP_VERSION", (char *)gmp_version, CONST_CS | CONST_PERSISTENT);
     347             : 
     348       20270 :         return SUCCESS;
     349             : }
     350             : /* }}} */
     351             : 
     352             : /* {{{ ZEND_RSHUTDOWN_FUNCTION
     353             :  */
     354       20265 : ZEND_MODULE_DEACTIVATE_D(gmp)
     355             : {
     356       20265 :         if (GMPG(rand_initialized)) {
     357           1 :                 gmp_randclear(GMPG(rand_state));
     358           1 :                 GMPG(rand_initialized) = 0;
     359             :         }
     360             : 
     361       20265 :         return SUCCESS;
     362             : }
     363             : /* }}} */
     364             : 
     365             : /* {{{ ZEND_MINFO_FUNCTION
     366             :  */
     367         148 : ZEND_MODULE_INFO_D(gmp)
     368             : {
     369         148 :         php_info_print_table_start();
     370         148 :         php_info_print_table_row(2, "gmp support", "enabled");
     371             : #ifdef mpir_version
     372             :         php_info_print_table_row(2, "MPIR version", mpir_version);
     373             : #else
     374         148 :         php_info_print_table_row(2, "GMP version", gmp_version);
     375             : #endif
     376         148 :         php_info_print_table_end();
     377         148 : }
     378             : /* }}} */
     379             : 
     380             : /* Fetch zval to be GMP number.
     381             :    Initially, zval can be also number or string */
     382             : #define FETCH_GMP_ZVAL(gmpnumber, zval, tmp_resource)                                                           \
     383             : if (Z_TYPE_PP(zval) == IS_RESOURCE) {                                                                                           \
     384             :         ZEND_FETCH_RESOURCE(gmpnumber, mpz_t *, zval, -1, GMP_RESOURCE_NAME, le_gmp);   \
     385             :         tmp_resource = 0;                                                                                                                               \
     386             : } else {                                                                                                                                                        \
     387             :         if (convert_to_gmp(&gmpnumber, zval, 0 TSRMLS_CC) == FAILURE) {                                     \
     388             :                 RETURN_FALSE;                                                                                                                           \
     389             :         }                                                                                                                                                               \
     390             :         tmp_resource = ZEND_REGISTER_RESOURCE(NULL, gmpnumber, le_gmp);                                 \
     391             : }
     392             : 
     393             : #define FREE_GMP_TEMP(tmp_resource)                     \
     394             :         if(tmp_resource) {                                              \
     395             :                 zend_list_delete(tmp_resource);         \
     396             :         }
     397             : 
     398             : 
     399             : /* create a new initialized GMP number */
     400             : #define INIT_GMP_NUM(gmpnumber) { gmpnumber=emalloc(sizeof(mpz_t)); mpz_init(*gmpnumber); }
     401             : #define FREE_GMP_NUM(gmpnumber) { mpz_clear(*gmpnumber); efree(gmpnumber); }
     402             : 
     403             : /* {{{ convert_to_gmp
     404             :  * Convert zval to be gmp number */
     405        1614 : static int convert_to_gmp(mpz_t * *gmpnumber, zval **val, int base TSRMLS_DC) 
     406             : {
     407        1614 :         int ret = 0;
     408        1614 :         int skip_lead = 0;
     409             : 
     410        1614 :         *gmpnumber = emalloc(sizeof(mpz_t));
     411             : 
     412        1614 :         switch (Z_TYPE_PP(val)) {
     413             :         case IS_LONG:
     414             :         case IS_BOOL:
     415             :         case IS_CONSTANT:
     416             :                 {
     417        1480 :                         convert_to_long_ex(val);
     418        1365 :                         mpz_init_set_si(**gmpnumber, Z_LVAL_PP(val));
     419             :                 }
     420        1365 :                 break;
     421             :         case IS_STRING:
     422             :                 {
     423         187 :                         char *numstr = Z_STRVAL_PP(val);
     424             : 
     425         187 :                         if (Z_STRLEN_PP(val) > 2) {
     426         154 :                                 if (numstr[0] == '0') {
     427          13 :                                         if (numstr[1] == 'x' || numstr[1] == 'X') {
     428           3 :                                                 base = 16;
     429           3 :                                                 skip_lead = 1;
     430           7 :                                         } else if (base != 16 && (numstr[1] == 'b' || numstr[1] == 'B')) {
     431           2 :                                                 base = 2;
     432           2 :                                                 skip_lead = 1;
     433             :                                         }
     434             :                                 }
     435             :                         }
     436         187 :                         ret = mpz_init_set_str(**gmpnumber, (skip_lead ? &numstr[2] : numstr), base);
     437             :                 }
     438         187 :                 break;
     439             :         default:
     440          62 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Unable to convert variable to GMP - wrong type");
     441          62 :                 efree(*gmpnumber);
     442          62 :                 return FAILURE;
     443             :         }
     444             : 
     445        1552 :         if (ret) {
     446          18 :                 FREE_GMP_NUM(*gmpnumber);
     447          18 :                 return FAILURE;
     448             :         }
     449             :         
     450        1534 :         return SUCCESS;
     451             : }
     452             : /* }}} */
     453             : 
     454             : /* {{{ typedefs
     455             :  */
     456             : typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr);
     457             : typedef int (*gmp_unary_opl_t)(mpz_srcptr);
     458             : 
     459             : typedef void (*gmp_unary_ui_op_t)(mpz_ptr, unsigned long);
     460             : 
     461             : typedef void (*gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr);
     462             : typedef int (*gmp_binary_opl_t)(mpz_srcptr, mpz_srcptr);
     463             : 
     464             : typedef unsigned long (*gmp_binary_ui_op_t)(mpz_ptr, mpz_srcptr, unsigned long);
     465             : typedef void (*gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
     466             : typedef unsigned long (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long);
     467             : /* }}} */
     468             : 
     469             : #define gmp_zval_binary_ui_op(r, a, b, o, u) gmp_zval_binary_ui_op_ex(r, a, b, o, u, 0, 0, 0 TSRMLS_CC)
     470             : #define gmp_zval_binary_ui_op2(r, a, b, o, u) gmp_zval_binary_ui_op2_ex(r, a, b, o, u, 0, 0, 0 TSRMLS_CC)
     471             : 
     472             : #define gmp_binary_ui_op(op, uop) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop)
     473             : #define gmp_binary_op(op)         _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, NULL)
     474             : #define gmp_binary_opl(op) _gmp_binary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
     475             : 
     476             : /* Unary operations */
     477             : #define gmp_unary_op(op)         _gmp_unary_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
     478             : #define gmp_unary_opl(op)         _gmp_unary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
     479             : #define gmp_unary_ui_op(op)      _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
     480             : 
     481             : /* {{{ gmp_zval_binary_ui_op_ex
     482             :    Execute GMP binary operation.
     483             :    May return GMP resource or long if operation allows this
     484             : */
     485        1107 : static inline void gmp_zval_binary_ui_op_ex(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int allow_ui_return, int check_b_zero, int use_sign TSRMLS_DC) 
     486             : {
     487             :         mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result;
     488        1107 :         unsigned long long_result = 0;
     489        1107 :         int use_ui = 0;
     490        1107 :         int arga_tmp = 0, argb_tmp = 0;
     491             : 
     492        1107 :         FETCH_GMP_ZVAL(gmpnum_a, a_arg, arga_tmp);
     493             :         
     494        1138 :         if (gmp_ui_op && Z_TYPE_PP(b_arg) == IS_LONG && Z_LVAL_PP(b_arg) >= 0) {
     495          46 :                 use_ui = 1;
     496             :         } else {
     497        1046 :                 FETCH_GMP_ZVAL(gmpnum_b, b_arg, argb_tmp);
     498             :         }
     499             : 
     500        1089 :         if(check_b_zero) {
     501          48 :                 int b_is_zero = 0;
     502          48 :                 if(use_ui) {
     503          26 :                         b_is_zero = (Z_LVAL_PP(b_arg) == 0);
     504             :                 } else {
     505          22 :                         b_is_zero = !mpz_cmp_ui(*gmpnum_b, 0);
     506             :                 }
     507             : 
     508          48 :                 if(b_is_zero) {
     509           5 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero operand not allowed");
     510           5 :                         FREE_GMP_TEMP(arga_tmp);
     511           5 :                         FREE_GMP_TEMP(argb_tmp);
     512           5 :                         RETURN_FALSE;
     513             :                 }
     514             :         }
     515             : 
     516        1084 :         INIT_GMP_NUM(gmpnum_result);
     517             : 
     518        1126 :         if (use_ui && gmp_ui_op) {
     519          42 :                 if (allow_ui_return) {
     520          14 :                         long_result = gmp_ui_op(*gmpnum_result, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg));
     521          14 :                         if (use_sign && mpz_sgn(*gmpnum_a) == -1) {
     522           0 :                                 long_result = -long_result;
     523             :                         }
     524             :                 } else {
     525          28 :                         gmp_ui_op(*gmpnum_result, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg));
     526             :                 }
     527             :         } else {
     528        1042 :                 gmp_op(*gmpnum_result, *gmpnum_a, *gmpnum_b);
     529             :         }
     530             : 
     531        1084 :         FREE_GMP_TEMP(arga_tmp);
     532        1084 :         FREE_GMP_TEMP(argb_tmp);
     533             : 
     534        1084 :         if (use_ui && allow_ui_return) {
     535          14 :                 FREE_GMP_NUM(gmpnum_result);
     536          14 :                 RETURN_LONG((long)long_result);
     537             :         } else {
     538        1070 :                 ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
     539             :         }
     540             : }
     541             : /* }}} */
     542             : 
     543             : /* {{{ gmp_zval_binary_ui_op2_ex
     544             :    Execute GMP binary operation which returns 2 values.
     545             :    May return GMP resources or longs if operation allows this.
     546             : */
     547          12 : static inline void gmp_zval_binary_ui_op2_ex(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int allow_ui_return, int check_b_zero TSRMLS_DC)
     548             : {
     549             :         mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result1, *gmpnum_result2;
     550             :         zval r;
     551          12 :         int use_ui = 0;
     552          12 :         unsigned long long_result = 0;
     553          12 :         int arga_tmp = 0, argb_tmp = 0;
     554             : 
     555          12 :         FETCH_GMP_ZVAL(gmpnum_a, a_arg, arga_tmp);
     556             : 
     557          20 :         if (gmp_ui_op && Z_TYPE_PP(b_arg) == IS_LONG && Z_LVAL_PP(b_arg) >= 0) {
     558             :                 /* use _ui function */
     559          10 :                 use_ui = 1;
     560             :         } else {
     561           0 :                 FETCH_GMP_ZVAL(gmpnum_b, b_arg, argb_tmp);
     562             :         }
     563             : 
     564          10 :         if(check_b_zero) {
     565          10 :                 int b_is_zero = 0;
     566          10 :                 if(use_ui) {
     567          10 :                         b_is_zero = (Z_LVAL_PP(b_arg) == 0);
     568             :                 } else {
     569           0 :                         b_is_zero = !mpz_cmp_ui(*gmpnum_b, 0);
     570             :                 }
     571             : 
     572          10 :                 if(b_is_zero) {
     573           2 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero operand not allowed");
     574           2 :                         FREE_GMP_TEMP(arga_tmp);
     575           2 :                         FREE_GMP_TEMP(argb_tmp);
     576           2 :                         RETURN_FALSE;
     577             :                 }
     578             :         }
     579             : 
     580           8 :         INIT_GMP_NUM(gmpnum_result1);
     581           8 :         INIT_GMP_NUM(gmpnum_result2);
     582             : 
     583          16 :         if (use_ui && gmp_ui_op) {
     584           8 :                 if (allow_ui_return) {
     585           0 :                         long_result = gmp_ui_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg));
     586             :                 } else {
     587           8 :                         gmp_ui_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg));
     588             :                 }
     589             :         } else {
     590           0 :                 gmp_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, *gmpnum_b);
     591             :         }
     592             : 
     593           8 :         FREE_GMP_TEMP(arga_tmp);
     594           8 :         FREE_GMP_TEMP(argb_tmp);
     595             : 
     596           8 :         array_init(return_value);
     597           8 :         ZEND_REGISTER_RESOURCE(&r, gmpnum_result1, le_gmp);
     598           8 :         add_index_resource(return_value, 0, Z_LVAL(r));
     599           8 :         if (use_ui && allow_ui_return) {
     600           0 :                 mpz_clear(*gmpnum_result2);
     601           0 :                 add_index_long(return_value, 1, long_result);
     602             :         } else {
     603           8 :                 ZEND_REGISTER_RESOURCE(&r, gmpnum_result2, le_gmp);
     604           8 :                 add_index_resource(return_value, 1, Z_LVAL(r));
     605             :         }
     606             : }
     607             : /* }}} */
     608             : 
     609             : /* {{{ _gmp_binary_ui_op
     610             :  */
     611        1049 : static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op)
     612             : {
     613             :         zval **a_arg, **b_arg;
     614             : 
     615        1049 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
     616           7 :                 return;
     617             :         }
     618             :         
     619        1042 :         gmp_zval_binary_ui_op(return_value, a_arg, b_arg, gmp_op, gmp_ui_op);
     620             : }
     621             : /* }}} */
     622             : 
     623             : /* Unary operations */
     624             : 
     625             : /* {{{ gmp_zval_unary_op
     626             :  */
     627          37 : static inline void gmp_zval_unary_op(zval *return_value, zval **a_arg, gmp_unary_op_t gmp_op TSRMLS_DC) 
     628             : {
     629             :         mpz_t *gmpnum_a, *gmpnum_result;
     630             :         int temp_a;
     631             :         
     632          37 :         FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
     633             : 
     634          25 :         INIT_GMP_NUM(gmpnum_result);
     635          25 :         gmp_op(*gmpnum_result, *gmpnum_a);
     636             : 
     637          25 :         FREE_GMP_TEMP(temp_a);
     638          25 :         ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
     639             : }
     640             : /* }}} */
     641             : 
     642             : /* {{{ gmp_zval_unary_ui_op
     643             :  */
     644          11 : static inline void gmp_zval_unary_ui_op(zval *return_value, zval **a_arg, gmp_unary_ui_op_t gmp_op TSRMLS_DC)
     645             : {
     646             :         mpz_t *gmpnum_result;
     647             : 
     648          16 :         convert_to_long_ex(a_arg);
     649             : 
     650          11 :         INIT_GMP_NUM(gmpnum_result);
     651          11 :         gmp_op(*gmpnum_result, Z_LVAL_PP(a_arg));
     652             : 
     653          11 :         ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
     654          11 : }
     655             : /* }}} */
     656             : 
     657             : /* {{{ _gmp_unary_ui_op
     658             :    Execute GMP unary operation.
     659             : */
     660             : static inline void _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_ui_op_t gmp_op)
     661             : {
     662             :         zval **a_arg;
     663             : 
     664             :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
     665             :                 return;
     666             :         }
     667             : 
     668             :         gmp_zval_unary_ui_op(return_value, a_arg, gmp_op TSRMLS_CC);
     669             : }
     670             : /* }}} */
     671             : 
     672             : /* {{{ _gmp_unary_op
     673             :  */
     674          42 : static inline void _gmp_unary_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_op_t gmp_op)
     675             : {
     676             :         zval **a_arg;
     677             : 
     678          42 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
     679           5 :                 return;
     680             :         }
     681             :         
     682          37 :         gmp_zval_unary_op(return_value, a_arg, gmp_op TSRMLS_CC);
     683             : }
     684             : /* }}} */
     685             : 
     686             : /* {{{ _gmp_unary_opl
     687             :  */
     688             : static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t gmp_op)
     689             : {
     690             :         zval **a_arg;
     691             :         mpz_t *gmpnum_a;
     692             :         int temp_a;
     693             : 
     694             :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
     695             :                 return;
     696             :         }
     697             :         
     698             :         FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
     699             :         RETVAL_LONG(gmp_op(*gmpnum_a));
     700             :         FREE_GMP_TEMP(temp_a);
     701             : }
     702             : /* }}} */
     703             : 
     704             : /* {{{ _gmp_binary_opl
     705             :  */
     706          46 : static inline void _gmp_binary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_opl_t gmp_op)
     707             : {
     708             :         zval **a_arg, **b_arg;
     709             :         mpz_t *gmpnum_a, *gmpnum_b;
     710             :         int temp_a, temp_b;
     711             : 
     712          46 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
     713           6 :                 return;
     714             :         }
     715             : 
     716          40 :         FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
     717          36 :         FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b);
     718             : 
     719          34 :         RETVAL_LONG(gmp_op(*gmpnum_a, *gmpnum_b));
     720             : 
     721          34 :         FREE_GMP_TEMP(temp_a);
     722          34 :         FREE_GMP_TEMP(temp_b);
     723             : }
     724             : /* }}} */
     725             : 
     726             : /* {{{ proto resource gmp_init(mixed number [, int base])
     727             :    Initializes GMP number */
     728         122 : ZEND_FUNCTION(gmp_init)
     729             : {
     730             :         zval **number_arg;
     731             :         mpz_t * gmpnumber;
     732         122 :         long base=0;
     733             : 
     734         122 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &number_arg, &base) == FAILURE) {
     735           3 :                 return;
     736             :         }
     737             : 
     738         119 :         if (base && (base < 2 || base > MAX_BASE)) {
     739           1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad base for conversion: %ld (should be between 2 and %d)", base, MAX_BASE);
     740           1 :                 RETURN_FALSE;
     741             :         }
     742             : 
     743         118 :         if (convert_to_gmp(&gmpnumber, number_arg, base TSRMLS_CC) == FAILURE) {
     744           5 :                 RETURN_FALSE;
     745             :         }
     746             : 
     747             :         /* Write your own code here to handle argument number. */
     748         113 :         ZEND_REGISTER_RESOURCE(return_value, gmpnumber, le_gmp);
     749             : }
     750             : /* }}} */
     751             : 
     752             : /* {{{ proto int gmp_intval(resource gmpnumber)
     753             :    Gets signed long value of GMP number */
     754          19 : ZEND_FUNCTION(gmp_intval)
     755             : {
     756             :         zval **gmpnumber_arg;
     757             :         mpz_t * gmpnum;
     758             : 
     759          19 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &gmpnumber_arg) == FAILURE){
     760           1 :                 return;
     761             :         }
     762             :         
     763          18 :         if (Z_TYPE_PP(gmpnumber_arg) == IS_RESOURCE) {
     764           8 :                 ZEND_FETCH_RESOURCE(gmpnum, mpz_t *, gmpnumber_arg, -1, GMP_RESOURCE_NAME, le_gmp);
     765           7 :                 RETVAL_LONG(mpz_get_si(*gmpnum));
     766             :         } else {
     767          31 :                 convert_to_long_ex(gmpnumber_arg);
     768          10 :                 RETVAL_LONG(Z_LVAL_PP(gmpnumber_arg));
     769             :         }
     770             : }
     771             : /* }}} */
     772             : 
     773             : /* {{{ proto string gmp_strval(resource gmpnumber [, int base])
     774             :    Gets string representation of GMP number  */
     775         345 : ZEND_FUNCTION(gmp_strval)
     776             : {
     777             :         zval **gmpnumber_arg;
     778             :         int num_len;
     779         345 :         long base = 10;
     780             :         mpz_t * gmpnum;
     781             :         char *out_string;
     782             :         int temp_a;
     783             : 
     784         345 :         if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &gmpnumber_arg, &base ) == FAILURE ) {
     785           5 :                 return;
     786             :         }
     787             : 
     788             : #if MAX_BASE == 62
     789             :         /* Although the maximum base in general in GMP >= 4.2 is 62, mpz_get_str()
     790             :          * is explicitly limited to -36 when dealing with negative bases. */
     791         340 :         if ((base < 2 && base > -2) || base > MAX_BASE || base < -36) {
     792           9 :                 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);
     793             : #else
     794             :         if (base < 2 || base > MAX_BASE) {
     795             :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad base for conversion: %ld (should be between 2 and %d)", base, MAX_BASE);
     796             : #endif
     797           9 :                 RETURN_FALSE;
     798             :         }
     799             : 
     800         331 :         FETCH_GMP_ZVAL(gmpnum, gmpnumber_arg, temp_a);
     801             : 
     802         317 :         num_len = mpz_sizeinbase(*gmpnum, abs(base));
     803         317 :         out_string = emalloc(num_len+2);
     804         317 :         if (mpz_sgn(*gmpnum) < 0) {
     805          43 :                 num_len++;
     806             :         }
     807         317 :         mpz_get_str(out_string, base, *gmpnum);
     808             :         
     809         317 :         FREE_GMP_TEMP(temp_a);
     810             :         
     811             :         /* 
     812             :         From GMP documentation for mpz_sizeinbase():
     813             :         The returned value will be exact or 1 too big.  If base is a power of
     814             :         2, the returned value will always be exact.
     815             : 
     816             :         So let's check to see if we already have a \0 byte...
     817             :         */
     818             : 
     819         317 :         if (out_string[num_len-1] == '\0') {
     820          44 :                 num_len--;
     821             :         } else {
     822         273 :                 out_string[num_len] = '\0';
     823             :         }
     824         317 :         RETVAL_STRINGL(out_string, num_len, 0);
     825             : }
     826             : /* }}} */
     827             : 
     828             : /* {{{ proto resource gmp_add(resource a, resource b)
     829             :    Add a and b */
     830          15 : ZEND_FUNCTION(gmp_add)
     831             : {
     832          15 :         gmp_binary_ui_op(mpz_add, (gmp_binary_ui_op_t)mpz_add_ui);
     833          15 : }
     834             : /* }}} */
     835             : 
     836             : /* {{{ proto resource gmp_sub(resource a, resource b)
     837             :    Subtract b from a */
     838           9 : ZEND_FUNCTION(gmp_sub)
     839             : {
     840           9 :         gmp_binary_ui_op(mpz_sub, (gmp_binary_ui_op_t)mpz_sub_ui);
     841           9 : }
     842             : /* }}} */
     843             : 
     844             : /* {{{ proto resource gmp_mul(resource a, resource b)
     845             :    Multiply a and b */
     846         999 : ZEND_FUNCTION(gmp_mul)
     847             : {
     848         999 :         gmp_binary_ui_op(mpz_mul, (gmp_binary_ui_op_t)mpz_mul_ui);
     849         999 : }
     850             : /* }}} */
     851             : 
     852             : /* {{{ proto array gmp_div_qr(resource a, resource b [, int round])
     853             :    Divide a by b, returns quotient and reminder */
     854          15 : ZEND_FUNCTION(gmp_div_qr)
     855             : {
     856             :         zval **a_arg, **b_arg;
     857          15 :         long round = GMP_ROUND_ZERO;
     858             : 
     859          15 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|l", &a_arg, &b_arg, &round) == FAILURE) {
     860           2 :                 return;
     861             :         }
     862             : 
     863          13 :         switch (round) {
     864             :         case GMP_ROUND_ZERO:
     865           8 :                 gmp_zval_binary_ui_op2_ex(return_value, a_arg, b_arg, mpz_tdiv_qr, (gmp_binary_ui_op2_t)mpz_tdiv_qr_ui, 0, 1 TSRMLS_CC);
     866           8 :                 break;
     867             :         case GMP_ROUND_PLUSINF:
     868           2 :                 gmp_zval_binary_ui_op2_ex(return_value, a_arg, b_arg, mpz_cdiv_qr, (gmp_binary_ui_op2_t)mpz_cdiv_qr_ui, 0, 1 TSRMLS_CC);
     869           2 :                 break;
     870             :         case GMP_ROUND_MINUSINF:
     871           2 :                 gmp_zval_binary_ui_op2_ex(return_value, a_arg, b_arg, mpz_fdiv_qr, (gmp_binary_ui_op2_t)mpz_fdiv_qr_ui, 0, 1 TSRMLS_CC);
     872             :                 break;
     873             :         }
     874             :                                                            
     875             : }
     876             : /* }}} */
     877             : 
     878             : /* {{{ proto resource gmp_div_r(resource a, resource b [, int round])
     879             :    Divide a by b, returns reminder only */
     880          14 : ZEND_FUNCTION(gmp_div_r)
     881             : {
     882             :         zval **a_arg, **b_arg;
     883          14 :         long round = GMP_ROUND_ZERO;
     884             : 
     885          14 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|l", &a_arg, &b_arg, &round) == FAILURE) {
     886           2 :                 return;
     887             :         }
     888             : 
     889          12 :         switch (round) {
     890             :         case GMP_ROUND_ZERO:
     891           7 :                 gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_tdiv_r, (gmp_binary_ui_op_t)mpz_tdiv_r_ui, 1, 1, 1 TSRMLS_CC);
     892           7 :                 break;
     893             :         case GMP_ROUND_PLUSINF:
     894           2 :                 gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_cdiv_r, (gmp_binary_ui_op_t)mpz_cdiv_r_ui, 1, 1, 1 TSRMLS_CC);
     895           2 :                 break;
     896             :         case GMP_ROUND_MINUSINF:
     897           2 :                 gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_fdiv_r, (gmp_binary_ui_op_t)mpz_fdiv_r_ui, 1, 1, 1 TSRMLS_CC);
     898             :                 break;
     899             :         }
     900             : }
     901             : /* }}} */
     902             : 
     903             : /* {{{ proto resource gmp_div_q(resource a, resource b [, int round])
     904             :    Divide a by b, returns quotient only */
     905          15 : ZEND_FUNCTION(gmp_div_q)
     906             : {
     907             :         zval **a_arg, **b_arg;
     908          15 :         long round = GMP_ROUND_ZERO;
     909             : 
     910          15 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|l", &a_arg, &b_arg, &round) == FAILURE) {
     911           2 :                 return;
     912             :         }
     913             : 
     914          13 :         switch (round) {
     915             :         case GMP_ROUND_ZERO:
     916           8 :                 gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_tdiv_q, (gmp_binary_ui_op_t)mpz_tdiv_q_ui, 0, 1, 1 TSRMLS_CC);
     917           8 :                 break;
     918             :         case GMP_ROUND_PLUSINF:
     919           2 :                 gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_cdiv_q, (gmp_binary_ui_op_t)mpz_cdiv_q_ui, 0, 1, 1 TSRMLS_CC);
     920           2 :                 break;
     921             :         case GMP_ROUND_MINUSINF:
     922           2 :                 gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_fdiv_q, (gmp_binary_ui_op_t)mpz_fdiv_q_ui, 0, 1, 1 TSRMLS_CC);
     923             :                 break;
     924             :         }
     925             :                                                            
     926             : }
     927             : /* }}} */
     928             : 
     929             : /* {{{ proto resource gmp_mod(resource a, resource b)
     930             :    Computes a modulo b */
     931          26 : ZEND_FUNCTION(gmp_mod)
     932             : {
     933             :         zval **a_arg, **b_arg;
     934             : 
     935          26 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
     936           2 :                 return;
     937             :         }       
     938             : 
     939          24 :         gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_mod, (gmp_binary_ui_op_t)mpz_mod_ui, 1, 1, 0 TSRMLS_CC);
     940             : }
     941             : /* }}} */
     942             : 
     943             : /* {{{ proto resource gmp_divexact(resource a, resource b)
     944             :    Divide a by b using exact division algorithm */
     945           9 : ZEND_FUNCTION(gmp_divexact)
     946             : {
     947             :         zval **a_arg, **b_arg;
     948             : 
     949           9 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
     950           2 :                 return;
     951             :         }
     952             :         
     953           7 :         gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_divexact, NULL, 0, 1, 1 TSRMLS_CC);
     954             : }
     955             : /* }}} */
     956             : 
     957             : /* {{{ proto resource gmp_neg(resource a)
     958             :    Negates a number */
     959          11 : ZEND_FUNCTION(gmp_neg)
     960             : {
     961          11 :         gmp_unary_op(mpz_neg);
     962          11 : }
     963             : /* }}} */
     964             : 
     965             : /* {{{ proto resource gmp_abs(resource a)
     966             :    Calculates absolute value */
     967          12 : ZEND_FUNCTION(gmp_abs)
     968             : {
     969          12 :         gmp_unary_op(mpz_abs);
     970          12 : }
     971             : /* }}} */
     972             : 
     973             : /* {{{ proto resource gmp_fact(int a)
     974             :    Calculates factorial function */
     975          16 : ZEND_FUNCTION(gmp_fact)
     976             : {
     977             :         zval **a_arg;
     978             :         mpz_t *gmpnum_tmp;
     979             :         int temp_a;
     980             : 
     981          16 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
     982           2 :                 return;
     983             :         }
     984             : 
     985          14 :         if (Z_TYPE_PP(a_arg) == IS_RESOURCE) {
     986           2 :                 FETCH_GMP_ZVAL(gmpnum_tmp, a_arg, temp_a);      /* no need to free this since it's IS_RESOURCE */
     987           2 :                 if (mpz_sgn(*gmpnum_tmp) < 0) {
     988           1 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0");
     989           1 :                         RETURN_FALSE;
     990             :                 }
     991             :         } else {
     992          39 :                 convert_to_long_ex(a_arg);
     993          12 :                 if (Z_LVAL_PP(a_arg) < 0) {
     994           2 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0");
     995           2 :                         RETURN_FALSE;
     996             :                 }
     997             :         }
     998             :                 
     999          11 :         gmp_zval_unary_ui_op(return_value, a_arg, mpz_fac_ui TSRMLS_CC);
    1000             : }
    1001             : /* }}} */
    1002             : 
    1003             : /* {{{ proto resource gmp_pow(resource base, int exp)
    1004             :    Raise base to power exp */
    1005          18 : ZEND_FUNCTION(gmp_pow)
    1006             : {
    1007             :         zval **base_arg;
    1008             :         mpz_t *gmpnum_result, *gmpnum_base;
    1009          18 :         int use_ui = 0;
    1010             :         int temp_base;
    1011             :         long exp;
    1012             : 
    1013          18 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &base_arg, &exp) == FAILURE) {
    1014           5 :                 return;
    1015             :         }
    1016             : 
    1017          17 :         if (Z_TYPE_PP(base_arg) == IS_LONG && Z_LVAL_PP(base_arg) >= 0) {
    1018           4 :                 use_ui = 1;
    1019             :         } else {
    1020           9 :                 FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base);
    1021             :         }
    1022             : 
    1023          12 :         if (exp < 0) {
    1024           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Negative exponent not supported");
    1025           2 :                 RETURN_FALSE;
    1026             :         }
    1027             :         
    1028          10 :         INIT_GMP_NUM(gmpnum_result);
    1029          10 :         if (use_ui) {
    1030           3 :                 mpz_ui_pow_ui(*gmpnum_result, Z_LVAL_PP(base_arg), exp);
    1031             :         } else {
    1032           7 :                 mpz_pow_ui(*gmpnum_result, *gmpnum_base, exp);
    1033           7 :                 FREE_GMP_TEMP(temp_base);
    1034             :         }
    1035          10 :         ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
    1036             : }
    1037             : /* }}} */
    1038             : 
    1039             : /* {{{ proto resource gmp_powm(resource base, resource exp, resource mod)
    1040             :    Raise base to power exp and take result modulo mod */
    1041          18 : ZEND_FUNCTION(gmp_powm)
    1042             : {
    1043             :         zval **base_arg, **exp_arg, **mod_arg;
    1044             :         mpz_t *gmpnum_base, *gmpnum_exp, *gmpnum_mod, *gmpnum_result;
    1045          18 :         int use_ui = 0;
    1046          18 :         int temp_base = 0, temp_exp = 0, temp_mod;
    1047             : 
    1048          18 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ", &base_arg, &exp_arg, &mod_arg) == FAILURE){
    1049           3 :                 return;
    1050             :         }
    1051             : 
    1052          15 :         FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base);
    1053             : 
    1054          20 :         if (Z_TYPE_PP(exp_arg) == IS_LONG && Z_LVAL_PP(exp_arg) >= 0) {
    1055           7 :                 use_ui = 1;
    1056             :         } else {
    1057           6 :                 FETCH_GMP_ZVAL(gmpnum_exp, exp_arg, temp_exp);
    1058           5 :                 if (mpz_sgn(*gmpnum_exp) < 0) {
    1059           1 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING,"Second parameter cannot be less than 0");
    1060           1 :                         RETURN_FALSE;
    1061             :                 }
    1062             :         }
    1063          11 :         FETCH_GMP_ZVAL(gmpnum_mod, mod_arg, temp_mod);
    1064             : 
    1065          10 :         if (!mpz_cmp_ui(*gmpnum_mod, 0)) {
    1066           0 :                 FREE_GMP_TEMP(temp_base);
    1067           0 :                 if (use_ui) {
    1068           0 :                         FREE_GMP_TEMP(temp_exp);
    1069             :                 }
    1070           0 :                 FREE_GMP_TEMP(temp_mod);
    1071           0 :                 RETURN_FALSE;
    1072             :         }
    1073             : 
    1074          10 :         INIT_GMP_NUM(gmpnum_result);
    1075          10 :         if (use_ui) {
    1076           7 :                 mpz_powm_ui(*gmpnum_result, *gmpnum_base, (unsigned long)Z_LVAL_PP(exp_arg), *gmpnum_mod);
    1077             :         } else {
    1078           3 :                 mpz_powm(*gmpnum_result, *gmpnum_base, *gmpnum_exp, *gmpnum_mod);
    1079           3 :                 FREE_GMP_TEMP(temp_exp);
    1080             :         }
    1081             : 
    1082          10 :         FREE_GMP_TEMP(temp_base);
    1083          10 :         FREE_GMP_TEMP(temp_mod);
    1084             : 
    1085          10 :         ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
    1086             : 
    1087             : }
    1088             : /* }}} */
    1089             : 
    1090             : /* {{{ proto resource gmp_sqrt(resource a)
    1091             :    Takes integer part of square root of a */
    1092          11 : ZEND_FUNCTION(gmp_sqrt)
    1093             : {
    1094             :         zval **a_arg;
    1095             :         mpz_t *gmpnum_a, *gmpnum_result;
    1096             :         int temp_a;
    1097             : 
    1098          11 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
    1099           2 :                 return;
    1100             :         }
    1101             :         
    1102           9 :         FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
    1103             : 
    1104           8 :         if (mpz_sgn(*gmpnum_a) < 0) {
    1105           3 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0");
    1106           3 :                 FREE_GMP_TEMP(temp_a);
    1107           3 :                 RETURN_FALSE;
    1108             :         }       
    1109             :         
    1110           5 :         INIT_GMP_NUM(gmpnum_result);
    1111           5 :         mpz_sqrt(*gmpnum_result, *gmpnum_a);
    1112           5 :         FREE_GMP_TEMP(temp_a);
    1113             : 
    1114           5 :         ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
    1115             : }
    1116             : /* }}} */
    1117             : 
    1118             : /* {{{ proto array gmp_sqrtrem(resource a)
    1119             :    Square root with remainder */
    1120          13 : ZEND_FUNCTION(gmp_sqrtrem)
    1121             : {
    1122             :         zval **a_arg;
    1123             :         mpz_t *gmpnum_a, *gmpnum_result1, *gmpnum_result2;
    1124             :         zval r;
    1125             :         int temp_a;
    1126             : 
    1127          13 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
    1128           1 :                 return;
    1129             :         }
    1130             : 
    1131          12 :         FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
    1132             :         
    1133          11 :         if (mpz_sgn(*gmpnum_a) < 0) {
    1134           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Number has to be greater than or equal to 0");
    1135           2 :                 RETURN_FALSE;
    1136             :         }
    1137             :         
    1138           9 :         INIT_GMP_NUM(gmpnum_result1);
    1139           9 :         INIT_GMP_NUM(gmpnum_result2);
    1140             : 
    1141           9 :         mpz_sqrtrem(*gmpnum_result1, *gmpnum_result2, *gmpnum_a);
    1142           9 :         FREE_GMP_TEMP(temp_a);
    1143             : 
    1144           9 :         array_init(return_value);
    1145           9 :         ZEND_REGISTER_RESOURCE(&r, gmpnum_result1, le_gmp);
    1146           9 :         add_index_resource(return_value, 0, Z_LVAL(r));
    1147           9 :         ZEND_REGISTER_RESOURCE(&r, gmpnum_result2, le_gmp);
    1148           9 :         add_index_resource(return_value, 1, Z_LVAL(r));
    1149             : }
    1150             : /* }}} */
    1151             : 
    1152             : /* {{{ proto bool gmp_perfect_square(resource a)
    1153             :    Checks if a is an exact square */
    1154          13 : ZEND_FUNCTION(gmp_perfect_square)
    1155             : {
    1156             :         zval **a_arg;
    1157             :         mpz_t *gmpnum_a;
    1158             :         int temp_a;
    1159             : 
    1160          13 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
    1161           1 :                 return;
    1162             :         }
    1163             : 
    1164          12 :         FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
    1165             : 
    1166          11 :         RETVAL_BOOL((mpz_perfect_square_p(*gmpnum_a)!=0));
    1167          11 :         FREE_GMP_TEMP(temp_a);
    1168             : }
    1169             : /* }}} */
    1170             : 
    1171             : /* {{{ proto int gmp_prob_prime(resource a[, int reps])
    1172             :    Checks if a is "probably prime" */
    1173          40 : ZEND_FUNCTION(gmp_prob_prime)
    1174             : {
    1175             :         zval **gmpnumber_arg;
    1176             :         mpz_t *gmpnum_a;
    1177          40 :         long reps = 10;
    1178             :         int temp_a;
    1179             : 
    1180          40 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &gmpnumber_arg, &reps) == FAILURE) {
    1181           1 :                 return;
    1182             :         }
    1183             : 
    1184          39 :         FETCH_GMP_ZVAL(gmpnum_a, gmpnumber_arg, temp_a);
    1185             : 
    1186          38 :         RETVAL_LONG(mpz_probab_prime_p(*gmpnum_a, reps));
    1187          38 :         FREE_GMP_TEMP(temp_a);
    1188             : }
    1189             : /* }}} */
    1190             : 
    1191             : /* {{{ proto resource gmp_gcd(resource a, resource b)
    1192             :    Computes greatest common denominator (gcd) of a and b */
    1193          14 : ZEND_FUNCTION(gmp_gcd)
    1194             : {
    1195             :         zval **a_arg, **b_arg;
    1196             : 
    1197          14 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
    1198           3 :                 return;
    1199             :         }
    1200             : 
    1201          11 :         gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_gcd, (gmp_binary_ui_op_t)mpz_gcd_ui, 0, 0, 1 TSRMLS_CC);
    1202             : }
    1203             : /* }}} */
    1204             : 
    1205             : /* {{{ proto array gmp_gcdext(resource a, resource b)
    1206             :    Computes G, S, and T, such that AS + BT = G = `gcd' (A, B) */
    1207          15 : ZEND_FUNCTION(gmp_gcdext)
    1208             : {
    1209             :         zval **a_arg, **b_arg;
    1210             :         mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_t, *gmpnum_s, *gmpnum_g;
    1211             :         zval r;
    1212             :         int temp_a, temp_b;
    1213             : 
    1214          15 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
    1215           3 :                 return;
    1216             :         }
    1217             : 
    1218          12 :         FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
    1219          11 :         FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b);
    1220             : 
    1221          10 :         INIT_GMP_NUM(gmpnum_g);
    1222          10 :         INIT_GMP_NUM(gmpnum_s);
    1223          10 :         INIT_GMP_NUM(gmpnum_t);
    1224             : 
    1225          10 :         mpz_gcdext(*gmpnum_g, *gmpnum_s, *gmpnum_t, *gmpnum_a, *gmpnum_b);
    1226          10 :         FREE_GMP_TEMP(temp_a);
    1227          10 :         FREE_GMP_TEMP(temp_b);
    1228             : 
    1229          10 :         array_init(return_value);
    1230             : 
    1231          10 :         ZEND_REGISTER_RESOURCE(&r, gmpnum_g, le_gmp);
    1232          10 :         add_assoc_resource(return_value, "g", Z_LVAL(r));
    1233          10 :         ZEND_REGISTER_RESOURCE(&r, gmpnum_s, le_gmp);
    1234          10 :         add_assoc_resource(return_value, "s", Z_LVAL(r));
    1235          10 :         ZEND_REGISTER_RESOURCE(&r, gmpnum_t, le_gmp);
    1236          10 :         add_assoc_resource(return_value, "t", Z_LVAL(r));
    1237             : }
    1238             : /* }}} */
    1239             : 
    1240             : /* {{{ proto resource gmp_invert(resource a, resource b)
    1241             :    Computes the inverse of a modulo b */
    1242          14 : ZEND_FUNCTION(gmp_invert)
    1243             : {
    1244             :         zval **a_arg, **b_arg;
    1245             :         mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result;
    1246             :         int temp_a, temp_b;
    1247             :         int res;
    1248             : 
    1249          14 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
    1250           2 :                 return;
    1251             :         }
    1252             : 
    1253          12 :         FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
    1254          10 :         FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b);
    1255             : 
    1256           9 :         INIT_GMP_NUM(gmpnum_result);
    1257           9 :         res=mpz_invert(*gmpnum_result, *gmpnum_a, *gmpnum_b);
    1258           9 :         FREE_GMP_TEMP(temp_a);
    1259           9 :         FREE_GMP_TEMP(temp_b);
    1260           9 :         if (res) {
    1261           4 :                 ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
    1262             :         } else {
    1263           5 :                 FREE_GMP_NUM(gmpnum_result);
    1264           5 :                 RETURN_FALSE;
    1265             :         }
    1266             : }
    1267             : /* }}} */
    1268             : 
    1269             : /* {{{ proto int gmp_jacobi(resource a, resource b)
    1270             :    Computes Jacobi symbol */
    1271          23 : ZEND_FUNCTION(gmp_jacobi)
    1272             : {
    1273          23 :         gmp_binary_opl(mpz_jacobi);
    1274          23 : }
    1275             : /* }}} */
    1276             : 
    1277             : /* {{{ proto int gmp_legendre(resource a, resource b)
    1278             :    Computes Legendre symbol */
    1279          23 : ZEND_FUNCTION(gmp_legendre)
    1280             : {
    1281          23 :         gmp_binary_opl(mpz_legendre);
    1282          23 : }
    1283             : /* }}} */
    1284             : 
    1285             : /* {{{ proto int gmp_cmp(resource a, resource b)
    1286             :    Compares two numbers */
    1287          12 : ZEND_FUNCTION(gmp_cmp)
    1288             : {
    1289             :         zval **a_arg, **b_arg;
    1290             :         mpz_t *gmpnum_a, *gmpnum_b;
    1291          12 :         int use_si = 0, res;
    1292             :         int temp_a, temp_b;
    1293             : 
    1294          12 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
    1295           3 :                 return;
    1296             :         }
    1297             : 
    1298           9 :         FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
    1299             : 
    1300           8 :         if (Z_TYPE_PP(b_arg) == IS_LONG) {
    1301           4 :                 use_si = 1;
    1302             :         } else {
    1303           4 :                 FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b);
    1304             :         }
    1305             : 
    1306           8 :         if (use_si) {
    1307           4 :                 res = mpz_cmp_si(*gmpnum_a, Z_LVAL_PP(b_arg));
    1308             :         } else {
    1309           4 :                 res = mpz_cmp(*gmpnum_a, *gmpnum_b);
    1310           4 :                 FREE_GMP_TEMP(temp_b);
    1311             :         }
    1312           8 :         FREE_GMP_TEMP(temp_a);
    1313             :         
    1314           8 :         RETURN_LONG(res);
    1315             : }
    1316             : /* }}} */
    1317             : 
    1318             : /* {{{ proto int gmp_sign(resource a)
    1319             :    Gets the sign of the number */
    1320          10 : ZEND_FUNCTION(gmp_sign)
    1321             : {
    1322             :         zval **a_arg;
    1323             :         mpz_t *gmpnum_a;
    1324             :         int temp_a;
    1325             : 
    1326          10 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
    1327           2 :                 return;
    1328             :         }
    1329             :         
    1330           8 :         FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
    1331             : 
    1332           6 :         RETVAL_LONG(mpz_sgn(*gmpnum_a));
    1333           6 :         FREE_GMP_TEMP(temp_a);
    1334             : }
    1335             : /* }}} */
    1336             : 
    1337             : /* {{{ proto resource gmp_random([int limiter])
    1338             :    Gets random number */
    1339          10 : ZEND_FUNCTION(gmp_random)
    1340             : {
    1341          10 :         long limiter = 20;
    1342             :         mpz_t *gmpnum_result;
    1343             : 
    1344          10 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &limiter) == FAILURE) {
    1345           4 :                 return;
    1346             :         }
    1347             : 
    1348           6 :         INIT_GMP_NUM(gmpnum_result);
    1349             : 
    1350           6 :         if (!GMPG(rand_initialized)) {
    1351             :                 /* Initialize */
    1352           1 :                 gmp_randinit_lc_2exp_size(GMPG(rand_state), 32L);
    1353             : 
    1354             :                 /* Seed */
    1355           1 :                 gmp_randseed_ui(GMPG(rand_state), GENERATE_SEED());
    1356             : 
    1357           1 :                 GMPG(rand_initialized) = 1;
    1358             :         }
    1359             : #ifdef GMP_LIMB_BITS
    1360           6 :         mpz_urandomb(*gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * GMP_LIMB_BITS);
    1361             : #else
    1362             :         mpz_urandomb(*gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * __GMP_BITS_PER_MP_LIMB);
    1363             : #endif
    1364           6 :         ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
    1365             : }
    1366             : /* }}} */
    1367             : 
    1368             : /* {{{ proto resource gmp_and(resource a, resource b)
    1369             :    Calculates logical AND of a and b */
    1370          13 : ZEND_FUNCTION(gmp_and)
    1371             : {
    1372          13 :         gmp_binary_op(mpz_and);
    1373          13 : }
    1374             : /* }}} */
    1375             : 
    1376             : /* {{{ proto resource gmp_or(resource a, resource b)
    1377             :    Calculates logical OR of a and b */
    1378          13 : ZEND_FUNCTION(gmp_or)
    1379             : {
    1380          13 :         gmp_binary_op(mpz_ior);
    1381          13 : }
    1382             : /* }}} */
    1383             : 
    1384             : /* {{{ proto resource gmp_com(resource a)
    1385             :    Calculates one's complement of a */
    1386          11 : ZEND_FUNCTION(gmp_com)
    1387             : {
    1388          11 :         gmp_unary_op(mpz_com);
    1389          11 : }
    1390             : /* }}} */
    1391             : 
    1392             : /* {{{ proto resource gmp_nextprime(resource a)
    1393             :    Finds next prime of a */
    1394           8 : ZEND_FUNCTION(gmp_nextprime)
    1395             : {
    1396           8 :    gmp_unary_op(mpz_nextprime);
    1397           8 : }
    1398             : /* }}} */
    1399             : 
    1400             : /* {{{ proto resource gmp_xor(resource a, resource b)
    1401             :    Calculates logical exclusive OR of a and b */
    1402          13 : ZEND_FUNCTION(gmp_xor)
    1403             : {
    1404             :         /* use formula: a^b = (a|b)&^(a&b) */
    1405             :         zval **a_arg, **b_arg;
    1406             :         mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result, *gmpnum_t;
    1407             :         int temp_a, temp_b;
    1408             : 
    1409          13 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
    1410           2 :                 return;
    1411             :         }
    1412             : 
    1413          11 :         FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
    1414           8 :         FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b);
    1415             : 
    1416           7 :         INIT_GMP_NUM(gmpnum_result);
    1417           7 :         INIT_GMP_NUM(gmpnum_t);
    1418             : 
    1419           7 :         mpz_and(*gmpnum_t, *gmpnum_a, *gmpnum_b);
    1420           7 :         mpz_com(*gmpnum_t, *gmpnum_t);
    1421             : 
    1422           7 :         mpz_ior(*gmpnum_result, *gmpnum_a, *gmpnum_b);
    1423           7 :         mpz_and(*gmpnum_result, *gmpnum_result, *gmpnum_t);
    1424             : 
    1425           7 :         FREE_GMP_NUM(gmpnum_t);
    1426             : 
    1427           7 :         FREE_GMP_TEMP(temp_a);
    1428           7 :         FREE_GMP_TEMP(temp_b);
    1429           7 :         ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
    1430             : }
    1431             : /* }}} */
    1432             : 
    1433             : /* {{{ proto void gmp_setbit(resource &a, int index[, bool set_clear])
    1434             :    Sets or clear bit in a */
    1435          15 : ZEND_FUNCTION(gmp_setbit)
    1436             : {
    1437             :         zval **a_arg;
    1438             :         long index;
    1439          15 :         zend_bool set = 1;
    1440             :         mpz_t *gmpnum_a;
    1441             : 
    1442          15 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl|b", &a_arg, &index, &set) == FAILURE) {
    1443           4 :                 return;
    1444             :         }
    1445             : 
    1446          11 :         ZEND_FETCH_RESOURCE(gmpnum_a, mpz_t *, a_arg, -1, GMP_RESOURCE_NAME, le_gmp);
    1447             : 
    1448          10 :         if (index < 0) {
    1449           1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero");
    1450           1 :                 return;
    1451             :         }
    1452             : 
    1453           9 :         if (set) {
    1454           7 :                 mpz_setbit(*gmpnum_a, index);
    1455             :         } else {
    1456           2 :                 mpz_clrbit(*gmpnum_a, index);
    1457             :         }
    1458             : }
    1459             : /* }}} */
    1460             : 
    1461             : /* {{{ proto void gmp_clrbit(resource &a, int index)
    1462             :    Clears bit in a */
    1463          12 : ZEND_FUNCTION(gmp_clrbit)
    1464             : {
    1465             :         zval **a_arg;
    1466             :         long index;
    1467             :         mpz_t *gmpnum_a;
    1468             : 
    1469          12 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &index) == FAILURE){
    1470           3 :                 return;
    1471             :         }
    1472             : 
    1473           9 :         ZEND_FETCH_RESOURCE(gmpnum_a, mpz_t *, a_arg, -1, GMP_RESOURCE_NAME, le_gmp);
    1474             : 
    1475           8 :         if (index < 0) {
    1476           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero");
    1477           2 :                 return;
    1478             :         }
    1479             : 
    1480           6 :         mpz_clrbit(*gmpnum_a, index);
    1481             : }
    1482             : /* }}} */
    1483             : 
    1484             : /* {{{ proto bool gmp_testbit(resource a, int index)
    1485             :    Tests if bit is set in a */
    1486          12 : ZEND_FUNCTION(gmp_testbit)
    1487             : {
    1488             :         zval **a_arg;
    1489             :         long index;
    1490             :         mpz_t *gmpnum_a;
    1491             : 
    1492          12 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &index) == FAILURE){
    1493           0 :                 return;
    1494             :         }
    1495             : 
    1496          12 :         ZEND_FETCH_RESOURCE(gmpnum_a, mpz_t *, a_arg, -1, GMP_RESOURCE_NAME, le_gmp);
    1497             : 
    1498          12 :         if (index < 0) {
    1499           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero");
    1500           2 :                 RETURN_FALSE;
    1501             :         }
    1502             : 
    1503          10 :         if (mpz_tstbit(*gmpnum_a, index)) {
    1504           4 :                 RETURN_TRUE;
    1505             :         }
    1506             : 
    1507           6 :         RETURN_FALSE;
    1508             : }
    1509             : /* }}} */
    1510             : 
    1511             : /* {{{ proto int gmp_popcount(resource a)
    1512             :    Calculates the population count of a */
    1513           8 : ZEND_FUNCTION(gmp_popcount)
    1514             : {
    1515             :         zval **a_arg;
    1516             :         mpz_t *gmpnum_a;
    1517             :         int temp_a;
    1518             : 
    1519           8 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
    1520           1 :                 return;
    1521             :         }
    1522             :         
    1523           7 :         FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
    1524             : 
    1525           6 :         RETVAL_LONG(mpz_popcount(*gmpnum_a));
    1526           6 :         FREE_GMP_TEMP(temp_a);
    1527             : }
    1528             : /* }}} */
    1529             : 
    1530             : /* {{{ proto int gmp_hamdist(resource a, resource b)
    1531             :    Calculates hamming distance between a and b */
    1532          12 : ZEND_FUNCTION(gmp_hamdist)
    1533             : {
    1534             :         zval **a_arg, **b_arg;
    1535             :         mpz_t *gmpnum_a, *gmpnum_b;
    1536             :         int temp_a, temp_b;
    1537             : 
    1538          12 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
    1539           2 :                 return;
    1540             :         }
    1541             : 
    1542          10 :         FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
    1543           8 :         FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b);
    1544             : 
    1545           7 :         RETVAL_LONG(mpz_hamdist(*gmpnum_a, *gmpnum_b));
    1546           7 :         FREE_GMP_TEMP(temp_a);
    1547           7 :         FREE_GMP_TEMP(temp_b);
    1548             : }
    1549             : /* }}} */
    1550             : 
    1551             : /* {{{ proto int gmp_scan0(resource a, int start)
    1552             :    Finds first zero bit */
    1553           9 : ZEND_FUNCTION(gmp_scan0)
    1554             : {
    1555             :         zval **a_arg;
    1556             :         mpz_t *gmpnum_a;
    1557             :         int temp_a;
    1558             :         long start;
    1559             : 
    1560           9 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &start) == FAILURE){
    1561           2 :                 return;
    1562             :         }
    1563             : 
    1564           7 :         FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
    1565             : 
    1566           6 :         if (start < 0) {
    1567           1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Starting index must be greater than or equal to zero");
    1568           1 :                 RETURN_FALSE;
    1569             :         }
    1570             : 
    1571           5 :         RETVAL_LONG(mpz_scan0(*gmpnum_a, start));
    1572           5 :         FREE_GMP_TEMP(temp_a);
    1573             : }
    1574             : /* }}} */
    1575             : 
    1576             : /* {{{ proto int gmp_scan1(resource a, int start)
    1577             :    Finds first non-zero bit */
    1578           9 : ZEND_FUNCTION(gmp_scan1)
    1579             : {
    1580             :         zval **a_arg;
    1581             :         mpz_t *gmpnum_a;
    1582             :         int temp_a;
    1583             :         long start;
    1584             : 
    1585           9 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &start) == FAILURE){
    1586           2 :                 return;
    1587             :         }
    1588             : 
    1589           7 :         FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
    1590           6 :         if (start < 0) {
    1591           1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Starting index must be greater than or equal to zero");
    1592           1 :                 RETURN_FALSE;
    1593             :         }
    1594             : 
    1595           5 :         RETVAL_LONG(mpz_scan1(*gmpnum_a, start));
    1596           5 :         FREE_GMP_TEMP(temp_a);
    1597             : }
    1598             : /* }}} */
    1599             : 
    1600             : /* {{{ _php_gmpnum_free
    1601             :  */
    1602        2746 : static void _php_gmpnum_free(zend_rsrc_list_entry *rsrc TSRMLS_DC)
    1603             : {
    1604        2746 :         mpz_t *gmpnum = (mpz_t *)rsrc->ptr;
    1605             : 
    1606        2746 :         FREE_GMP_NUM(gmpnum);
    1607        2746 : }
    1608             : /* }}} */
    1609             : 
    1610             : #endif  /* HAVE_GMP */
    1611             : 
    1612             : /*
    1613             :  * Local variables:
    1614             :  * tab-width: 4
    1615             :  * c-basic-offset: 4
    1616             :  * End:
    1617             :  * vim600: noet sw=4 ts=4 fdm=marker
    1618             :  * vim<600: noet sw=4 ts=4
    1619             :  */

Generated by: LCOV version 1.10

Generated at Mon, 29 Jun 2015 08:36:50 +0000 (5 days ago)

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