From a80a9c117f1bc4f26f067c6253170c14c63694ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20H=C3=BCbinette=20=28Hubbe=29?= <hubbe@hubbe.net> Date: Tue, 11 Feb 1997 00:08:54 -0800 Subject: [PATCH] files moved for new module system Rev: src/modules/Gdbm/.cvsignore:1.1 Rev: src/modules/Gdbm/Makefile.in:1.1 Rev: src/modules/Gdbm/configure.in:1.1 Rev: src/modules/Gdbm/doc/gdbm:1.1 Rev: src/modules/Gdbm/gdbm_machine.h.in:1.1 Rev: src/modules/Gdbm/gdbmmod.c:1.1 Rev: src/modules/Gdbm/testsuite.in:1.1 Rev: src/modules/Gmp/.cvsignore:1.1 Rev: src/modules/Gmp/Makefile.in:1.1 Rev: src/modules/Gmp/configure.in:1.1 Rev: src/modules/Gmp/doc/mpz:1.1 Rev: src/modules/Gmp/gmp_machine.h.in:1.1 Rev: src/modules/Gmp/mpz_glue.c:1.1 Rev: src/modules/Gmp/testsuite.in:1.1 --- .gitattributes | 2 + src/modules/Gdbm/.cvsignore | 10 + src/modules/Gdbm/.gitignore | 10 + src/modules/Gdbm/Makefile.in | 7 + src/modules/Gdbm/configure.in | 15 + src/modules/Gdbm/doc/gdbm | 150 +++++++ src/modules/Gdbm/gdbm_machine.h.in | 10 + src/modules/Gdbm/gdbmmod.c | 358 ++++++++++++++++ src/modules/Gdbm/testsuite.in | 52 +++ src/modules/Gmp/.cvsignore | 9 + src/modules/Gmp/.gitignore | 9 + src/modules/Gmp/Makefile.in | 7 + src/modules/Gmp/configure.in | 16 + src/modules/Gmp/doc/mpz | 136 ++++++ src/modules/Gmp/gmp_machine.h.in | 10 + src/modules/Gmp/mpz_glue.c | 666 +++++++++++++++++++++++++++++ src/modules/Gmp/testsuite.in | 57 +++ 17 files changed, 1524 insertions(+) create mode 100644 src/modules/Gdbm/.cvsignore create mode 100644 src/modules/Gdbm/.gitignore create mode 100644 src/modules/Gdbm/Makefile.in create mode 100644 src/modules/Gdbm/configure.in create mode 100644 src/modules/Gdbm/doc/gdbm create mode 100644 src/modules/Gdbm/gdbm_machine.h.in create mode 100644 src/modules/Gdbm/gdbmmod.c create mode 100644 src/modules/Gdbm/testsuite.in create mode 100644 src/modules/Gmp/.cvsignore create mode 100644 src/modules/Gmp/.gitignore create mode 100644 src/modules/Gmp/Makefile.in create mode 100644 src/modules/Gmp/configure.in create mode 100644 src/modules/Gmp/doc/mpz create mode 100644 src/modules/Gmp/gmp_machine.h.in create mode 100644 src/modules/Gmp/mpz_glue.c create mode 100644 src/modules/Gmp/testsuite.in diff --git a/.gitattributes b/.gitattributes index 5317cf7304..ad0703b1d1 100644 --- a/.gitattributes +++ b/.gitattributes @@ -20,6 +20,8 @@ testfont binary /src/lex.c foreign_ident /src/main.c foreign_ident /src/mapping.c foreign_ident +/src/modules/Gdbm/gdbmmod.c foreign_ident +/src/modules/Gmp/mpz_glue.c foreign_ident /src/modules/_Crypto/cbc.c foreign_ident /src/modules/_Crypto/crypto.c foreign_ident /src/modules/_Crypto/crypto.h foreign_ident diff --git a/src/modules/Gdbm/.cvsignore b/src/modules/Gdbm/.cvsignore new file mode 100644 index 0000000000..aad00c7c3e --- /dev/null +++ b/src/modules/Gdbm/.cvsignore @@ -0,0 +1,10 @@ + +.pure +Makefile +config.log +config.status +configure +dependencies +gdbm_machine.h +linker_options +stamp-h diff --git a/src/modules/Gdbm/.gitignore b/src/modules/Gdbm/.gitignore new file mode 100644 index 0000000000..0a44e55840 --- /dev/null +++ b/src/modules/Gdbm/.gitignore @@ -0,0 +1,10 @@ + +/.pure +/Makefile +/config.log +/config.status +/configure +/dependencies +/gdbm_machine.h +/linker_options +/stamp-h diff --git a/src/modules/Gdbm/Makefile.in b/src/modules/Gdbm/Makefile.in new file mode 100644 index 0000000000..75379bf80d --- /dev/null +++ b/src/modules/Gdbm/Makefile.in @@ -0,0 +1,7 @@ +SRCDIR=@srcdir@ +VPATH=@srcdir@:@srcdir@/../..:../.. +MODULE_LDFLAGS=@LIBS@ +OBJS=gdbmmod.o + +@static_module_makefile@ +@dependencies@ diff --git a/src/modules/Gdbm/configure.in b/src/modules/Gdbm/configure.in new file mode 100644 index 0000000000..1ae3ef7fa6 --- /dev/null +++ b/src/modules/Gdbm/configure.in @@ -0,0 +1,15 @@ +AC_INIT(gdbmmod.c) +AC_CONFIG_HEADER(gdbm_machine.h) + +AC_ARG_WITH(gdbm, [ --with(out)-gdbm GNU database manager support ],[],[with_gdbm=yes]) + +sinclude(../module_configure.in) + +if test x$with_gdbm = xyes; then + AC_CHECK_HEADERS(gdbm.h) + AC_CHECK_LIB(gdbm, gdbm_open) +fi + +AC_OUTPUT(Makefile,echo FOO >stamp-h ) + + diff --git a/src/modules/Gdbm/doc/gdbm b/src/modules/Gdbm/doc/gdbm new file mode 100644 index 0000000000..ddf660a793 --- /dev/null +++ b/src/modules/Gdbm/doc/gdbm @@ -0,0 +1,150 @@ +NAME + /precompiled/gdbm - database interface + +DESCRIPTION + This is the an interface to the gdbm library. This module might or + might not be available in your Pike depending on weather gdbm was + available when Pike was compiled. + + A gdbm database has essentially the same functionality as a mapping, + except the syntax is different, and it is located on disk, not in + memory. Each gdbm database is one file which contains a set of + key-value pairs. Both keys and values are strings and all keys are + unique. + +============================================================================ +NAME + create - open database + +SYNTAX + int gdbm->create(); + or + int gdbm->create(string file); + or + int gdbm->create(string file, string mode); + +DESCRIPTION + Without arguments, this function does nothing. With one argument it + opens the given file as a gdbm database, if this fails for some + reason, an error will be generated. If a second argument is present, + it specifies how to open the database using one or more of the follow + flags in a string: + + r open database for reading + w open database for writing + c create database if it does not exist + t overwrite existing database + f fast mode + + The fast mode prevents the database from syncronizing each change + in the database immediately. This is dangerous because the database + can be left in an unusable state if Pike is terminated abnormally. + + The default mode is "rwc". + +NOTA BENE + The gdbm manual states that it is important that the database is + closed properly. Unfortunately this will not be the case if Pike + calls exit() or returns from main(). You should therefore make sure + you call close or destruct your gdbm objects when exiting your + program. This will probably be done automatically in the future. + +============================================================================ +NAME + close - close database + +SYNTAX + void gdbm->close(); + +DESCRIPTION + This closes the database. + +============================================================================ +NAME + store - store a value in the database + +SYNTAX + int gdbm->store(string key, string data); + +DESCRIPTION + Associate the contents of 'data' with the key 'key'. If the key 'key' + already exists in the database the data for that key will be replaced. + If it does not exist it will be added. An error will be generated if + the database was not open for writing. + +============================================================================ +NAME + fetch - fetch a value from the databse + +SYNTAX + string gdbm->fetch(string key); + +DESCRIPTION + Return the data associated with the key 'key' in the database. + If there was no such key in the database, zero is returned. + +============================================================================ +NAME + delete - delete a value from the database + +SYNTAX + int gdbm->delete(string key); + +DESCRIPTION + Remove a key from the database. Note that no error will be generated + if the key does not exist. + +============================================================================ +NAME + firstkey - get first key in database + +SYNTAX + string gdbm->firstkey(); + +DESCRIPTION + Return the first key in the database, this can be any key in the + database. + +============================================================================ +NAME + nextkey - get next key in database + +SYNTAX + string gdbm->nextkey(string key); + +DESCRIPTION + This returns the key in database that follows the key 'key' key. + This is of course used to iterate over all keys in the database. + +EXAMPLE + /* Write the contents of the database */ + for(key=gdbm->firstkey(); k; k=gdbm->nextkey(k)) + write(k+":"+gdbm->fetch(k)+"\n"); + +============================================================================ +NAME + reorganize - reorganize database + +SYNTAX + int gdbm->reorganize(); + +DESCRIPTION + Deletions and insertions into the database can cause fragmentation + which will make the database bigger. This routine reorganizes the + contents to get rid of fragmentation. Note however that this function + can take a LOT of time to run. + +============================================================================ +NAME + sync - synchronize database + +SYNTAX + void gdbm->sync(); + +DESCRIPTION + When opening the database with the 'f' flag writings to the database + can be cached in memory for a long time. Calling sync will write + all such caches to disk and not return until everything is stored + on the disk. + +============================================================================ diff --git a/src/modules/Gdbm/gdbm_machine.h.in b/src/modules/Gdbm/gdbm_machine.h.in new file mode 100644 index 0000000000..e0768c6db7 --- /dev/null +++ b/src/modules/Gdbm/gdbm_machine.h.in @@ -0,0 +1,10 @@ +#ifndef GDBM_MACHINE_H +#define GDBM_MACHINE_H + +/* Define this if you have <gdbm.h> */ +#undef HAVE_GDBM_H + +/* Define this if you have libgdbm */ +#undef HAVE_LIBGDBM + +#endif diff --git a/src/modules/Gdbm/gdbmmod.c b/src/modules/Gdbm/gdbmmod.c new file mode 100644 index 0000000000..ee01ec75c0 --- /dev/null +++ b/src/modules/Gdbm/gdbmmod.c @@ -0,0 +1,358 @@ +/*\ +||| This file a part of Pike, and is copyright by Fredrik Hubinette +||| Pike is distributed as GPL (General Public License) +||| See the files COPYING and DISCLAIMER for more information. +\*/ +#include "global.h" +RCSID("$Id: gdbmmod.c,v 1.1 1997/02/11 08:00:50 hubbe Exp $"); +#include "gdbm_machine.h" +#include "types.h" +#include "threads.h" + +/* Todo: make sure only one thread accesses the same gdbmmod */ + +#if defined(HAVE_GDBM_H) && defined(HAVE_LIBGDBM) + +#include "interpret.h" +#include "svalue.h" +#include "stralloc.h" +#include "array.h" +#include "object.h" +#include "macros.h" + +#include <gdbm.h> + +#ifdef _REENTRANT +static MUTEX_T gdbm_lock; +#endif + +struct gdbm_glue +{ + GDBM_FILE dbf; +}; + +#define THIS ((struct gdbm_glue *)(fp->current_storage)) + +static void do_free() +{ + if(THIS->dbf) + { + GDBM_FILE dbf; + dbf=THIS->dbf; + THIS->dbf=0; + + THREADS_ALLOW(); + mt_lock(& gdbm_lock); + gdbm_close(dbf); + mt_unlock(& gdbm_lock); + THREADS_DISALLOW(); + } +} + +static int fixmods(char *mods) +{ + int mode; + mode=0; + while(1) + { + switch(*(mods++)) + { + case 0: + switch(mode & 15) + { + default: error("No mode given for gdbm->open()\n"); + case 1|16: + case 1: mode=GDBM_READER; break; + case 3: mode=GDBM_WRITER; break; + case 3|16: mode=GDBM_WRITER | GDBM_FAST; break; + case 7: mode=GDBM_WRCREAT; break; + case 7|16: mode=GDBM_WRCREAT | GDBM_FAST; break; + case 15: mode=GDBM_NEWDB; break; + case 15|16: mode=GDBM_NEWDB | GDBM_FAST; break; + } + return mode; + + case 'r': case 'R': mode|=1; break; + case 'w': case 'W': mode|=3; break; + case 'c': case 'C': mode|=7; break; + case 't': case 'T': mode|=15; break; + case 'f': case 'F': mode|=16; break; + + default: + error("Bad mode flag in gdbm->open.\n"); + } + } +} + +void gdbmmod_fatal(char *err) +{ + error("GDBM: %s\n",err); +} + +static void gdbmmod_create(INT32 args) +{ + struct gdbm_glue *this=THIS; + do_free(); + if(args) + { + GDBM_FILE tmp; + struct pike_string *tmp2; + int rwmode = GDBM_WRCREAT; + + if(sp[-args].type != T_STRING) + error("Bad argument 1 to gdbm->create()\n"); + + if(args>1) + { + if(sp[1-args].type != T_STRING) + error("Bad argument 2 to gdbm->create()\n"); + + rwmode=fixmods(sp[1-args].u.string->str); + } + + tmp2=sp[-args].u.string; + + THREADS_ALLOW(); + mt_lock(& gdbm_lock); + tmp=gdbm_open(tmp2->str, 512, rwmode, 00666, gdbmmod_fatal); + mt_unlock(& gdbm_lock); + THREADS_DISALLOW(); + + if(!fp->current_object->prog) + { + if(tmp) gdbm_close(tmp); + error("Object destructed in gdbm->open()n"); + } + THIS->dbf=tmp; + + pop_n_elems(args); + if(!THIS->dbf) + error("Failed to open GDBM database.\n"); + } +} + +#define STRING_TO_DATUM(dat, st) dat.dptr=st->str,dat.dsize=st->len; +#define DATUM_TO_STRING(dat) make_shared_binary_string(dat.dptr, dat.dsize) + +static void gdbmmod_fetch(INT32 args) +{ + struct gdbm_glue *this=THIS; + datum key,ret; + + if(!args) + error("Too few arguments to gdbm->fetch()\n"); + + if(sp[-args].type != T_STRING) + error("Bad argument 1 to gdbm->fetch()\n"); + + if(!THIS->dbf) + error("GDBM database not open.\n"); + + STRING_TO_DATUM(key, sp[-args].u.string); + + THREADS_ALLOW(); + mt_lock(& gdbm_lock); + ret=gdbm_fetch(this->dbf, key); + mt_unlock(& gdbm_lock); + THREADS_DISALLOW(); + + pop_n_elems(args); + if(ret.dptr) + { + push_string(DATUM_TO_STRING(ret)); + free(ret.dptr); + }else{ + push_int(0); + } +} + +static void gdbmmod_delete(INT32 args) +{ + struct gdbm_glue *this=THIS; + datum key; + int ret; + if(!args) + error("Too few arguments to gdbm->delete()\n"); + + if(sp[-args].type != T_STRING) + error("Bad argument 1 to gdbm->delete()\n"); + + if(!this->dbf) + error("GDBM database not open.\n"); + + STRING_TO_DATUM(key, sp[-args].u.string); + + THREADS_ALLOW(); + mt_lock(& gdbm_lock); + ret=gdbm_delete(this->dbf, key); + mt_unlock(& gdbm_lock); + THREADS_DISALLOW(); + + pop_n_elems(args); + push_int(0); +} + +static void gdbmmod_firstkey(INT32 args) +{ + struct gdbm_glue *this=THIS; + datum ret; + pop_n_elems(args); + + if(!this->dbf) error("GDBM database not open.\n"); + + THREADS_ALLOW(); + mt_lock(& gdbm_lock); + ret=gdbm_firstkey(this->dbf); + mt_unlock(& gdbm_lock); + THREADS_DISALLOW(); + + if(ret.dptr) + { + push_string(DATUM_TO_STRING(ret)); + free(ret.dptr); + }else{ + push_int(0); + } +} + +static void gdbmmod_nextkey(INT32 args) +{ + struct gdbm_glue *this=THIS; + datum key,ret; + if(!args) + error("Too few arguments to gdbm->nextkey()\n"); + + if(sp[-args].type != T_STRING) + error("Bad argument 1 to gdbm->nextkey()\n"); + + if(!THIS->dbf) + error("GDBM database not open.\n"); + + STRING_TO_DATUM(key, sp[-args].u.string); + + THREADS_ALLOW(); + mt_lock(& gdbm_lock); + ret=gdbm_nextkey(this->dbf, key); + mt_unlock(& gdbm_lock); + THREADS_DISALLOW(); + + pop_n_elems(args); + if(ret.dptr) + { + push_string(DATUM_TO_STRING(ret)); + free(ret.dptr); + }else{ + push_int(0); + } +} + +static void gdbmmod_store(INT32 args) +{ + struct gdbm_glue *this=THIS; + datum key,data; + int ret; + if(args<2) + error("Too few arguments to gdbm->store()\n"); + + if(sp[-args].type != T_STRING) + error("Bad argument 1 to gdbm->store()\n"); + + if(sp[1-args].type != T_STRING) + error("Bad argument 2 to gdbm->store()\n"); + + if(!THIS->dbf) + error("GDBM database not open.\n"); + + STRING_TO_DATUM(key, sp[-args].u.string); + STRING_TO_DATUM(data, sp[1-args].u.string); + + THREADS_ALLOW(); + mt_lock(& gdbm_lock); + ret=gdbm_store(this->dbf, key, data, GDBM_REPLACE); + mt_unlock(& gdbm_lock); + THREADS_DISALLOW(); + + if(ret == -1) + error("GDBM database not open for writing.\n"); + + pop_n_elems(args); + push_int(ret == 0); +} + +static void gdbmmod_reorganize(INT32 args) +{ + struct gdbm_glue *this=THIS; + int ret; + pop_n_elems(args); + + if(!THIS->dbf) error("GDBM database not open.\n"); + THREADS_ALLOW(); + mt_lock(& gdbm_lock); + ret=gdbm_reorganize(this->dbf); + mt_unlock(& gdbm_lock); + THREADS_DISALLOW(); + pop_n_elems(args); + push_int(ret); +} + +static void gdbmmod_sync(INT32 args) +{ + struct gdbm_glue *this=THIS; + pop_n_elems(args); + + if(!THIS->dbf) error("GDBM database not open.\n"); + THREADS_ALLOW(); + mt_lock(& gdbm_lock); + gdbm_sync(this->dbf); + mt_unlock(& gdbm_lock); + THREADS_DISALLOW(); + push_int(0); +} + +static void gdbmmod_close(INT32 args) +{ + pop_n_elems(args); + + do_free(THIS->dbf); + push_int(0); +} + +static void init_gdbm_glue(struct object *o) +{ + THIS->dbf=0; +} + +static void exit_gdbm_glue(struct object *o) +{ + do_free(); +} + +#endif + +void pike_module_exit(void) {} + +void pike_module_init(void) +{ +#if defined(HAVE_GDBM_H) && defined(HAVE_LIBGDBM) + start_new_program(); + add_storage(sizeof(struct gdbm_glue)); + + add_function("create",gdbmmod_create,"function(void|string,void|string:void)",0); + + add_function("close",gdbmmod_close,"function(:void)",0); + add_function("store",gdbmmod_store,"function(string,string:int)",0); + add_function("`[]=",gdbmmod_store,"function(string,string:int)",0); + add_function("fetch",gdbmmod_fetch,"function(string:string)",0); + add_function("`[]",gdbmmod_fetch,"function(string:string)",0); + add_function("delete",gdbmmod_delete,"function(string:int)",0); + add_function("firstkey",gdbmmod_firstkey,"function(:string)",0); + add_function("nextkey",gdbmmod_nextkey,"function(string:string)",0); + add_function("reorganize",gdbmmod_reorganize,"function(:int)",0); + add_function("sync",gdbmmod_sync,"function(:void)",0); + + set_init_callback(init_gdbm_glue); + set_exit_callback(exit_gdbm_glue); + end_class("gdbm",0); +#endif +} + diff --git a/src/modules/Gdbm/testsuite.in b/src/modules/Gdbm/testsuite.in new file mode 100644 index 0000000000..e1ce5f879b --- /dev/null +++ b/src/modules/Gdbm/testsuite.in @@ -0,0 +1,52 @@ +// gdbm +cond( [[ master()->programs["/precompiled/gdbm"] ]], +[[ + define([[GDBM]],[[ (program)"/precompiled/gdbm" ]]) + test_true(programp(GDBM)) + test_do(destruct(clone(GDBM))) + + define([[GDBMTESTS]], + [[ + test_do(rm("test.gdbm")) + test_do(add_efun("GDBMBASE",clone(GDBM,"test.gdbm"))) + test_true(file_stat("test.gdbm")) + + GDBMNULLTEST + test_true(GDBMBASE->store("foo","bar")) + GDBMNULLTEST + test_equal(GDBMBASE->fetch("foo"),"bar") + test_do([[int e; for(e=0;e<100;e++) GDBMBASE->store("x"+e,"y"+e)]]) + GDBMNULLTEST + test_any(int e; for(e=0;e<100;e++) if(GDBMBASE->fetch("x"+e)!="y"+e) return e; return -1,-1) + GDBMNULLTEST + test_true(GDBMBASE->store(sprintf("%'23'100000s","") , sprintf("%'32'100000s",""))) + test_true(GDBMBASE->fetch(sprintf("%'23'100000s",""))==sprintf("%'32'100000s","")) + GDBMNULLTEST + test_equal(GDBMBASE->fetch("foo"),"bar") + test_any(int e; for(e=0;e<100;e++) if(GDBMBASE->fetch("x"+e)!="y"+e) return e; return -1,-1) + test_true(GDBMBASE->fetch(sprintf("%'23'100000s",""))==sprintf("%'32'100000s","")) + test_any(int e; string k; for(k=GDBMBASE->firstkey();k;k=GDBMBASE->nextkey(k)) e++; return e,102) + + test_do(GDBMBASE->sync()) + test_do(GDBMBASE->reorganize()) + test_do(GDBMBASE->close()) + ]]) + + define([[GDBMNULLTEST]],[[ + test_false(GDBMBASE->fetch("slakjdfasdf")) + ]]) + + GDBMTESTS + + define([[GDBMNULLTEST]],[[ + test_false(GDBMBASE->fetch("slakjdfasdf")) + test_do(GDBMBASE->reorganize()) + test_do(GDBMBASE->sync()) + test_do(GDBMBASE->close()) + test_do(GDBMBASE->create("test.gdbm")) + ]]) + + GDBMTESTS + + test_do(rm("test.gdbm")) +]]) diff --git a/src/modules/Gmp/.cvsignore b/src/modules/Gmp/.cvsignore new file mode 100644 index 0000000000..86d2c454d7 --- /dev/null +++ b/src/modules/Gmp/.cvsignore @@ -0,0 +1,9 @@ +.pure +Makefile +config.log +config.status +configure +dependencies +gmp_machine.h +linker_options +stamp-h diff --git a/src/modules/Gmp/.gitignore b/src/modules/Gmp/.gitignore new file mode 100644 index 0000000000..f201fb660d --- /dev/null +++ b/src/modules/Gmp/.gitignore @@ -0,0 +1,9 @@ +/.pure +/Makefile +/config.log +/config.status +/configure +/dependencies +/gmp_machine.h +/linker_options +/stamp-h diff --git a/src/modules/Gmp/Makefile.in b/src/modules/Gmp/Makefile.in new file mode 100644 index 0000000000..a7c8bf3359 --- /dev/null +++ b/src/modules/Gmp/Makefile.in @@ -0,0 +1,7 @@ +SRCDIR=@srcdir@ +VPATH=@srcdir@:@srcdir@/../..:../.. +MODULE_LDFLAGS=@LIBS@ +OBJS=mpz_glue.o + +@static_module_makefile@ +@dependencies@ diff --git a/src/modules/Gmp/configure.in b/src/modules/Gmp/configure.in new file mode 100644 index 0000000000..0df3eec924 --- /dev/null +++ b/src/modules/Gmp/configure.in @@ -0,0 +1,16 @@ +AC_INIT(mpz_glue.c) +AC_CONFIG_HEADER(gmp_machine.h) +AC_ARG_WITH(gmp, [ --with(out)-gmp Support bignums],[],[with_gmp=yes]) + +sinclude(../module_configure.in) + +if test x$with_gmp = xyes ; then + AC_CHECK_HEADERS(gmp.h) + if test $ac_cv_header_gmp_h = yes ; then + AC_CHECK_LIB(gmp, mpz_set_d) + fi +fi + +AC_OUTPUT(Makefile,echo FOO >stamp-h ) + + diff --git a/src/modules/Gmp/doc/mpz b/src/modules/Gmp/doc/mpz new file mode 100644 index 0000000000..2b4c0bc67e --- /dev/null +++ b/src/modules/Gmp/doc/mpz @@ -0,0 +1,136 @@ +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 Pike was compiled. + +============================================================================ +NAME + create - initialize a bignum + +SYNTAX + object Mpz(); + or + object Mpz(int|object|float i); + or + object Mpz(string digits, int base); + + +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. You can also + give the number in the string in another base by specifying the + base as a second argument. Valid bases are 2-36 and 256. + +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. + +============================================================================ +NAME + cast - cast to other type + +SYNTAX + object mpz->gcd( "string" | "int" | "float" ); + or + (string) mpz + or + (int) mpz + or + (float) mpz + + +DESCRIPTION + This function converts an mpz to a string, int or float. This is + nessesary when you want to view, store or use the result of an mpz + calculation. + +SEE ALSO + cast + +============================================================================ +NAME + digits - convert mpz to a string + +SYNTAX + string mpz->digits(); + or + string mpz->digits(int base); + +DESCRIPTION + This function converts an mpz to a string. If a base is given the + number will be represented in that base. Valid bases are 2-36 and + 256. The default base is 10. + +SEE ALSO + mpz->cast + +============================================================================ +NAME + size - how long is a number + +SYNTAX + string mpz->size(); + or + string mpz->size(int base); + +DESCRIPTION + This function returns how long the mpz would be represented in the + specified base. The default base is 2. + +SEE ALSO + mpz->digits + +============================================================================ diff --git a/src/modules/Gmp/gmp_machine.h.in b/src/modules/Gmp/gmp_machine.h.in new file mode 100644 index 0000000000..f304d6b576 --- /dev/null +++ b/src/modules/Gmp/gmp_machine.h.in @@ -0,0 +1,10 @@ +#ifndef GMP_MACHINE_H +#define GMP_MACHINE_H + +/* Define this if you have <gmp.h> */ +#undef HAVE_GMP_H + +/* Define this if you have -lgmp */ +#undef HAVE_LIBGMP + +#endif diff --git a/src/modules/Gmp/mpz_glue.c b/src/modules/Gmp/mpz_glue.c new file mode 100644 index 0000000000..0c77e0e96f --- /dev/null +++ b/src/modules/Gmp/mpz_glue.c @@ -0,0 +1,666 @@ +/*\ +||| This file a part of Pike, and is copyright by Fredrik Hubinette +||| Pike is distributed as GPL (General Public License) +||| See the files COPYING and DISCLAIMER for more information. +\*/ +#include "global.h" +RCSID("$Id: mpz_glue.c,v 1.1 1997/02/11 08:08:40 hubbe Exp $"); +#include "gmp_machine.h" +#include "types.h" + +#if !defined(HAVE_LIBGMP) +#undef HAVE_GMP_H +#endif + +#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 "pike_types.h" + +#include <gmp.h> +#include <assert.h> + +#define THIS ((MP_INT *)(fp->current_storage)) +#define OBTOMPZ(o) ((MP_INT *)(o->storage)) + +static struct program *mpzmod_program; + +static void get_mpz_from_digits(MP_INT *tmp, + struct pike_string *digits, + int base) +{ + if(!base || ((base >= 2) && (base <= 36))) + { + if (mpz_set_str(tmp, digits->str, base)) + error("invalid digits, cannot convert to mpz"); + } + else if(base == 256) + { + + INT8 i; + mpz_t digit; + + mpz_init(digit); + mpz_set_ui(tmp, 0); + for (i = 0; i < digits->len; i++) + { + mpz_set_ui(digit, EXTRACT_UCHAR(digits->str + i)); + mpz_mul_2exp(digit, digit, (digits->len - i - 1) * 8); + mpz_ior(tmp, tmp, digit); + } + } + else + { + error("invalid base.\n"); + } +} + +static void get_new_mpz(MP_INT *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_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; +#if 0 + case T_STRING: + mpz_set_str(tmp, s->u.string->str, 0); + break; + + case T_ARRAY: /* Experimental */ + if ( (s->u.array->size != 2) + || (ITEM(s->u.array)[0].type != T_STRING) + || (ITEM(s->u.array)[1].type != T_INT)) + error("cannot convert array to mpz.\n"); + get_mpz_from_digits(tmp, ITEM(s->u.array)[0].u.string, + ITEM(s->u.array)[1]); + break; +#endif + default: + error("cannot convert argument to mpz.\n"); + } +} + +static void mpzmod_create(INT32 args) +{ + switch(args) + { + case 1: + if(sp[-args].type == T_STRING) + get_mpz_from_digits(THIS, sp[-args].u.string, 0); + else + get_new_mpz(THIS, sp-args); + break; + + case 2: /* Args are string of digits and integer base */ + if(sp[-args].type != T_STRING) + error("bad argument 1 for Mpz->create()"); + + if (sp[1-args].type != T_INT) + error("wrong type for base in Mpz->create()"); + + get_mpz_from_digits(THIS, sp[-args].u.string, sp[1-args].u.integer); + break; + + default: + error("Too many arguments to Mpz->create()\n"); + + case 0: + break; /* Needed by AIX cc */ + } + 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 struct pike_string *low_get_digits(MP_INT *mpz, int base) +{ + struct pike_string *s; + INT32 len; + + if ( (base >= 2) && (base <= 36)) + { + len = mpz_sizeinbase(mpz, base) + 2; + s = begin_shared_string(len); + mpz_get_str(s->str, base, mpz); + /* Find NULL character */ + len-=4; + if (len < 0) len = 0; + while(s->str[len]) len++; + s->len=len; + s=end_shared_string(s); + } + else if (base == 256) + { + INT32 i; + mpz_t tmp; + + if (mpz_sgn(mpz) < 0) + error("only non-negative numbers can be converted to base 256.\n"); + len = (mpz_sizeinbase(mpz, 2) + 7) / 8; + s = begin_shared_string(len); + mpz_init_set(tmp, mpz); + i = len; + while(i--) + { + s->str[i] = mpz_get_ui(tmp) & 0xff; + mpz_tdiv_q_2exp(tmp, tmp, 8); + } + assert(mpz_sgn(tmp) == 0); + mpz_clear(tmp); + s = end_shared_string(s); + } + else + { + error("invalid base.\n"); + return 0; /* Make GCC happy */ + } + + return s; +} + +static void mpzmod_get_string(INT32 args) +{ + pop_n_elems(args); + push_string(low_get_digits(THIS, 10)); +} + +static void mpzmod_digits(INT32 args) +{ + INT32 base; + if (!args) + { + base = 10; + } + else + { + if (sp[-args].type != T_INT) + error("Bad argument 1 for Mpz->digits().\n"); + base = sp[-args].u.integer; + } + pop_n_elems(args); + + push_string(low_get_digits(THIS, base)); +} + +static void mpzmod_size(INT32 args) +{ + int base; + if (!args) + { + /* Default is number of bits */ + base = 2; + } + else + { + if (sp[-args].type != T_INT) + error("bad argument 1 for Mpz->size()\n"); + base = sp[-args].u.integer; + if ((base != 256) && ((base < 2) || (base > 36))) + error("invalid base\n"); + } + pop_n_elems(args); + + if (base == 256) + push_int((mpz_sizeinbase(THIS, 2) + 7) / 8); + else + push_int(mpz_sizeinbase(THIS, base)); +} + +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: +#if 0 + case T_STRING: + case T_ARRAY: +#endif + 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); +} + +static void mpzmod_gcdext(INT32 args) +{ + struct object *g, *s, *t; + MP_INT *a; + + a = get_mpz(sp-args); + + g = clone(mpzmod_program, 0); + s = clone(mpzmod_program, 0); + t = clone(mpzmod_program, 0); + + mpz_gcdext(OBTOMPZ(g), OBTOMPZ(s), OBTOMPZ(t), THIS, a); + pop_n_elems(args); + push_object(g); push_object(s); push_object(t); + f_aggregate(3); +} + +static void mpzmod_gcdext2(INT32 args) +{ + struct object *g, *s; + MP_INT *a; + + a = get_mpz(sp-args); + + g = clone(mpzmod_program, 0); + s = clone(mpzmod_program, 0); + + mpz_gcdext(OBTOMPZ(g), OBTOMPZ(s), NULL, THIS, a); + pop_n_elems(args); + push_object(g); push_object(s); + f_aggregate(2); +} + +static void mpzmod_invert(INT32 args) +{ + MP_INT *modulo; + MP_INT *tmp; + + modulo = get_mpz(sp-args); + if (!mpz_sgn(modulo)) + error("divide by zero"); + tmp = get_tmp(); + if (mpz_invert(tmp, THIS, modulo) == 0) + error("not invertible"); + 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_sqrtrem(INT32 args) +{ + struct object *root, *rem; + + pop_n_elems(args); + if(mpz_sgn(THIS)<0) + error("mpz->sqrtrem() on negative number.\n"); + + root = clone(mpzmod_program,0); + rem = clone(mpzmod_program,0); + mpz_sqrtrem(OBTOMPZ(root), OBTOMPZ(rem), THIS); + push_object(root); push_object(rem); + f_aggregate(2); +} + +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, THIS, 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(struct object *o) +{ + mpz_init(THIS); +} + +static void exit_mpz_glue(struct object *o) +{ + mpz_clear(THIS); +} +#endif + +void pike_module_exit(void) +{ +#ifdef HAVE_GMP_H + if(temporary) free_object(temporary); + free_program(mpzmod_program); +#endif +} + +void pike_module_init(void) +{ +#ifdef HAVE_GMP_H + start_new_program(); + add_storage(sizeof(MP_INT)); + + add_function("create", mpzmod_create, + "function(void|string|int|float|object:void)" + "|function(string,int:void)", 0); + +#define MPZ_ARG_TYPE "int|float|object" +#define MPZ_BINOP_TYPE ("function(" MPZ_ARG_TYPE "...: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(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(" MPZ_ARG_TYPE ":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("digits", mpzmod_digits, "function(void|int:string)", 0); + add_function("size", mpzmod_size, "function(void|int:int)", 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, MPZ_BINOP_TYPE, 0); + add_function("gcdext", mpzmod_gcdext, + "function(" MPZ_ARG_TYPE "," MPZ_ARG_TYPE ":array(object))", 0); + add_function("gcdext2", mpzmod_gcdext2, + "function(" MPZ_ARG_TYPE "," MPZ_ARG_TYPE ":array(object))", 0); + add_function("invert", mpzmod_invert, + "function(" MPZ_ARG_TYPE ":object)", 0); + + add_function("sqrt",mpzmod_gcd,"function(:object)",0); + add_function("sqrtrem", mpzmod_sqrtrem, "function(:array(object))", 0); + add_function("`~",mpzmod_gcd,"function(:object)",0); + add_function("powm",mpzmod_powm, + "function(" MPZ_ARG_TYPE "," MPZ_ARG_TYPE ":object)", 0); +#if 0 + /* These are not implemented yet */ + add_function("squarep", mpzmod_squarep, "function(:int)", 0); + add_function("divmod", mpzmod_divmod, "function(" MPZ_ARG_TYPE ":array(object))", 0); + add_function("pow", mpzmod_pow, "function(int:object)", 0); + add_function("divm", mpzmod_divm, "function(string|int|float|object, string|int|float|object:object)", 0); + add_efun("mpz_pow", mpz_pow, "function(int, int)", 0); + add_efun("mpz_fac", mpz_fac, "function(int|object:object)", 0); +#endif + set_init_callback(init_mpz_glue); + set_exit_callback(exit_mpz_glue); + + mpzmod_program=end_program(); + add_program_constant("mpz",mpzmod_program,0); +#endif +} + diff --git a/src/modules/Gmp/testsuite.in b/src/modules/Gmp/testsuite.in new file mode 100644 index 0000000000..39fd5d4ac9 --- /dev/null +++ b/src/modules/Gmp/testsuite.in @@ -0,0 +1,57 @@ +// mpz +cond( [[ master()->programs["/precompiled/mpz"] ]], +[[ + define([[MPZ]],[[(program)"/precompiled/mpz"]]) + test_true(programp(MPZ)) + test_false(clone(MPZ)) + test_do(destruct(clone(MPZ))) + + test_eq(Mpz(10),10) + test_eq(Mpz("10"),10) + test_eq(Mpz(10.0),10) + test_eq(Mpz("10",8),8) + test_eq(Mpz("0",256),'0') + + test_eq(clone(MPZ,99)+1,100) + test_eq(clone(MPZ,100)*10,1000) + test_eq(clone(MPZ,"100")*10.0,1000) + test_eq(clone(MPZ,100.0)*clone(MPZ,3),300) + test_eq(clone(MPZ,100.0)/4,25) + test_eq(clone(MPZ,42)%10,2) + test_eq(clone(MPZ,10)<<1,20) + test_eq(clone(MPZ,10)>>1,5) + test_eq(clone(MPZ,66)+11,77) + test_eq(clone(MPZ,66)-11,55) + test_eq(clone(MPZ,17)&18,16) + test_eq(clone(MPZ,17)|7,31) + test_eq(-clone(MPZ,17),17) + test_eq((~clone(MPZ,17)) & 255,0xf0) + test_true(stringp((string)clone(MPZ,17))) + test_eq((string)clone(MPZ,17),"17") + test_true(intp((int)clone(MPZ,17))) + test_eq((int)clone(MPZ,17),17) + test_false(clone(MPZ,0)) + test_true(clone(MPZ,1)) + test_eq(clone(MPZ,17)->powm(2,4711),290) + + define([[mpz_test_cmp]],[[ + test_cmp(clone(MPZ,$1), $2) + test_cmp($1, clone(MPZ,$2)) + test_cmp(clone(MPZ, $1), clone(MPZ, $2)) + ]]) + + define([[mpz_test_type1]],[[ + mpz_test_cmp($1,$2) + mpz_test_cmp($1.0,$2) + ]]) + + define([[mpz_test_type2]],[[ + mpz_test_type1($1,$2) + mpz_test_type1($1,$2.0) + ]]) + + mpz_test_type2(1,2) + mpz_test_type2(-2,1) + +]]); + -- GitLab