diff --git a/src/modules/gmpmod/.cvsignore b/src/modules/gmpmod/.cvsignore new file mode 100644 index 0000000000000000000000000000000000000000..64200ddc24cb90d8f410a6a9e2b0b79c4cd30d58 --- /dev/null +++ b/src/modules/gmpmod/.cvsignore @@ -0,0 +1,2 @@ +Makefile.in +configure diff --git a/src/modules/gmpmod/.gitignore b/src/modules/gmpmod/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..addfc0376f648196d317f7f7299705f23cb23c21 --- /dev/null +++ b/src/modules/gmpmod/.gitignore @@ -0,0 +1,2 @@ +/Makefile.in +/configure diff --git a/src/modules/gmpmod/Makefile.src b/src/modules/gmpmod/Makefile.src new file mode 100644 index 0000000000000000000000000000000000000000..9c2029bb31c1d6cc59916cb67728dc5f08a0db6e --- /dev/null +++ b/src/modules/gmpmod/Makefile.src @@ -0,0 +1,19 @@ +SRCDIR=@srcdir@ +VPATH=@srcdir@:@srcdir@/../..:../.. +PREFLAGS=-I. -I$(SRCDIR) -I$(SRCDIR)/../.. -I../.. +CFLAGS=$(PREFLAGS) $(OTHERFLAGS) + +FILES=mpz_glue.o +LIB=gmpmod.a + +$(LIB): $(FILES) + -rm -f $(LIB) + ar cq $(LIB) $(FILES) + -@RANLIB@ $(LIB) + echo >linker_options @LIBS@ + +clean: + -rm -f *.o *.a + +depend: + gcc -MM $(PREFLAGS) $(SRCDIR)/*.c | $(FIXDEP) $(SRCDIR) diff --git a/src/modules/gmpmod/configure.in b/src/modules/gmpmod/configure.in new file mode 100644 index 0000000000000000000000000000000000000000..b8c1fa3b4afe39a8b85c5d1063174dd7395f44ee --- /dev/null +++ b/src/modules/gmpmod/configure.in @@ -0,0 +1,13 @@ +AC_INIT(mpz_glue.c) +AC_CONFIG_HEADER(gmp_machine.h) + +AC_PROG_CC +AC_PROG_RANLIB +AC_SUBST(RANLIB) + +AC_CHECK_HEADERS(gmp.h) +AC_CHECK_LIB(gmp, mpz_set_si) + +AC_OUTPUT(Makefile,echo FOO >stamp-h ) + + diff --git a/src/modules/gmpmod/doc/mpz b/src/modules/gmpmod/doc/mpz new file mode 100644 index 0000000000000000000000000000000000000000..596b815876de042bcd0e5866c91568e140016f8e --- /dev/null +++ b/src/modules/gmpmod/doc/mpz @@ -0,0 +1,76 @@ +NAME + /precompiled/mpz - bignum program + +DESCRIPTION + /precompiled/mpz is a builtin program written in C. It implements + large, very large integers. In fact, the only limitation on these + integers is the available memory. + + The mpz object implements all the normal integer operations. + (except xor) There are also some extra operators: + +NOTA BENE + This module is only available if libgmp.a was available and + found when uLPC was compiled. + +============================================================================ +NAME + create - initialize a bignum + +SYNTAX + object clone((program)"/precompiled/mpz"); + or + object clone((program)"/precompiled/mpz",int|object|string|float i); + +DESCRIPTION + When cloning an mpz it is by default initalized to zero. However, + you can give a second argument to clone to initialize the new + object to that value. The argument can be an int, float another + mpz object, or a string containing an ascii number. + +SEE ALSO + builtin/clone + +============================================================================ +NAME + powm - raise and modulo + +SYNTAX + object mpz->powm(int|string|float|object a,int|string|float|object b); + +DESCRIPTION + This function returns ( mpz ** a ) % b + +============================================================================ +NAME + sqrt - square root + +SYNTAX + object mpz->sqrt(); + +DESCRIPTION + This function return the the truncated integer part of the square + root of the value of mpz. + +============================================================================ +NAME + probably_prime_p - is this number a prime? + +SYNTAX + int mpz->probably_prime_p(); + +DESCRIPTION + This function returns 1 if mpz is a prime, and 0 most of the time + if it is not. + +============================================================================ +NAME + gcd - greatest common divisor + +SYNTAX + object mpz->gcd(object|int|float|string arg) + +DESCRIPTION + This function returns the greatest common divisor for arg and mpz. + +============================================================================ diff --git a/src/modules/gmpmod/gmp_machine.h.in b/src/modules/gmpmod/gmp_machine.h.in new file mode 100644 index 0000000000000000000000000000000000000000..0a79aef13b5e6bb3e9756f2369fd33595766c378 --- /dev/null +++ b/src/modules/gmpmod/gmp_machine.h.in @@ -0,0 +1,7 @@ +#ifndef GMP_MACHINE_H +#define GMP_MACHINE_H + +/* Define this if you have <gmp.h> */ +#undef HAVE_GMP_H + +#endif diff --git a/src/modules/gmpmod/mpz_glue.c b/src/modules/gmpmod/mpz_glue.c new file mode 100644 index 0000000000000000000000000000000000000000..641196dacd1bdae814163fe72d90936fcf916a2f --- /dev/null +++ b/src/modules/gmpmod/mpz_glue.c @@ -0,0 +1,440 @@ +/*\ +||| This file a part of uLPC, and is copyright by Fredrik Hubinette +||| uLPC is distributed as GPL (General Public License) +||| See the files COPYING and DISCLAIMER for more information. +\*/ +#include "global.h" +#include "gmp_machine.h" +#include "types.h" + +#ifdef HAVE_GMP_H + +#include "interpret.h" +#include "svalue.h" +#include "stralloc.h" +#include "array.h" +#include "macros.h" +#include "program.h" +#include "stralloc.h" +#include "object.h" +#include "lpc_types.h" + +#include <gmp.h> + +#define THIS (*(mpz_t *)(fp->current_storage)) +#define OBTOMPZ(o) (*(mpz_t *)(o->storage)) + +static struct program *mpzmod_program; + +static void get_new_mpz(mpz_t tmp, struct svalue *s) +{ + switch(s->type) + { + case T_INT: + mpz_set_si(tmp, (signed long int) s->u.integer); + break; + + case T_FLOAT: + mpz_set_d(tmp, (double) s->u.float_number); + break; + + case T_STRING: + mpz_set_str(tmp, s->u.string->str, 0); + break; + + case T_OBJECT: + if(s->u.object->prog != mpzmod_program) + error("Wrong type of object, cannot convert to mpz.\n"); + + mpz_set(tmp, OBTOMPZ(s->u.object)); + break; + + default: + error("Bad argument 1 to mpz->create()\n"); + } +} + +static void mpzmod_create(INT32 args) +{ + if(args) + { + get_new_mpz(THIS, sp-args); + pop_n_elems(args); + } +} + +static void mpzmod_get_int(INT32 args) +{ + pop_n_elems(args); + push_int(mpz_get_si(THIS)); +} + +static void mpzmod_get_float(INT32 args) +{ + pop_n_elems(args); + push_float((float)mpz_get_d(THIS)); +} + +static void mpzmod_get_string(INT32 args) +{ + struct lpc_string *s; + INT32 len; + + pop_n_elems(args); + len=mpz_sizeinbase(THIS,10); + len++; /* For a zero */ + if(mpz_sgn(THIS) < 0) len++; /* For the - sign */ + + s=begin_shared_string(len); + mpz_get_str(s->str,10,THIS); + + len-=4; + if(len < 0) len = 0; + while(s->str[len]) len++; + s->len=len; + s=end_shared_string(s); + push_string(s); +} + +static void mpzmod_cast(INT32 args) +{ + if(args < 1) + error("mpz->cast() called without arguments.\n"); + if(sp[-args].type != T_STRING) + error("Bad argument 1 to mpz->cast().\n"); + + switch(sp[-args].u.string->str[0]) + { + case 'i': + if(!strcmp(sp[-args].u.string->str, "int")) + { + mpzmod_get_int(args); + return; + } + break; + + case 's': + if(!strcmp(sp[-args].u.string->str, "string")) + { + mpzmod_get_string(args); + return; + } + break; + + case 'f': + if(!strcmp(sp[-args].u.string->str, "float")) + { + mpzmod_get_float(args); + return; + } + break; + + case 'o': + if(!strcmp(sp[-args].u.string->str, "object")) + { + pop_n_elems(args); + push_object(this_object()); + } + break; + + case 'm': + if(!strcmp(sp[-args].u.string->str, "mixed")) + { + pop_n_elems(args); + push_object(this_object()); + } + break; + + } + + error("mpz->cast() to other type than string, int or float.\n"); +} + +static MP_INT *get_mpz(struct svalue *s) +{ + struct object *o; + switch(s->type) + { + default: + error("Wrong type of object, cannot convert to mpz.\n"); + return 0; + + case T_INT: + case T_FLOAT: + case T_STRING: + o=clone(mpzmod_program,0); + get_new_mpz(OBTOMPZ(o), s); + free_svalue(s); + s->u.object=o; + s->type=T_OBJECT; + return (MP_INT *)o->storage; + + case T_OBJECT: + if(s->u.object->prog != mpzmod_program) + error("Wrong type of object, cannot convert to mpz.\n"); + + return (MP_INT *)s->u.object->storage; + } +} + +/* These two functions are here so we can allocate temporary + * objects without having to worry about them leaking in + * case of errors.. + */ +static struct object *temporary; +MP_INT *get_tmp() +{ + if(!temporary) + temporary=clone(mpzmod_program,0); + + return (MP_INT *)temporary->storage; +} + +static void return_temporary(INT32 args) +{ + pop_n_elems(args); + push_object(temporary); + temporary=0; +} + +#define BINFUN(name, fun) \ +static void name(INT32 args) \ +{ \ + INT32 e; \ + MP_INT *tmp=get_tmp(); \ + mpz_set(tmp, THIS); \ + for(e=0;e<args;e++) \ + fun(tmp, tmp, get_mpz(sp+e-args)); \ + return_temporary(args); \ +} + +BINFUN(mpzmod_add,mpz_add) +BINFUN(mpzmod_mul,mpz_mul) +BINFUN(mpzmod_gcd,mpz_gcd) + +static void mpzmod_sub(INT32 args) +{ + INT32 e; + MP_INT *tmp=get_tmp(); + mpz_set(tmp, THIS); + + if(args) + { + for(e=0;e<args;e++) + mpz_sub(tmp, tmp, get_mpz(sp+e-args)); + }else{ + mpz_neg(tmp, tmp); + } + + return_temporary(args); +} + +static void mpzmod_div(INT32 args) +{ + INT32 e; + MP_INT *tmp=get_tmp(); + mpz_set(tmp, THIS); + + for(e=0;e<args;e++) + { + MP_INT *tmp2; + tmp2=get_mpz(sp+e-args); + if(!mpz_sgn(tmp2)) + error("Division by zero.\n"); + mpz_tdiv_q(tmp, tmp, tmp2); + } + return_temporary(args); +} + +static void mpzmod_mod(INT32 args) +{ + INT32 e; + MP_INT *tmp=get_tmp(); + mpz_set(tmp, THIS); + + for(e=0;e<args;e++) + { + MP_INT *tmp2; + tmp2=get_mpz(sp+e-args); + if(!mpz_sgn(tmp2)) + error("Modulo by zero.\n"); + mpz_tdiv_r(tmp, tmp, tmp2); + } + return_temporary(args); +} + + +BINFUN(mpzmod_and,mpz_and) +BINFUN(mpzmod_or,mpz_ior) + +static void mpzmod_compl(INT32 args) +{ + struct object *o; + pop_n_elems(args); + o=clone(mpzmod_program,0); + push_object(o); + mpz_com(OBTOMPZ(o), THIS); +} + + +#define CMPFUN(name,cmp) \ +static void name(INT32 args) \ +{ \ + INT32 i; \ + if(!args) error("Comparison with one argument?\n"); \ + i=mpz_cmp(THIS, get_mpz(sp-args)) cmp 0; \ + pop_n_elems(args); \ + push_int(i); \ +} + +CMPFUN(mpzmod_gt, >) +CMPFUN(mpzmod_lt, <) +CMPFUN(mpzmod_ge, >=) +CMPFUN(mpzmod_le, <=) +CMPFUN(mpzmod_eq, ==) +CMPFUN(mpzmod_nq, !=) + +static void mpzmod_probably_prime_p(INT32 args) +{ + pop_n_elems(args); + push_int(mpz_probab_prime_p(THIS, 25)); +} + +static void mpzmod_sgn(INT32 args) +{ + pop_n_elems(args); + push_int(mpz_sgn(THIS)); +} + + +static void mpzmod_sqrt(INT32 args) +{ + struct object *o; + pop_n_elems(args); + if(mpz_sgn(THIS)<0) + error("mpz->sqrt() on negative number.\n"); + + o=clone(mpzmod_program,0); + push_object(o); + mpz_sqrt(OBTOMPZ(o), THIS); +} + +static void mpzmod_lsh(INT32 args) +{ + MP_INT *tmp; + pop_n_elems(args-1); + push_string(int_type_string); + int_type_string->refs++; + f_cast(2); + tmp=get_tmp(); + if(sp[-1].u.integer < 0) + error("mpz->lsh on negative number.\n"); + mpz_mul_2exp(tmp, THIS, sp[-1].u.integer); + return_temporary(1); +} + +static void mpzmod_rsh(INT32 args) +{ + MP_INT *tmp; + pop_n_elems(args-1); + push_string(int_type_string); + int_type_string->refs++; + f_cast(2); + tmp=get_tmp(); + mpz_set_ui(tmp,1); + mpz_mul_2exp(tmp, tmp, sp[-1].u.integer); + mpz_tdiv_q(tmp, THIS, tmp); + return_temporary(1); +} + +static void mpzmod_powm(INT32 args) +{ + MP_INT *tmp; + if(args < 2) + error("Too few arguments to mpzmod->powm()\n"); + + tmp=get_tmp(); + mpz_powm(tmp, tmp, get_mpz(sp-args), get_mpz(sp+1-args)); + return_temporary(args); +} + +static void mpzmod_not(INT32 args) +{ + pop_n_elems(args); + push_int(!mpz_sgn(THIS)); +} + +static void init_mpz_glue(char *foo, struct object *o) +{ + mpz_init(THIS); +} + +static void exit_mpz_glue(char *foo, struct object *o) +{ + mpz_clear(THIS); +} + +#endif + +void init_gmpmod_efuns(void) {} +void exit_gmpmod(void) +{ + if(temporary) free_object(temporary); + free_program(mpzmod_program); +} + +void init_gmpmod_programs(void) +{ +#ifdef HAVE_GMP_H + start_new_program(); + add_storage(sizeof(mpz_t)); + + add_function("create",mpzmod_create,"function(void|string|int|float|object:void)",0); + +#define MPZ_BINOP_TYPE "function(string|int|float|object...:object)" + + add_function("`+",mpzmod_add,MPZ_BINOP_TYPE,0); + add_function("`-",mpzmod_sub,MPZ_BINOP_TYPE,0); + add_function("`*",mpzmod_mul,MPZ_BINOP_TYPE,0); + add_function("`/",mpzmod_div,MPZ_BINOP_TYPE,0); + add_function("`%",mpzmod_mod,MPZ_BINOP_TYPE,0); + add_function("`&",mpzmod_and,MPZ_BINOP_TYPE,0); + add_function("`|",mpzmod_or,MPZ_BINOP_TYPE,0); + +#define MPZ_SHIFT_TYPE "function(object|int|float|object:object)" + add_function("`<<",mpzmod_lsh,MPZ_SHIFT_TYPE,0); + add_function("`>>",mpzmod_rsh,MPZ_SHIFT_TYPE,0); + +#define MPZ_CMPOP_TYPE "function(string|int|float|object:int)" + + add_function("`>", mpzmod_gt,MPZ_CMPOP_TYPE,0); + add_function("`<", mpzmod_lt,MPZ_CMPOP_TYPE,0); + add_function("`>=",mpzmod_ge,MPZ_CMPOP_TYPE,0); + add_function("`<=",mpzmod_le,MPZ_CMPOP_TYPE,0); + + add_function("`==",mpzmod_le,MPZ_CMPOP_TYPE,0); + add_function("`!=",mpzmod_le,MPZ_CMPOP_TYPE,0); + + add_function("`!",mpzmod_not,"function(:int)",0); + + add_function("__hash",mpzmod_get_int,"function(:int)",0); + add_function("cast",mpzmod_cast,"function(string:mixed)",0); + + add_function("cast_to_int",mpzmod_get_int,"function(:int)",0); + add_function("cast_to_string",mpzmod_get_string,"function(:string)",0); + add_function("cast_to_float",mpzmod_get_float,"function(:float)",0); + + add_function("probably_prime_p",mpzmod_probably_prime_p,"function(:int)",0); + add_function("gcd",mpzmod_gcd,"function(object|string|int|float...:object)",0); + add_function("sqrt",mpzmod_gcd,"function(:object)",0); + add_function("`~",mpzmod_gcd,"function(:object)",0); + add_function("powm",mpzmod_gcd,"function(object|string|int|float,object|string|int|float:object)",0); + + set_init_callback(init_mpz_glue); + set_exit_callback(exit_mpz_glue); + + mpzmod_program=end_c_program("/precompiled/mpz"); + mpzmod_program->refs++; +#endif +} +