#include "global.h" #ifdef AUTO_BIGNUM #include "interpret.h" #include "program.h" #include "object.h" #include "svalue.h" #include "pike_error.h" struct svalue auto_bignum_program = { T_INT, 0, #ifdef HAVE_UNION_INIT {0}, /* Only to avoid warnings. */ #endif }; PMOD_EXPORT int gmp_library_loaded=0; int gmp_library_resolving=0; static void resolve_auto_bignum_program(void) { if(auto_bignum_program.type == T_INT) { if(gmp_library_resolving) fatal("Recursive GMP resolving!\n"); gmp_library_resolving=1; push_text("Gmp.bignum"); SAFE_APPLY_MASTER("resolv", 1); if(sp[-1].type != T_FUNCTION && sp[-1].type != T_PROGRAM) Pike_error("Failed to resolv Gmp.mpz!\n"); auto_bignum_program=sp[-1]; sp--; dmalloc_touch_svalue(sp); gmp_library_resolving=0; } } PMOD_EXPORT struct program *get_auto_bignum_program(void) { resolve_auto_bignum_program(); return program_from_function(&auto_bignum_program); } PMOD_EXPORT struct program *get_auto_bignum_program_or_zero(void) { if(!gmp_library_loaded || gmp_library_resolving || !master_object) return 0; resolve_auto_bignum_program(); return program_from_function(&auto_bignum_program); } void exit_auto_bignum(void) { free_svalue(&auto_bignum_program); auto_bignum_program.type=T_INT; } PMOD_EXPORT void convert_stack_top_to_bignum(void) { resolve_auto_bignum_program(); apply_svalue(&auto_bignum_program, 1); if(sp[-1].type != T_OBJECT) Pike_error("Gmp.mpz conversion failed.\n"); } PMOD_EXPORT void convert_stack_top_with_base_to_bignum(void) { resolve_auto_bignum_program(); apply_svalue(&auto_bignum_program, 2); if(sp[-1].type != T_OBJECT) Pike_error("Gmp.mpz conversion failed.\n"); } int is_bignum_object(struct object *o) { /* Note: * This function should *NOT* try to resolv Gmp.mpz unless * it is already loaded into memory. * /Hubbe */ if(!gmp_library_loaded || gmp_library_resolving || !master_object) return 0; /* not possible */ resolve_auto_bignum_program(); return o->prog == program_from_svalue(&auto_bignum_program); } PMOD_EXPORT int is_bignum_object_in_svalue(struct svalue *sv) { return sv->type == T_OBJECT && is_bignum_object(sv->u.object); } PMOD_EXPORT struct object *make_bignum_object(void) { convert_stack_top_to_bignum(); return (--sp)->u.object; } PMOD_EXPORT struct object *bignum_from_svalue(struct svalue *s) { push_svalue(s); convert_stack_top_to_bignum(); return (--sp)->u.object; } PMOD_EXPORT struct pike_string *string_from_bignum(struct object *o, int base) { push_int(base); safe_apply(o, "digits", 1); if(sp[-1].type != T_STRING) Pike_error("Gmp.mpz string conversion failed.\n"); return (--sp)->u.string; } PMOD_EXPORT void convert_svalue_to_bignum(struct svalue *s) { push_svalue(s); convert_stack_top_to_bignum(); free_svalue(s); *s=sp[-1]; sp--; dmalloc_touch_svalue(sp); } #ifdef INT64 PMOD_EXPORT void push_int64(INT64 i) { if(i == DO_NOT_WARN((INT_TYPE)i)) { push_int(DO_NOT_WARN((INT_TYPE)i)); } else { unsigned int neg = 0; if( i < 0 ) { i = -i; neg = 1; } #if PIKE_BYTEORDER == 1234 { char digits[8]; char *ledigits = (char *)&i; digits[7] = ledigits[ 0 ]; digits[6] = ledigits[ 1 ]; digits[5] = ledigits[ 2 ]; digits[4] = ledigits[ 3 ]; digits[3] = ledigits[ 4 ]; digits[2] = ledigits[ 5 ]; digits[1] = ledigits[ 6 ]; digits[0] = ledigits[ 7 ]; push_string( make_shared_binary_string( digits, 8 ) ); } #else push_string( make_shared_binary_string( (char *)&i, 8 ) ); #endif push_int( 256 ); apply_svalue(&auto_bignum_program, 2); if(neg) apply_low(sp[-1].u.object,FIND_LFUN(sp[-1].u.object->prog,LFUN_COMPL),0); } } /* This routines can be optimized quite drastically. */ #define BIGNUM_INT64_MASK 0xffffff #define BIGNUM_INT64_SHIFT 24 PMOD_EXPORT int int64_from_bignum(INT64 *i, struct object *bignum) { int neg, pos, rshfun, andfun; *i = 0; push_int(0); apply_low(bignum, FIND_LFUN(bignum->prog, LFUN_LT), 1); if(sp[-1].type != T_INT) Pike_error("Result from Gmp.bignum->`< not an integer.\n"); neg = (--sp)->u.integer; if(neg) apply_low(bignum, FIND_LFUN(bignum->prog, LFUN_COMPL), 0); rshfun = FIND_LFUN(bignum->prog, LFUN_RSH); andfun = FIND_LFUN(bignum->prog, LFUN_AND); ref_push_object(bignum); for(pos = 0; sp[-1].type != T_INT; ) { push_int(BIGNUM_INT64_MASK); apply_low(sp[-2].u.object, andfun, 1); if(sp[-1].type != T_INT) Pike_error("Result from Gmp.bignum->`& not an integer.\n"); *i |= (INT64)(--sp)->u.integer << (INT64)pos; pos += BIGNUM_INT64_SHIFT; push_int(BIGNUM_INT64_SHIFT); apply_low(sp[-2].u.object, rshfun, 1); stack_swap(); pop_stack(); } *i |= (INT64)(--sp)->u.integer << (INT64)pos; if(neg) *i = ~*i; return 1; /* We may someday return 0 if the conversion fails. */ } #endif /* INT64 */ #endif /* AUTO_BIGNUM */