Back to index

php5  5.3.10
gmp.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Stanislav Malyshev <stas@php.net>                            |
00016    +----------------------------------------------------------------------+
00017  */
00018 
00019 #ifdef HAVE_CONFIG_H
00020 #include "config.h"
00021 #endif
00022 
00023 #include "php.h"
00024 #include "php_ini.h"
00025 #include "php_gmp.h"
00026 #include "ext/standard/info.h"
00027 
00028 #if HAVE_GMP
00029 
00030 #include <gmp.h>
00031 
00032 /* Needed for gmp_random() */
00033 #include "ext/standard/php_rand.h"
00034 #include "ext/standard/php_lcg.h"
00035 #define GMP_ABS(x) ((x) >= 0 ? (x) : -(x))
00036 
00037 /* True global resources - no need for thread safety here */
00038 static int le_gmp;
00039 
00040 /* {{{ arginfo */
00041 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_init, 0, 0, 1)
00042        ZEND_ARG_INFO(0, number)
00043        ZEND_ARG_INFO(0, base)
00044 ZEND_END_ARG_INFO()
00045 
00046 ZEND_BEGIN_ARG_INFO(arginfo_gmp_intval, 0)
00047        ZEND_ARG_INFO(0, gmpnumber)
00048 ZEND_END_ARG_INFO()
00049 
00050 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_strval, 0, 0, 1)
00051        ZEND_ARG_INFO(0, gmpnumber)
00052        ZEND_ARG_INFO(0, base)
00053 ZEND_END_ARG_INFO()
00054 
00055 ZEND_BEGIN_ARG_INFO(arginfo_gmp_add, 0)
00056        ZEND_ARG_INFO(0, a)
00057        ZEND_ARG_INFO(0, b)
00058 ZEND_END_ARG_INFO()
00059 
00060 ZEND_BEGIN_ARG_INFO(arginfo_gmp_sub, 0)
00061        ZEND_ARG_INFO(0, a)
00062        ZEND_ARG_INFO(0, b)
00063 ZEND_END_ARG_INFO()
00064 
00065 ZEND_BEGIN_ARG_INFO(arginfo_gmp_mul, 0)
00066        ZEND_ARG_INFO(0, a)
00067        ZEND_ARG_INFO(0, b)
00068 ZEND_END_ARG_INFO()
00069 
00070 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_div_qr, 0, 0, 2)
00071        ZEND_ARG_INFO(0, a)
00072        ZEND_ARG_INFO(0, b)
00073        ZEND_ARG_INFO(0, round)
00074 ZEND_END_ARG_INFO()
00075 
00076 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_div_r, 0, 0, 2)
00077        ZEND_ARG_INFO(0, a)
00078        ZEND_ARG_INFO(0, b)
00079        ZEND_ARG_INFO(0, round)
00080 ZEND_END_ARG_INFO()
00081 
00082 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_div_q, 0, 0, 2)
00083        ZEND_ARG_INFO(0, a)
00084        ZEND_ARG_INFO(0, b)
00085        ZEND_ARG_INFO(0, round)
00086 ZEND_END_ARG_INFO()
00087 
00088 ZEND_BEGIN_ARG_INFO(arginfo_gmp_mod, 0)
00089        ZEND_ARG_INFO(0, a)
00090        ZEND_ARG_INFO(0, b)
00091 ZEND_END_ARG_INFO()
00092 
00093 ZEND_BEGIN_ARG_INFO(arginfo_gmp_divexact, 0)
00094        ZEND_ARG_INFO(0, a)
00095        ZEND_ARG_INFO(0, b)
00096 ZEND_END_ARG_INFO()
00097 
00098 ZEND_BEGIN_ARG_INFO(arginfo_gmp_neg, 0)
00099        ZEND_ARG_INFO(0, a)
00100 ZEND_END_ARG_INFO()
00101 
00102 ZEND_BEGIN_ARG_INFO(arginfo_gmp_abs, 0)
00103        ZEND_ARG_INFO(0, a)
00104 ZEND_END_ARG_INFO()
00105 
00106 ZEND_BEGIN_ARG_INFO(arginfo_gmp_fact, 0)
00107        ZEND_ARG_INFO(0, a)
00108 ZEND_END_ARG_INFO()
00109 
00110 ZEND_BEGIN_ARG_INFO(arginfo_gmp_pow, 0)
00111        ZEND_ARG_INFO(0, base)
00112        ZEND_ARG_INFO(0, exp)
00113 ZEND_END_ARG_INFO()
00114 
00115 ZEND_BEGIN_ARG_INFO(arginfo_gmp_powm, 0)
00116        ZEND_ARG_INFO(0, base)
00117        ZEND_ARG_INFO(0, exp)
00118        ZEND_ARG_INFO(0, mod)
00119 ZEND_END_ARG_INFO()
00120 
00121 ZEND_BEGIN_ARG_INFO(arginfo_gmp_sqrt, 0)
00122        ZEND_ARG_INFO(0, a)
00123 ZEND_END_ARG_INFO()
00124 
00125 ZEND_BEGIN_ARG_INFO(arginfo_gmp_sqrtrem, 0)
00126        ZEND_ARG_INFO(0, a)
00127 ZEND_END_ARG_INFO()
00128 
00129 ZEND_BEGIN_ARG_INFO(arginfo_gmp_perfect_square, 0)
00130        ZEND_ARG_INFO(0, a)
00131 ZEND_END_ARG_INFO()
00132 
00133 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_prob_prime, 0, 0, 1)
00134        ZEND_ARG_INFO(0, a)
00135        ZEND_ARG_INFO(0, reps)
00136 ZEND_END_ARG_INFO()
00137 
00138 ZEND_BEGIN_ARG_INFO(arginfo_gmp_gcd, 0)
00139        ZEND_ARG_INFO(0, a)
00140        ZEND_ARG_INFO(0, b)
00141 ZEND_END_ARG_INFO()
00142 
00143 ZEND_BEGIN_ARG_INFO(arginfo_gmp_gcdext, 0)
00144        ZEND_ARG_INFO(0, a)
00145        ZEND_ARG_INFO(0, b)
00146 ZEND_END_ARG_INFO()
00147 
00148 ZEND_BEGIN_ARG_INFO(arginfo_gmp_invert, 0)
00149        ZEND_ARG_INFO(0, a)
00150        ZEND_ARG_INFO(0, b)
00151 ZEND_END_ARG_INFO()
00152 
00153 ZEND_BEGIN_ARG_INFO(arginfo_gmp_jacobi, 0)
00154        ZEND_ARG_INFO(0, a)
00155        ZEND_ARG_INFO(0, b)
00156 ZEND_END_ARG_INFO()
00157 
00158 ZEND_BEGIN_ARG_INFO(arginfo_gmp_legendre, 0)
00159        ZEND_ARG_INFO(0, a)
00160        ZEND_ARG_INFO(0, b)
00161 ZEND_END_ARG_INFO()
00162 
00163 ZEND_BEGIN_ARG_INFO(arginfo_gmp_cmp, 0)
00164        ZEND_ARG_INFO(0, a)
00165        ZEND_ARG_INFO(0, b)
00166 ZEND_END_ARG_INFO()
00167 
00168 ZEND_BEGIN_ARG_INFO(arginfo_gmp_sign, 0)
00169        ZEND_ARG_INFO(0, a)
00170 ZEND_END_ARG_INFO()
00171 
00172 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_random, 0, 0, 0)
00173        ZEND_ARG_INFO(0, limiter)
00174 ZEND_END_ARG_INFO()
00175 
00176 ZEND_BEGIN_ARG_INFO(arginfo_gmp_and, 0)
00177        ZEND_ARG_INFO(0, a)
00178        ZEND_ARG_INFO(0, b)
00179 ZEND_END_ARG_INFO()
00180 
00181 ZEND_BEGIN_ARG_INFO(arginfo_gmp_or, 0)
00182        ZEND_ARG_INFO(0, a)
00183        ZEND_ARG_INFO(0, b)
00184 ZEND_END_ARG_INFO()
00185 
00186 ZEND_BEGIN_ARG_INFO(arginfo_gmp_com, 0)
00187        ZEND_ARG_INFO(0, a)
00188 ZEND_END_ARG_INFO()
00189 
00190 ZEND_BEGIN_ARG_INFO(arginfo_gmp_xor, 0)
00191        ZEND_ARG_INFO(0, a)
00192        ZEND_ARG_INFO(0, b)
00193 ZEND_END_ARG_INFO()
00194 
00195 ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_setbit, 0, 0, 2)
00196        ZEND_ARG_INFO(1, a)
00197        ZEND_ARG_INFO(0, index)
00198        ZEND_ARG_INFO(0, set_clear)
00199 ZEND_END_ARG_INFO()
00200 
00201 ZEND_BEGIN_ARG_INFO(arginfo_gmp_clrbit, 0)
00202        ZEND_ARG_INFO(1, a)
00203        ZEND_ARG_INFO(0, index)
00204 ZEND_END_ARG_INFO()
00205 
00206 ZEND_BEGIN_ARG_INFO(arginfo_gmp_testbit, 0)
00207        ZEND_ARG_INFO(0, a)
00208        ZEND_ARG_INFO(0, index)
00209 ZEND_END_ARG_INFO()
00210 
00211 ZEND_BEGIN_ARG_INFO(arginfo_gmp_popcount, 0)
00212        ZEND_ARG_INFO(0, a)
00213 ZEND_END_ARG_INFO()
00214 
00215 ZEND_BEGIN_ARG_INFO(arginfo_gmp_hamdist, 0)
00216        ZEND_ARG_INFO(0, a)
00217        ZEND_ARG_INFO(0, b)
00218 ZEND_END_ARG_INFO()
00219 
00220 ZEND_BEGIN_ARG_INFO(arginfo_gmp_scan0, 0)
00221        ZEND_ARG_INFO(0, a)
00222        ZEND_ARG_INFO(0, start)
00223 ZEND_END_ARG_INFO()
00224 
00225 ZEND_BEGIN_ARG_INFO(arginfo_gmp_scan1, 0)
00226        ZEND_ARG_INFO(0, a)
00227        ZEND_ARG_INFO(0, start)
00228 ZEND_END_ARG_INFO()
00229 
00230 ZEND_BEGIN_ARG_INFO(arginfo_gmp_nextprime, 0)
00231        ZEND_ARG_INFO(0, a)
00232 ZEND_END_ARG_INFO()
00233 
00234 /* }}} */
00235 
00236 ZEND_DECLARE_MODULE_GLOBALS(gmp)
00237 static ZEND_GINIT_FUNCTION(gmp);
00238 
00239 /* {{{ gmp_functions[]
00240  */
00241 const zend_function_entry gmp_functions[] = {
00242        ZEND_FE(gmp_init,    arginfo_gmp_init)
00243        ZEND_FE(gmp_intval,  arginfo_gmp_intval)
00244        ZEND_FE(gmp_strval,  arginfo_gmp_strval)
00245        ZEND_FE(gmp_add,         arginfo_gmp_add)
00246        ZEND_FE(gmp_sub,         arginfo_gmp_sub)
00247        ZEND_FE(gmp_mul,         arginfo_gmp_mul)
00248        ZEND_FE(gmp_div_qr,  arginfo_gmp_div_qr)
00249        ZEND_FE(gmp_div_q,   arginfo_gmp_div_q)
00250        ZEND_FE(gmp_div_r,   arginfo_gmp_div_r)
00251        ZEND_FALIAS(gmp_div, gmp_div_q, arginfo_gmp_div_q)
00252        ZEND_FE(gmp_mod,     arginfo_gmp_mod)
00253        ZEND_FE(gmp_divexact,       arginfo_gmp_divexact)
00254        ZEND_FE(gmp_neg,     arginfo_gmp_neg)
00255        ZEND_FE(gmp_abs,     arginfo_gmp_abs)
00256        ZEND_FE(gmp_fact,    arginfo_gmp_fact)
00257        ZEND_FE(gmp_sqrt,    arginfo_gmp_sqrt)
00258        ZEND_FE(gmp_sqrtrem, arginfo_gmp_sqrtrem)
00259        ZEND_FE(gmp_pow,     arginfo_gmp_pow)
00260        ZEND_FE(gmp_powm,    arginfo_gmp_powm)
00261        ZEND_FE(gmp_perfect_square, arginfo_gmp_perfect_square)
00262        ZEND_FE(gmp_prob_prime,     arginfo_gmp_prob_prime)
00263        ZEND_FE(gmp_gcd,     arginfo_gmp_gcd)
00264        ZEND_FE(gmp_gcdext,  arginfo_gmp_gcdext)
00265        ZEND_FE(gmp_invert,  arginfo_gmp_invert)
00266        ZEND_FE(gmp_jacobi,  arginfo_gmp_jacobi)
00267        ZEND_FE(gmp_legendre,       arginfo_gmp_legendre)
00268        ZEND_FE(gmp_cmp,     arginfo_gmp_cmp)
00269        ZEND_FE(gmp_sign,    arginfo_gmp_sign)
00270        ZEND_FE(gmp_random,  arginfo_gmp_random)
00271        ZEND_FE(gmp_and,     arginfo_gmp_and)
00272        ZEND_FE(gmp_or,      arginfo_gmp_or)
00273        ZEND_FE(gmp_com,     arginfo_gmp_com)
00274        ZEND_FE(gmp_xor,     arginfo_gmp_xor)
00275        ZEND_FE(gmp_setbit,  arginfo_gmp_setbit)
00276        ZEND_FE(gmp_clrbit,  arginfo_gmp_clrbit)
00277        ZEND_FE(gmp_scan0,  arginfo_gmp_scan0)
00278        ZEND_FE(gmp_scan1,  arginfo_gmp_scan1)
00279        ZEND_FE(gmp_testbit,arginfo_gmp_testbit)
00280        ZEND_FE(gmp_popcount, arginfo_gmp_popcount)
00281        ZEND_FE(gmp_hamdist, arginfo_gmp_hamdist)
00282        ZEND_FE(gmp_nextprime, arginfo_gmp_nextprime)
00283        PHP_FE_END
00284 };
00285 /* }}} */
00286 
00287 /* {{{ gmp_module_entry
00288  */
00289 zend_module_entry gmp_module_entry = {
00290        STANDARD_MODULE_HEADER,
00291        "gmp",
00292        gmp_functions,
00293        ZEND_MODULE_STARTUP_N(gmp),
00294        NULL,
00295        NULL,
00296        ZEND_MODULE_DEACTIVATE_N(gmp),
00297        ZEND_MODULE_INFO_N(gmp),
00298        NO_VERSION_YET,
00299        ZEND_MODULE_GLOBALS(gmp),
00300        ZEND_GINIT(gmp),
00301        NULL,
00302        NULL,
00303        STANDARD_MODULE_PROPERTIES_EX
00304 };
00305 /* }}} */
00306 
00307 #ifdef COMPILE_DL_GMP
00308 ZEND_GET_MODULE(gmp)
00309 #endif
00310 
00311 static void _php_gmpnum_free(zend_rsrc_list_entry *rsrc TSRMLS_DC);
00312 
00313 #define GMP_RESOURCE_NAME "GMP integer"
00314 
00315 #define GMP_ROUND_ZERO      0
00316 #define GMP_ROUND_PLUSINF   1
00317 #define GMP_ROUND_MINUSINF  2
00318 
00319 /* The maximum base for input and output conversions is 62 from GMP 4.2
00320  * onwards. */
00321 #if (__GNU_MP_VERSION >= 5) || (__GNU_MP_VERSION >= 4 && __GNU_MP_VERSION_MINOR >= 2)
00322 #      define MAX_BASE 62
00323 #else
00324 #      define MAX_BASE 36
00325 #endif
00326 
00327 /* {{{ gmp_emalloc
00328  */
00329 static void *gmp_emalloc(size_t size)
00330 {
00331        return emalloc(size);
00332 }
00333 /* }}} */
00334 
00335 /* {{{ gmp_erealloc
00336  */
00337 static void *gmp_erealloc(void *ptr, size_t old_size, size_t new_size)
00338 {
00339        return erealloc(ptr, new_size);
00340 }
00341 /* }}} */
00342 
00343 /* {{{ gmp_efree
00344  */
00345 static void gmp_efree(void *ptr, size_t size)
00346 {
00347        efree(ptr);
00348 }
00349 /* }}} */
00350 
00351 /* {{{ ZEND_GINIT_FUNCTION
00352  */
00353 static ZEND_GINIT_FUNCTION(gmp)
00354 {
00355        gmp_globals->rand_initialized = 0;
00356 }
00357 /* }}} */
00358 
00359 /* {{{ ZEND_MINIT_FUNCTION
00360  */
00361 ZEND_MODULE_STARTUP_D(gmp)
00362 {
00363        le_gmp = zend_register_list_destructors_ex(_php_gmpnum_free, NULL, GMP_RESOURCE_NAME, module_number);
00364        REGISTER_LONG_CONSTANT("GMP_ROUND_ZERO", GMP_ROUND_ZERO, CONST_CS | CONST_PERSISTENT);
00365        REGISTER_LONG_CONSTANT("GMP_ROUND_PLUSINF", GMP_ROUND_PLUSINF, CONST_CS | CONST_PERSISTENT);
00366        REGISTER_LONG_CONSTANT("GMP_ROUND_MINUSINF", GMP_ROUND_MINUSINF, CONST_CS | CONST_PERSISTENT);
00367 #ifdef mpir_version
00368        REGISTER_STRING_CONSTANT("GMP_MPIR_VERSION", (char *)mpir_version, CONST_CS | CONST_PERSISTENT);
00369 #endif
00370        REGISTER_STRING_CONSTANT("GMP_VERSION", (char *)gmp_version, CONST_CS | CONST_PERSISTENT);
00371 
00372        mp_set_memory_functions(gmp_emalloc, gmp_erealloc, gmp_efree);
00373 
00374        return SUCCESS;
00375 }
00376 /* }}} */
00377 
00378 /* {{{ ZEND_RSHUTDOWN_FUNCTION
00379  */
00380 ZEND_MODULE_DEACTIVATE_D(gmp)
00381 {
00382        if (GMPG(rand_initialized)) {
00383               gmp_randclear(GMPG(rand_state));
00384               GMPG(rand_initialized) = 0;
00385        }
00386 
00387        return SUCCESS;
00388 }
00389 /* }}} */
00390 
00391 /* {{{ ZEND_MINFO_FUNCTION
00392  */
00393 ZEND_MODULE_INFO_D(gmp)
00394 {
00395        php_info_print_table_start();
00396        php_info_print_table_row(2, "gmp support", "enabled");
00397 #ifdef mpir_version
00398        php_info_print_table_row(2, "MPIR version", mpir_version);
00399 #else
00400        php_info_print_table_row(2, "GMP version", gmp_version);
00401 #endif
00402        php_info_print_table_end();
00403 }
00404 /* }}} */
00405 
00406 /* Fetch zval to be GMP number.
00407    Initially, zval can be also number or string */
00408 #define FETCH_GMP_ZVAL(gmpnumber, zval, tmp_resource)                                                    \
00409 if (Z_TYPE_PP(zval) == IS_RESOURCE) {                                                                                  \
00410        ZEND_FETCH_RESOURCE(gmpnumber, mpz_t *, zval, -1, GMP_RESOURCE_NAME, le_gmp);       \
00411        tmp_resource = 0;                                                                                                             \
00412 } else {                                                                                                                                    \
00413        if (convert_to_gmp(&gmpnumber, zval, 0 TSRMLS_CC) == FAILURE) {                                   \
00414               RETURN_FALSE;                                                                                                          \
00415        }                                                                                                                                           \
00416        tmp_resource = ZEND_REGISTER_RESOURCE(NULL, gmpnumber, le_gmp);                                   \
00417 }
00418 
00419 #define FREE_GMP_TEMP(tmp_resource)                     \
00420        if(tmp_resource) {                                      \
00421               zend_list_delete(tmp_resource);           \
00422        }
00423 
00424 
00425 /* create a new initialized GMP number */
00426 #define INIT_GMP_NUM(gmpnumber) { gmpnumber=emalloc(sizeof(mpz_t)); mpz_init(*gmpnumber); }
00427 #define FREE_GMP_NUM(gmpnumber) { mpz_clear(*gmpnumber); efree(gmpnumber); }
00428 
00429 /* {{{ convert_to_gmp
00430  * Convert zval to be gmp number */
00431 static int convert_to_gmp(mpz_t * *gmpnumber, zval **val, int base TSRMLS_DC) 
00432 {
00433        int ret = 0;
00434        int skip_lead = 0;
00435 
00436        *gmpnumber = emalloc(sizeof(mpz_t));
00437 
00438        switch (Z_TYPE_PP(val)) {
00439        case IS_LONG:
00440        case IS_BOOL:
00441        case IS_CONSTANT:
00442               {
00443                      convert_to_long_ex(val);
00444                      mpz_init_set_si(**gmpnumber, Z_LVAL_PP(val));
00445               }
00446               break;
00447        case IS_STRING:
00448               {
00449                      char *numstr = Z_STRVAL_PP(val);
00450 
00451                      if (Z_STRLEN_PP(val) > 2) {
00452                             if (numstr[0] == '0') {
00453                                    if (numstr[1] == 'x' || numstr[1] == 'X') {
00454                                           base = 16;
00455                                           skip_lead = 1;
00456                                    } else if (base != 16 && (numstr[1] == 'b' || numstr[1] == 'B')) {
00457                                           base = 2;
00458                                           skip_lead = 1;
00459                                    }
00460                             }
00461                      }
00462                      ret = mpz_init_set_str(**gmpnumber, (skip_lead ? &numstr[2] : numstr), base);
00463               }
00464               break;
00465        default:
00466               php_error_docref(NULL TSRMLS_CC, E_WARNING,"Unable to convert variable to GMP - wrong type");
00467               efree(*gmpnumber);
00468               return FAILURE;
00469        }
00470 
00471        if (ret) {
00472               FREE_GMP_NUM(*gmpnumber);
00473               return FAILURE;
00474        }
00475        
00476        return SUCCESS;
00477 }
00478 /* }}} */
00479 
00480 /* {{{ typedefs
00481  */
00482 typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr);
00483 typedef int (*gmp_unary_opl_t)(mpz_srcptr);
00484 
00485 typedef void (*gmp_unary_ui_op_t)(mpz_ptr, unsigned long);
00486 
00487 typedef void (*gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr);
00488 typedef int (*gmp_binary_opl_t)(mpz_srcptr, mpz_srcptr);
00489 
00490 typedef unsigned long (*gmp_binary_ui_op_t)(mpz_ptr, mpz_srcptr, unsigned long);
00491 typedef void (*gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
00492 typedef unsigned long (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long);
00493 /* }}} */
00494 
00495 #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)
00496 #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)
00497 
00498 #define gmp_binary_ui_op(op, uop) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop)
00499 #define gmp_binary_op(op)         _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, NULL)
00500 #define gmp_binary_opl(op) _gmp_binary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
00501 
00502 /* Unary operations */
00503 #define gmp_unary_op(op)         _gmp_unary_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
00504 #define gmp_unary_opl(op)         _gmp_unary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
00505 #define gmp_unary_ui_op(op)      _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
00506 
00507 /* {{{ gmp_zval_binary_ui_op_ex
00508    Execute GMP binary operation.
00509    May return GMP resource or long if operation allows this
00510 */
00511 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) 
00512 {
00513        mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result;
00514        unsigned long long_result = 0;
00515        int use_ui = 0;
00516        int arga_tmp = 0, argb_tmp = 0;
00517 
00518        FETCH_GMP_ZVAL(gmpnum_a, a_arg, arga_tmp);
00519        
00520        if (gmp_ui_op && Z_TYPE_PP(b_arg) == IS_LONG && Z_LVAL_PP(b_arg) >= 0) {
00521               use_ui = 1;
00522        } else {
00523               FETCH_GMP_ZVAL(gmpnum_b, b_arg, argb_tmp);
00524        }
00525 
00526        if(check_b_zero) {
00527               int b_is_zero = 0;
00528               if(use_ui) {
00529                      b_is_zero = (Z_LVAL_PP(b_arg) == 0);
00530               } else {
00531                      b_is_zero = !mpz_cmp_ui(*gmpnum_b, 0);
00532               }
00533 
00534               if(b_is_zero) {
00535                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero operand not allowed");
00536                      FREE_GMP_TEMP(arga_tmp);
00537                      FREE_GMP_TEMP(argb_tmp);
00538                      RETURN_FALSE;
00539               }
00540        }
00541 
00542        INIT_GMP_NUM(gmpnum_result);
00543 
00544        if (use_ui && gmp_ui_op) {
00545               if (allow_ui_return) {
00546                      long_result = gmp_ui_op(*gmpnum_result, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg));
00547                      if (use_sign && mpz_sgn(*gmpnum_a) == -1) {
00548                             long_result = -long_result;
00549                      }
00550               } else {
00551                      gmp_ui_op(*gmpnum_result, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg));
00552               }
00553        } else {
00554               gmp_op(*gmpnum_result, *gmpnum_a, *gmpnum_b);
00555        }
00556 
00557        FREE_GMP_TEMP(arga_tmp);
00558        FREE_GMP_TEMP(argb_tmp);
00559 
00560        if (use_ui && allow_ui_return) {
00561               FREE_GMP_NUM(gmpnum_result);
00562               RETURN_LONG((long)long_result);
00563        } else {
00564               ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
00565        }
00566 }
00567 /* }}} */
00568 
00569 /* {{{ gmp_zval_binary_ui_op2_ex
00570    Execute GMP binary operation which returns 2 values.
00571    May return GMP resources or longs if operation allows this.
00572 */
00573 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)
00574 {
00575        mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result1, *gmpnum_result2;
00576        zval r;
00577        int use_ui = 0;
00578        unsigned long long_result = 0;
00579        int arga_tmp = 0, argb_tmp = 0;
00580 
00581        FETCH_GMP_ZVAL(gmpnum_a, a_arg, arga_tmp);
00582 
00583        if (gmp_ui_op && Z_TYPE_PP(b_arg) == IS_LONG && Z_LVAL_PP(b_arg) >= 0) {
00584               /* use _ui function */
00585               use_ui = 1;
00586        } else {
00587               FETCH_GMP_ZVAL(gmpnum_b, b_arg, argb_tmp);
00588        }
00589 
00590        if(check_b_zero) {
00591               int b_is_zero = 0;
00592               if(use_ui) {
00593                      b_is_zero = (Z_LVAL_PP(b_arg) == 0);
00594               } else {
00595                      b_is_zero = !mpz_cmp_ui(*gmpnum_b, 0);
00596               }
00597 
00598               if(b_is_zero) {
00599                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero operand not allowed");
00600                      FREE_GMP_TEMP(arga_tmp);
00601                      FREE_GMP_TEMP(argb_tmp);
00602                      RETURN_FALSE;
00603               }
00604        }
00605 
00606        INIT_GMP_NUM(gmpnum_result1);
00607        INIT_GMP_NUM(gmpnum_result2);
00608 
00609        if (use_ui && gmp_ui_op) {
00610               if (allow_ui_return) {
00611                      long_result = gmp_ui_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg));
00612               } else {
00613                      gmp_ui_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg));
00614               }
00615        } else {
00616               gmp_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, *gmpnum_b);
00617        }
00618 
00619        FREE_GMP_TEMP(arga_tmp);
00620        FREE_GMP_TEMP(argb_tmp);
00621 
00622        array_init(return_value);
00623        ZEND_REGISTER_RESOURCE(&r, gmpnum_result1, le_gmp);
00624        add_index_resource(return_value, 0, Z_LVAL(r));
00625        if (use_ui && allow_ui_return) {
00626               mpz_clear(*gmpnum_result2);
00627               add_index_long(return_value, 1, long_result);
00628        } else {
00629               ZEND_REGISTER_RESOURCE(&r, gmpnum_result2, le_gmp);
00630               add_index_resource(return_value, 1, Z_LVAL(r));
00631        }
00632 }
00633 /* }}} */
00634 
00635 /* {{{ _gmp_binary_ui_op
00636  */
00637 static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op)
00638 {
00639        zval **a_arg, **b_arg;
00640 
00641        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
00642               return;
00643        }
00644        
00645        gmp_zval_binary_ui_op(return_value, a_arg, b_arg, gmp_op, gmp_ui_op);
00646 }
00647 /* }}} */
00648 
00649 /* Unary operations */
00650 
00651 /* {{{ gmp_zval_unary_op
00652  */
00653 static inline void gmp_zval_unary_op(zval *return_value, zval **a_arg, gmp_unary_op_t gmp_op TSRMLS_DC) 
00654 {
00655        mpz_t *gmpnum_a, *gmpnum_result;
00656        int temp_a;
00657        
00658        FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
00659 
00660        INIT_GMP_NUM(gmpnum_result);
00661        gmp_op(*gmpnum_result, *gmpnum_a);
00662 
00663        FREE_GMP_TEMP(temp_a);
00664        ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
00665 }
00666 /* }}} */
00667 
00668 /* {{{ gmp_zval_unary_ui_op
00669  */
00670 static inline void gmp_zval_unary_ui_op(zval *return_value, zval **a_arg, gmp_unary_ui_op_t gmp_op)
00671 {
00672        mpz_t *gmpnum_result;
00673 
00674        convert_to_long_ex(a_arg);
00675 
00676        INIT_GMP_NUM(gmpnum_result);
00677        gmp_op(*gmpnum_result, Z_LVAL_PP(a_arg));
00678 
00679        ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
00680 }
00681 /* }}} */
00682 
00683 /* {{{ _gmp_unary_ui_op
00684    Execute GMP unary operation.
00685 */
00686 static inline void _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_ui_op_t gmp_op)
00687 {
00688        zval **a_arg;
00689 
00690        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
00691               return;
00692        }
00693 
00694        gmp_zval_unary_ui_op(return_value, a_arg, gmp_op);
00695 }
00696 /* }}} */
00697 
00698 /* {{{ _gmp_unary_op
00699  */
00700 static inline void _gmp_unary_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_op_t gmp_op)
00701 {
00702        zval **a_arg;
00703 
00704        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
00705               return;
00706        }
00707        
00708        gmp_zval_unary_op(return_value, a_arg, gmp_op TSRMLS_CC);
00709 }
00710 /* }}} */
00711 
00712 /* {{{ _gmp_unary_opl
00713  */
00714 static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t gmp_op)
00715 {
00716        zval **a_arg;
00717        mpz_t *gmpnum_a;
00718        int temp_a;
00719 
00720        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
00721               return;
00722        }
00723        
00724        FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
00725        RETVAL_LONG(gmp_op(*gmpnum_a));
00726        FREE_GMP_TEMP(temp_a);
00727 }
00728 /* }}} */
00729 
00730 /* {{{ _gmp_binary_opl
00731  */
00732 static inline void _gmp_binary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_opl_t gmp_op)
00733 {
00734        zval **a_arg, **b_arg;
00735        mpz_t *gmpnum_a, *gmpnum_b;
00736        int temp_a, temp_b;
00737 
00738        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
00739               return;
00740        }
00741 
00742        FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
00743        FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b);
00744 
00745        RETVAL_LONG(gmp_op(*gmpnum_a, *gmpnum_b));
00746 
00747        FREE_GMP_TEMP(temp_a);
00748        FREE_GMP_TEMP(temp_b);
00749 }
00750 /* }}} */
00751 
00752 /* {{{ proto resource gmp_init(mixed number [, int base])
00753    Initializes GMP number */
00754 ZEND_FUNCTION(gmp_init)
00755 {
00756        zval **number_arg;
00757        mpz_t * gmpnumber;
00758        long base=0;
00759 
00760        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &number_arg, &base) == FAILURE) {
00761               return;
00762        }
00763 
00764        if (base && (base < 2 || base > MAX_BASE)) {
00765               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad base for conversion: %ld (should be between 2 and %d)", base, MAX_BASE);
00766               RETURN_FALSE;
00767        }
00768 
00769        if (convert_to_gmp(&gmpnumber, number_arg, base TSRMLS_CC) == FAILURE) {
00770               RETURN_FALSE;
00771        }
00772 
00773        /* Write your own code here to handle argument number. */
00774        ZEND_REGISTER_RESOURCE(return_value, gmpnumber, le_gmp);
00775 }
00776 /* }}} */
00777 
00778 /* {{{ proto int gmp_intval(resource gmpnumber)
00779    Gets signed long value of GMP number */
00780 ZEND_FUNCTION(gmp_intval)
00781 {
00782        zval **gmpnumber_arg;
00783        mpz_t * gmpnum;
00784 
00785        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &gmpnumber_arg) == FAILURE){
00786               return;
00787        }
00788        
00789        if (Z_TYPE_PP(gmpnumber_arg) == IS_RESOURCE) {
00790               ZEND_FETCH_RESOURCE(gmpnum, mpz_t *, gmpnumber_arg, -1, GMP_RESOURCE_NAME, le_gmp);
00791               RETVAL_LONG(mpz_get_si(*gmpnum));
00792        } else {
00793               convert_to_long_ex(gmpnumber_arg);
00794               RETVAL_LONG(Z_LVAL_PP(gmpnumber_arg));
00795        }
00796 }
00797 /* }}} */
00798 
00799 /* {{{ proto string gmp_strval(resource gmpnumber [, int base])
00800    Gets string representation of GMP number  */
00801 ZEND_FUNCTION(gmp_strval)
00802 {
00803        zval **gmpnumber_arg;
00804        int num_len;
00805        long base = 10;
00806        mpz_t * gmpnum;
00807        char *out_string;
00808        int temp_a;
00809 
00810        if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &gmpnumber_arg, &base ) == FAILURE ) {
00811               return;
00812        }
00813 
00814 #if MAX_BASE == 62
00815        /* Although the maximum base in general in GMP >= 4.2 is 62, mpz_get_str()
00816         * is explicitly limited to -36 when dealing with negative bases. */
00817        if ((base < 2 && base > -2) || base > MAX_BASE || base < -36) {
00818               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);
00819 #else
00820        if (base < 2 || base > MAX_BASE) {
00821               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad base for conversion: %ld (should be between 2 and %d)", base, MAX_BASE);
00822 #endif
00823               RETURN_FALSE;
00824        }
00825 
00826        FETCH_GMP_ZVAL(gmpnum, gmpnumber_arg, temp_a);
00827 
00828        num_len = mpz_sizeinbase(*gmpnum, abs(base));
00829        out_string = emalloc(num_len+2);
00830        if (mpz_sgn(*gmpnum) < 0) {
00831               num_len++;
00832        }
00833        mpz_get_str(out_string, base, *gmpnum);
00834        
00835        FREE_GMP_TEMP(temp_a);
00836        
00837        /* 
00838        From GMP documentation for mpz_sizeinbase():
00839        The returned value will be exact or 1 too big.  If base is a power of
00840        2, the returned value will always be exact.
00841 
00842        So let's check to see if we already have a \0 byte...
00843        */
00844 
00845        if (out_string[num_len-1] == '\0') {
00846               num_len--;
00847        } else {
00848               out_string[num_len] = '\0';
00849        }
00850        RETVAL_STRINGL(out_string, num_len, 0);
00851 }
00852 /* }}} */
00853 
00854 /* {{{ proto resource gmp_add(resource a, resource b)
00855    Add a and b */
00856 ZEND_FUNCTION(gmp_add)
00857 {
00858        gmp_binary_ui_op(mpz_add, (gmp_binary_ui_op_t)mpz_add_ui);
00859 }
00860 /* }}} */
00861 
00862 /* {{{ proto resource gmp_sub(resource a, resource b)
00863    Subtract b from a */
00864 ZEND_FUNCTION(gmp_sub)
00865 {
00866        gmp_binary_ui_op(mpz_sub, (gmp_binary_ui_op_t)mpz_sub_ui);
00867 }
00868 /* }}} */
00869 
00870 /* {{{ proto resource gmp_mul(resource a, resource b)
00871    Multiply a and b */
00872 ZEND_FUNCTION(gmp_mul)
00873 {
00874        gmp_binary_ui_op(mpz_mul, (gmp_binary_ui_op_t)mpz_mul_ui);
00875 }
00876 /* }}} */
00877 
00878 /* {{{ proto array gmp_div_qr(resource a, resource b [, int round])
00879    Divide a by b, returns quotient and reminder */
00880 ZEND_FUNCTION(gmp_div_qr)
00881 {
00882        zval **a_arg, **b_arg;
00883        long round = GMP_ROUND_ZERO;
00884 
00885        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|l", &a_arg, &b_arg, &round) == FAILURE) {
00886               return;
00887        }
00888 
00889        switch (round) {
00890        case GMP_ROUND_ZERO:
00891               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);
00892               break;
00893        case GMP_ROUND_PLUSINF:
00894               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);
00895               break;
00896        case GMP_ROUND_MINUSINF:
00897               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);
00898               break;
00899        }
00900                                                     
00901 }
00902 /* }}} */
00903 
00904 /* {{{ proto resource gmp_div_r(resource a, resource b [, int round])
00905    Divide a by b, returns reminder only */
00906 ZEND_FUNCTION(gmp_div_r)
00907 {
00908        zval **a_arg, **b_arg;
00909        long round = GMP_ROUND_ZERO;
00910 
00911        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|l", &a_arg, &b_arg, &round) == FAILURE) {
00912               return;
00913        }
00914 
00915        switch (round) {
00916        case GMP_ROUND_ZERO:
00917               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);
00918               break;
00919        case GMP_ROUND_PLUSINF:
00920               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);
00921               break;
00922        case GMP_ROUND_MINUSINF:
00923               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);
00924               break;
00925        }
00926 }
00927 /* }}} */
00928 
00929 /* {{{ proto resource gmp_div_q(resource a, resource b [, int round])
00930    Divide a by b, returns quotient only */
00931 ZEND_FUNCTION(gmp_div_q)
00932 {
00933        zval **a_arg, **b_arg;
00934        long round = GMP_ROUND_ZERO;
00935 
00936        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|l", &a_arg, &b_arg, &round) == FAILURE) {
00937               return;
00938        }
00939 
00940        switch (round) {
00941        case GMP_ROUND_ZERO:
00942               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);
00943               break;
00944        case GMP_ROUND_PLUSINF:
00945               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);
00946               break;
00947        case GMP_ROUND_MINUSINF:
00948               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);
00949               break;
00950        }
00951                                                     
00952 }
00953 /* }}} */
00954 
00955 /* {{{ proto resource gmp_mod(resource a, resource b)
00956    Computes a modulo b */
00957 ZEND_FUNCTION(gmp_mod)
00958 {
00959        zval **a_arg, **b_arg;
00960 
00961        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
00962               return;
00963        }
00964 
00965        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);
00966 }
00967 /* }}} */
00968 
00969 /* {{{ proto resource gmp_divexact(resource a, resource b)
00970    Divide a by b using exact division algorithm */
00971 ZEND_FUNCTION(gmp_divexact)
00972 {
00973        zval **a_arg, **b_arg;
00974 
00975        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
00976               return;
00977        }
00978        
00979        gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_divexact, NULL, 0, 1, 1 TSRMLS_CC);
00980 }
00981 /* }}} */
00982 
00983 /* {{{ proto resource gmp_neg(resource a)
00984    Negates a number */
00985 ZEND_FUNCTION(gmp_neg)
00986 {
00987        gmp_unary_op(mpz_neg);
00988 }
00989 /* }}} */
00990 
00991 /* {{{ proto resource gmp_abs(resource a)
00992    Calculates absolute value */
00993 ZEND_FUNCTION(gmp_abs)
00994 {
00995        gmp_unary_op(mpz_abs);
00996 }
00997 /* }}} */
00998 
00999 /* {{{ proto resource gmp_fact(int a)
01000    Calculates factorial function */
01001 ZEND_FUNCTION(gmp_fact)
01002 {
01003        zval **a_arg;
01004        mpz_t *gmpnum_tmp;
01005        int temp_a;
01006 
01007        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
01008               return;
01009        }
01010 
01011        if (Z_TYPE_PP(a_arg) == IS_RESOURCE) {
01012               FETCH_GMP_ZVAL(gmpnum_tmp, a_arg, temp_a);       /* no need to free this since it's IS_RESOURCE */
01013               if (mpz_sgn(*gmpnum_tmp) < 0) {
01014                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0");
01015                      RETURN_FALSE;
01016               }
01017        } else {
01018               convert_to_long_ex(a_arg);
01019               if (Z_LVAL_PP(a_arg) < 0) {
01020                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0");
01021                      RETURN_FALSE;
01022               }
01023        }
01024               
01025        gmp_zval_unary_ui_op(return_value, a_arg, mpz_fac_ui);
01026 }
01027 /* }}} */
01028 
01029 /* {{{ proto resource gmp_pow(resource base, int exp)
01030    Raise base to power exp */
01031 ZEND_FUNCTION(gmp_pow)
01032 {
01033        zval **base_arg;
01034        mpz_t *gmpnum_result, *gmpnum_base;
01035        int use_ui = 0;
01036        int temp_base;
01037        long exp;
01038 
01039        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &base_arg, &exp) == FAILURE) {
01040               return;
01041        }
01042 
01043        if (Z_TYPE_PP(base_arg) == IS_LONG && Z_LVAL_PP(base_arg) >= 0) {
01044               use_ui = 1;
01045        } else {
01046               FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base);
01047        }
01048 
01049        if (exp < 0) {
01050               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Negative exponent not supported");
01051               RETURN_FALSE;
01052        }
01053        
01054        INIT_GMP_NUM(gmpnum_result);
01055        if (use_ui) {
01056               mpz_ui_pow_ui(*gmpnum_result, Z_LVAL_PP(base_arg), exp);
01057        } else {
01058               mpz_pow_ui(*gmpnum_result, *gmpnum_base, exp);
01059               FREE_GMP_TEMP(temp_base);
01060        }
01061        ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
01062 }
01063 /* }}} */
01064 
01065 /* {{{ proto resource gmp_powm(resource base, resource exp, resource mod)
01066    Raise base to power exp and take result modulo mod */
01067 ZEND_FUNCTION(gmp_powm)
01068 {
01069        zval **base_arg, **exp_arg, **mod_arg;
01070        mpz_t *gmpnum_base, *gmpnum_exp, *gmpnum_mod, *gmpnum_result;
01071        int use_ui = 0;
01072        int temp_base, temp_exp, temp_mod;
01073 
01074        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ", &base_arg, &exp_arg, &mod_arg) == FAILURE){
01075               return;
01076        }
01077 
01078        FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base);
01079 
01080        if (Z_TYPE_PP(exp_arg) == IS_LONG && Z_LVAL_PP(exp_arg) >= 0) {
01081               use_ui = 1;
01082        } else {
01083               FETCH_GMP_ZVAL(gmpnum_exp, exp_arg, temp_exp);
01084               if (mpz_sgn(*gmpnum_exp) < 0) {
01085                      php_error_docref(NULL TSRMLS_CC, E_WARNING,"Second parameter cannot be less than 0");
01086                      RETURN_FALSE;
01087               }
01088        }
01089        FETCH_GMP_ZVAL(gmpnum_mod, mod_arg, temp_mod);
01090 
01091        if (!mpz_cmp_ui(*gmpnum_mod, 0)) {
01092               FREE_GMP_TEMP(temp_base);
01093               if (use_ui) {
01094                      FREE_GMP_TEMP(temp_exp);
01095               }
01096               FREE_GMP_TEMP(temp_mod);
01097               RETURN_FALSE;
01098        }
01099 
01100        INIT_GMP_NUM(gmpnum_result);
01101        if (use_ui) {
01102               mpz_powm_ui(*gmpnum_result, *gmpnum_base, (unsigned long)Z_LVAL_PP(exp_arg), *gmpnum_mod);
01103        } else {
01104               mpz_powm(*gmpnum_result, *gmpnum_base, *gmpnum_exp, *gmpnum_mod);
01105               FREE_GMP_TEMP(temp_exp);
01106        }
01107 
01108        FREE_GMP_TEMP(temp_base);
01109        FREE_GMP_TEMP(temp_mod);
01110 
01111        ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
01112 
01113 }
01114 /* }}} */
01115 
01116 /* {{{ proto resource gmp_sqrt(resource a)
01117    Takes integer part of square root of a */
01118 ZEND_FUNCTION(gmp_sqrt)
01119 {
01120        zval **a_arg;
01121        mpz_t *gmpnum_a, *gmpnum_result;
01122        int temp_a;
01123 
01124        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
01125               return;
01126        }
01127        
01128        FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
01129 
01130        if (mpz_sgn(*gmpnum_a) < 0) {
01131               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0");
01132               FREE_GMP_TEMP(temp_a);
01133               RETURN_FALSE;
01134        }      
01135        
01136        INIT_GMP_NUM(gmpnum_result);
01137        mpz_sqrt(*gmpnum_result, *gmpnum_a);
01138        FREE_GMP_TEMP(temp_a);
01139 
01140        ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
01141 }
01142 /* }}} */
01143 
01144 /* {{{ proto array gmp_sqrtrem(resource a)
01145    Square root with remainder */
01146 ZEND_FUNCTION(gmp_sqrtrem)
01147 {
01148        zval **a_arg;
01149        mpz_t *gmpnum_a, *gmpnum_result1, *gmpnum_result2;
01150        zval r;
01151        int temp_a;
01152 
01153        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
01154               return;
01155        }
01156 
01157        FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
01158        
01159        if (mpz_sgn(*gmpnum_a) < 0) {
01160               php_error_docref(NULL TSRMLS_CC, E_WARNING,"Number has to be greater than or equal to 0");
01161               RETURN_FALSE;
01162        }
01163        
01164        INIT_GMP_NUM(gmpnum_result1);
01165        INIT_GMP_NUM(gmpnum_result2);
01166 
01167        mpz_sqrtrem(*gmpnum_result1, *gmpnum_result2, *gmpnum_a);
01168        FREE_GMP_TEMP(temp_a);
01169 
01170        array_init(return_value);
01171        ZEND_REGISTER_RESOURCE(&r, gmpnum_result1, le_gmp);
01172        add_index_resource(return_value, 0, Z_LVAL(r));
01173        ZEND_REGISTER_RESOURCE(&r, gmpnum_result2, le_gmp);
01174        add_index_resource(return_value, 1, Z_LVAL(r));
01175 }
01176 /* }}} */
01177 
01178 /* {{{ proto bool gmp_perfect_square(resource a)
01179    Checks if a is an exact square */
01180 ZEND_FUNCTION(gmp_perfect_square)
01181 {
01182        zval **a_arg;
01183        mpz_t *gmpnum_a;
01184        int temp_a;
01185 
01186        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
01187               return;
01188        }
01189 
01190        FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
01191 
01192        RETVAL_BOOL((mpz_perfect_square_p(*gmpnum_a)!=0));
01193        FREE_GMP_TEMP(temp_a);
01194 }
01195 /* }}} */
01196 
01197 /* {{{ proto int gmp_prob_prime(resource a[, int reps])
01198    Checks if a is "probably prime" */
01199 ZEND_FUNCTION(gmp_prob_prime)
01200 {
01201        zval **gmpnumber_arg;
01202        mpz_t *gmpnum_a;
01203        long reps = 10;
01204        int temp_a;
01205 
01206        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &gmpnumber_arg, &reps) == FAILURE) {
01207               return;
01208        }
01209 
01210        FETCH_GMP_ZVAL(gmpnum_a, gmpnumber_arg, temp_a);
01211 
01212        RETVAL_LONG(mpz_probab_prime_p(*gmpnum_a, reps));
01213        FREE_GMP_TEMP(temp_a);
01214 }
01215 /* }}} */
01216 
01217 /* {{{ proto resource gmp_gcd(resource a, resource b)
01218    Computes greatest common denominator (gcd) of a and b */
01219 ZEND_FUNCTION(gmp_gcd)
01220 {
01221        zval **a_arg, **b_arg;
01222 
01223        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
01224               return;
01225        }
01226 
01227        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);
01228 }
01229 /* }}} */
01230 
01231 /* {{{ proto array gmp_gcdext(resource a, resource b)
01232    Computes G, S, and T, such that AS + BT = G = `gcd' (A, B) */
01233 ZEND_FUNCTION(gmp_gcdext)
01234 {
01235        zval **a_arg, **b_arg;
01236        mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_t, *gmpnum_s, *gmpnum_g;
01237        zval r;
01238        int temp_a, temp_b;
01239 
01240        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
01241               return;
01242        }
01243 
01244        FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
01245        FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b);
01246 
01247        INIT_GMP_NUM(gmpnum_g);
01248        INIT_GMP_NUM(gmpnum_s);
01249        INIT_GMP_NUM(gmpnum_t);
01250 
01251        mpz_gcdext(*gmpnum_g, *gmpnum_s, *gmpnum_t, *gmpnum_a, *gmpnum_b);
01252        FREE_GMP_TEMP(temp_a);
01253        FREE_GMP_TEMP(temp_b);
01254 
01255        array_init(return_value);
01256 
01257        ZEND_REGISTER_RESOURCE(&r, gmpnum_g, le_gmp);
01258        add_assoc_resource(return_value, "g", Z_LVAL(r));
01259        ZEND_REGISTER_RESOURCE(&r, gmpnum_s, le_gmp);
01260        add_assoc_resource(return_value, "s", Z_LVAL(r));
01261        ZEND_REGISTER_RESOURCE(&r, gmpnum_t, le_gmp);
01262        add_assoc_resource(return_value, "t", Z_LVAL(r));
01263 }
01264 /* }}} */
01265 
01266 /* {{{ proto resource gmp_invert(resource a, resource b)
01267    Computes the inverse of a modulo b */
01268 ZEND_FUNCTION(gmp_invert)
01269 {
01270        zval **a_arg, **b_arg;
01271        mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result;
01272        int temp_a, temp_b;
01273        int res;
01274 
01275        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
01276               return;
01277        }
01278 
01279        FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
01280        FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b);
01281 
01282        INIT_GMP_NUM(gmpnum_result);
01283        res=mpz_invert(*gmpnum_result, *gmpnum_a, *gmpnum_b);
01284        FREE_GMP_TEMP(temp_a);
01285        FREE_GMP_TEMP(temp_b);
01286        if (res) {
01287               ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
01288        } else {
01289               FREE_GMP_NUM(gmpnum_result);
01290               RETURN_FALSE;
01291        }
01292 }
01293 /* }}} */
01294 
01295 /* {{{ proto int gmp_jacobi(resource a, resource b)
01296    Computes Jacobi symbol */
01297 ZEND_FUNCTION(gmp_jacobi)
01298 {
01299        gmp_binary_opl(mpz_jacobi);
01300 }
01301 /* }}} */
01302 
01303 /* {{{ proto int gmp_legendre(resource a, resource b)
01304    Computes Legendre symbol */
01305 ZEND_FUNCTION(gmp_legendre)
01306 {
01307        gmp_binary_opl(mpz_legendre);
01308 }
01309 /* }}} */
01310 
01311 /* {{{ proto int gmp_cmp(resource a, resource b)
01312    Compares two numbers */
01313 ZEND_FUNCTION(gmp_cmp)
01314 {
01315        zval **a_arg, **b_arg;
01316        mpz_t *gmpnum_a, *gmpnum_b;
01317        int use_si = 0, res;
01318        int temp_a, temp_b;
01319 
01320        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
01321               return;
01322        }
01323 
01324        FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
01325 
01326        if (Z_TYPE_PP(b_arg) == IS_LONG) {
01327               use_si = 1;
01328        } else {
01329               FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b);
01330        }
01331 
01332        if (use_si) {
01333               res = mpz_cmp_si(*gmpnum_a, Z_LVAL_PP(b_arg));
01334        } else {
01335               res = mpz_cmp(*gmpnum_a, *gmpnum_b);
01336        }
01337        FREE_GMP_TEMP(temp_a);
01338        
01339        RETURN_LONG(res);
01340 }
01341 /* }}} */
01342 
01343 /* {{{ proto int gmp_sign(resource a)
01344    Gets the sign of the number */
01345 ZEND_FUNCTION(gmp_sign)
01346 {
01347        zval **a_arg;
01348        mpz_t *gmpnum_a;
01349        int temp_a;
01350 
01351        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
01352               return;
01353        }
01354        
01355        FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
01356 
01357        RETVAL_LONG(mpz_sgn(*gmpnum_a));
01358        FREE_GMP_TEMP(temp_a);
01359 }
01360 /* }}} */
01361 
01362 /* {{{ proto resource gmp_random([int limiter])
01363    Gets random number */
01364 ZEND_FUNCTION(gmp_random)
01365 {
01366        long limiter = 20;
01367        mpz_t *gmpnum_result;
01368 
01369        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &limiter) == FAILURE) {
01370               return;
01371        }
01372 
01373        INIT_GMP_NUM(gmpnum_result);
01374 
01375        if (!GMPG(rand_initialized)) {
01376               /* Initialize */
01377               gmp_randinit_lc_2exp_size(GMPG(rand_state), 32L);
01378 
01379               /* Seed */
01380               gmp_randseed_ui(GMPG(rand_state), GENERATE_SEED());
01381 
01382               GMPG(rand_initialized) = 1;
01383        }
01384 #ifdef GMP_LIMB_BITS
01385        mpz_urandomb(*gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * GMP_LIMB_BITS);
01386 #else
01387        mpz_urandomb(*gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * __GMP_BITS_PER_MP_LIMB);
01388 #endif
01389        ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
01390 }
01391 /* }}} */
01392 
01393 /* {{{ proto resource gmp_and(resource a, resource b)
01394    Calculates logical AND of a and b */
01395 ZEND_FUNCTION(gmp_and)
01396 {
01397        gmp_binary_op(mpz_and);
01398 }
01399 /* }}} */
01400 
01401 /* {{{ proto resource gmp_or(resource a, resource b)
01402    Calculates logical OR of a and b */
01403 ZEND_FUNCTION(gmp_or)
01404 {
01405        gmp_binary_op(mpz_ior);
01406 }
01407 /* }}} */
01408 
01409 /* {{{ proto resource gmp_com(resource a)
01410    Calculates one's complement of a */
01411 ZEND_FUNCTION(gmp_com)
01412 {
01413        gmp_unary_op(mpz_com);
01414 }
01415 /* }}} */
01416 
01417 /* {{{ proto resource gmp_nextprime(resource a)
01418    Finds next prime of a */
01419 ZEND_FUNCTION(gmp_nextprime)
01420 {
01421    gmp_unary_op(mpz_nextprime);
01422 }
01423 /* }}} */
01424 
01425 /* {{{ proto resource gmp_xor(resource a, resource b)
01426    Calculates logical exclusive OR of a and b */
01427 ZEND_FUNCTION(gmp_xor)
01428 {
01429        /* use formula: a^b = (a|b)&^(a&b) */
01430        zval **a_arg, **b_arg;
01431        mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result, *gmpnum_t;
01432        int temp_a, temp_b;
01433 
01434        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
01435               return;
01436        }
01437 
01438        FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
01439        FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b);
01440 
01441        INIT_GMP_NUM(gmpnum_result);
01442        INIT_GMP_NUM(gmpnum_t);
01443 
01444        mpz_and(*gmpnum_t, *gmpnum_a, *gmpnum_b);
01445        mpz_com(*gmpnum_t, *gmpnum_t);
01446 
01447        mpz_ior(*gmpnum_result, *gmpnum_a, *gmpnum_b);
01448        mpz_and(*gmpnum_result, *gmpnum_result, *gmpnum_t);
01449 
01450        FREE_GMP_NUM(gmpnum_t);
01451 
01452        FREE_GMP_TEMP(temp_a);
01453        FREE_GMP_TEMP(temp_b);
01454        ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
01455 }
01456 /* }}} */
01457 
01458 /* {{{ proto void gmp_setbit(resource &a, int index[, bool set_clear])
01459    Sets or clear bit in a */
01460 ZEND_FUNCTION(gmp_setbit)
01461 {
01462        zval **a_arg;
01463        long index;
01464        zend_bool set = 1;
01465        mpz_t *gmpnum_a;
01466 
01467        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl|b", &a_arg, &index, &set) == FAILURE) {
01468               return;
01469        }
01470 
01471        ZEND_FETCH_RESOURCE(gmpnum_a, mpz_t *, a_arg, -1, GMP_RESOURCE_NAME, le_gmp);
01472 
01473        if (index < 0) {
01474               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero");
01475               return;
01476        }
01477 
01478        if (set) {
01479               mpz_setbit(*gmpnum_a, index);
01480        } else {
01481               mpz_clrbit(*gmpnum_a, index);
01482        }
01483 }
01484 /* }}} */
01485 
01486 /* {{{ proto void gmp_clrbit(resource &a, int index)
01487    Clears bit in a */
01488 ZEND_FUNCTION(gmp_clrbit)
01489 {
01490        zval **a_arg;
01491        long index;
01492        mpz_t *gmpnum_a;
01493 
01494        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &index) == FAILURE){
01495               return;
01496        }
01497 
01498        ZEND_FETCH_RESOURCE(gmpnum_a, mpz_t *, a_arg, -1, GMP_RESOURCE_NAME, le_gmp);
01499 
01500        if (index < 0) {
01501               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero");
01502               return;
01503        }
01504 
01505        mpz_clrbit(*gmpnum_a, index);
01506 }
01507 /* }}} */
01508 
01509 /* {{{ proto bool gmp_testbit(resource a, int index)
01510    Tests if bit is set in a */
01511 ZEND_FUNCTION(gmp_testbit)
01512 {
01513        zval **a_arg;
01514        long index;
01515        mpz_t *gmpnum_a;
01516 
01517        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &index) == FAILURE){
01518               return;
01519        }
01520 
01521        ZEND_FETCH_RESOURCE(gmpnum_a, mpz_t *, a_arg, -1, GMP_RESOURCE_NAME, le_gmp);
01522 
01523        if (index < 0) {
01524               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero");
01525               RETURN_FALSE;
01526        }
01527 
01528        if (mpz_tstbit(*gmpnum_a, index)) {
01529               RETURN_TRUE;
01530        }
01531        RETURN_FALSE;
01532 }
01533 /* }}} */
01534 
01535 /* {{{ proto int gmp_popcount(resource a)
01536    Calculates the population count of a */
01537 ZEND_FUNCTION(gmp_popcount)
01538 {
01539        zval **a_arg;
01540        mpz_t *gmpnum_a;
01541        int temp_a;
01542 
01543        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){
01544               return;
01545        }
01546        
01547        FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
01548 
01549        RETVAL_LONG(mpz_popcount(*gmpnum_a));
01550        FREE_GMP_TEMP(temp_a);
01551 }
01552 /* }}} */
01553 
01554 /* {{{ proto int gmp_hamdist(resource a, resource b)
01555    Calculates hamming distance between a and b */
01556 ZEND_FUNCTION(gmp_hamdist)
01557 {
01558        zval **a_arg, **b_arg;
01559        mpz_t *gmpnum_a, *gmpnum_b;
01560        int temp_a, temp_b;
01561 
01562        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){
01563               return;
01564        }
01565 
01566        FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
01567        FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b);
01568 
01569        RETVAL_LONG(mpz_hamdist(*gmpnum_a, *gmpnum_b));
01570        FREE_GMP_TEMP(temp_a);
01571        FREE_GMP_TEMP(temp_b);
01572 }
01573 /* }}} */
01574 
01575 /* {{{ proto int gmp_scan0(resource a, int start)
01576    Finds first zero bit */
01577 ZEND_FUNCTION(gmp_scan0)
01578 {
01579        zval **a_arg;
01580        mpz_t *gmpnum_a;
01581        int temp_a;
01582        long start;
01583 
01584        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &start) == FAILURE){
01585               return;
01586        }
01587 
01588        FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
01589 
01590        if (start < 0) {
01591               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Starting index must be greater than or equal to zero");
01592               RETURN_FALSE;
01593        }
01594 
01595        RETVAL_LONG(mpz_scan0(*gmpnum_a, start));
01596        FREE_GMP_TEMP(temp_a);
01597 }
01598 /* }}} */
01599 
01600 /* {{{ proto int gmp_scan1(resource a, int start)
01601    Finds first non-zero bit */
01602 ZEND_FUNCTION(gmp_scan1)
01603 {
01604        zval **a_arg;
01605        mpz_t *gmpnum_a;
01606        int temp_a;
01607        long start;
01608 
01609        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &start) == FAILURE){
01610               return;
01611        }
01612 
01613        FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
01614        if (start < 0) {
01615               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Starting index must be greater than or equal to zero");
01616               RETURN_FALSE;
01617        }
01618 
01619        RETVAL_LONG(mpz_scan1(*gmpnum_a, start));
01620        FREE_GMP_TEMP(temp_a);
01621 }
01622 /* }}} */
01623 
01624 /* {{{ _php_gmpnum_free
01625  */
01626 static void _php_gmpnum_free(zend_rsrc_list_entry *rsrc TSRMLS_DC)
01627 {
01628        mpz_t *gmpnum = (mpz_t *)rsrc->ptr;
01629 
01630        FREE_GMP_NUM(gmpnum);
01631 }
01632 /* }}} */
01633 
01634 #endif /* HAVE_GMP */
01635 
01636 /*
01637  * Local variables:
01638  * tab-width: 4
01639  * c-basic-offset: 4
01640  * End:
01641  * vim600: noet sw=4 ts=4 fdm=marker
01642  * vim<600: noet sw=4 ts=4
01643  */