Annotation of embedaddon/php/ext/gmp/gmp.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>