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

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
1.1.1.3 ! misho       5:    | Copyright (c) 1997-2013 The PHP Group                                |
1.1       misho       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:  */
1.1.1.2   misho     670: static inline void gmp_zval_unary_ui_op(zval *return_value, zval **a_arg, gmp_unary_ui_op_t gmp_op TSRMLS_DC)
1.1       misho     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: 
1.1.1.2   misho     694:        gmp_zval_unary_ui_op(return_value, a_arg, gmp_op TSRMLS_CC);
1.1       misho     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;
1.1.1.2   misho     963:        }       
1.1       misho     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:                
1.1.1.2   misho    1025:        gmp_zval_unary_ui_op(return_value, a_arg, mpz_fac_ui TSRMLS_CC);
1.1       misho    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>