diff options
Diffstat (limited to 'ext/dbm')
37 files changed, 13096 insertions, 0 deletions
diff --git a/ext/dbm/GDBM_File.c b/ext/dbm/GDBM_File.c new file mode 100644 index 0000000000..b5d4a8884a --- /dev/null +++ b/ext/dbm/GDBM_File.c @@ -0,0 +1,310 @@ +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +#include <gdbm.h> + +#include <fcntl.h> + +typedef GDBM_FILE GDBM_File; + +#define gdbm_new(dbtype, name, block_size, read_write, mode, fatal_func) \ + gdbm_open(name, block_size, read_write, mode, fatal_func) + +typedef datum gdatum; + +typedef void (*FATALFUNC)(); + +static int +XS_GDBM_File_gdbm_new(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 5 || items > 6) { + fatal("Usage: GDBM_File::new(dbtype, name, block_size, read_write, mode, fatal_func = (FATALFUNC)fatal)"); + } + { + char * dbtype = SvPV(ST(1),na); + char * name = SvPV(ST(2),na); + int block_size = (int)SvIV(ST(3)); + int read_write = (int)SvIV(ST(4)); + int mode = (int)SvIV(ST(5)); + FATALFUNC fatal_func; + GDBM_File RETVAL; + + if (items < 6) + fatal_func = (FATALFUNC)fatal; + else { + fatal_func = (FATALFUNC)SvPV(ST(6),na); + } + + RETVAL = gdbm_new(dbtype, name, block_size, read_write, mode, fatal_func); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setptrobj(ST(0), RETVAL, "GDBM_File"); + } + return sp; +} + +static int +XS_GDBM_File_gdbm_open(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 4 || items > 5) { + fatal("Usage: GDBM_File::open(name, block_size, read_write, mode, fatal_func = (FATALFUNC)fatal)"); + } + { + char * name = SvPV(ST(1),na); + int block_size = (int)SvIV(ST(2)); + int read_write = (int)SvIV(ST(3)); + int mode = (int)SvIV(ST(4)); + FATALFUNC fatal_func; + GDBM_File RETVAL; + + if (items < 5) + fatal_func = (FATALFUNC)fatal; + else { + fatal_func = (FATALFUNC)SvPV(ST(5),na); + } + + RETVAL = gdbm_open(name, block_size, read_write, mode, fatal_func); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setptrobj(ST(0), RETVAL, "GDBM_File"); + } + return sp; +} + +static int +XS_GDBM_File_gdbm_close(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 1 || items > 1) { + fatal("Usage: GDBM_File::close(db)"); + } + { + GDBM_File db; + + if (sv_isa(ST(1), "GDBM_File")) + db = (GDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type GDBM_File"); + + gdbm_close(db); + } + return sp; +} + +static int +XS_GDBM_File_gdbm_DESTROY(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 1 || items > 1) { + fatal("Usage: GDBM_File::DESTROY(db)"); + } + { + GDBM_File db; + + if (sv_isa(ST(1), "GDBM_File")) + db = (GDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type GDBM_File"); + gdbm_close(db); + } + return sp; +} + +static int +XS_GDBM_File_gdbm_fetch(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 2 || items > 2) { + fatal("Usage: GDBM_File::fetch(db, key)"); + } + { + GDBM_File db; + datum key; + gdatum RETVAL; + + if (sv_isa(ST(1), "GDBM_File")) + db = (GDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type GDBM_File"); + + key.dptr = SvPV(ST(2), key.dsize);; + + RETVAL = gdbm_fetch(db, key); + ST(0) = sv_mortalcopy(&sv_undef); + sv_usepvn(ST(0), RETVAL.dptr, RETVAL.dsize); + } + return sp; +} + +static int +XS_GDBM_File_gdbm_store(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 3 || items > 4) { + fatal("Usage: GDBM_File::store(db, key, value, flags = GDBM_REPLACE)"); + } + { + GDBM_File db; + datum key; + datum value; + int flags; + int RETVAL; + + if (sv_isa(ST(1), "GDBM_File")) + db = (GDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type GDBM_File"); + + key.dptr = SvPV(ST(2), key.dsize);; + + value.dptr = SvPV(ST(3), value.dsize);; + + if (items < 4) + flags = GDBM_REPLACE; + else { + flags = (int)SvIV(ST(4)); + } + + RETVAL = gdbm_store(db, key, value, flags); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setiv(ST(0), (I32)RETVAL); + } + return sp; +} + +static int +XS_GDBM_File_gdbm_delete(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 2 || items > 2) { + fatal("Usage: GDBM_File::delete(db, key)"); + } + { + GDBM_File db; + datum key; + int RETVAL; + + if (sv_isa(ST(1), "GDBM_File")) + db = (GDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type GDBM_File"); + + key.dptr = SvPV(ST(2), key.dsize);; + + RETVAL = gdbm_delete(db, key); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setiv(ST(0), (I32)RETVAL); + } + return sp; +} + +static int +XS_GDBM_File_gdbm_firstkey(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 1 || items > 1) { + fatal("Usage: GDBM_File::firstkey(db)"); + } + { + GDBM_File db; + gdatum RETVAL; + + if (sv_isa(ST(1), "GDBM_File")) + db = (GDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type GDBM_File"); + + RETVAL = gdbm_firstkey(db); + ST(0) = sv_mortalcopy(&sv_undef); + sv_usepvn(ST(0), RETVAL.dptr, RETVAL.dsize); + } + return sp; +} + +static int +XS_GDBM_File_gdbm_nextkey(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 2 || items > 2) { + fatal("Usage: GDBM_File::nextkey(db, key)"); + } + { + GDBM_File db; + datum key; + gdatum RETVAL; + + if (sv_isa(ST(1), "GDBM_File")) + db = (GDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type GDBM_File"); + + key.dptr = SvPV(ST(2), key.dsize);; + + RETVAL = gdbm_nextkey(db, key); + ST(0) = sv_mortalcopy(&sv_undef); + sv_usepvn(ST(0), RETVAL.dptr, RETVAL.dsize); + } + return sp; +} + +static int +XS_GDBM_File_gdbm_reorganize(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 1 || items > 1) { + fatal("Usage: GDBM_File::reorganize(db)"); + } + { + GDBM_File db; + int RETVAL; + + if (sv_isa(ST(1), "GDBM_File")) + db = (GDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type GDBM_File"); + + RETVAL = gdbm_reorganize(db); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setiv(ST(0), (I32)RETVAL); + } + return sp; +} + +int init_GDBM_File(ix,sp,items) +int ix; +int sp; +int items; +{ + char* file = __FILE__; + + newXSUB("GDBM_File::new", 0, XS_GDBM_File_gdbm_new, file); + newXSUB("GDBM_File::open", 0, XS_GDBM_File_gdbm_open, file); + newXSUB("GDBM_File::close", 0, XS_GDBM_File_gdbm_close, file); + newXSUB("GDBM_File::DESTROY", 0, XS_GDBM_File_gdbm_DESTROY, file); + newXSUB("GDBM_File::fetch", 0, XS_GDBM_File_gdbm_fetch, file); + newXSUB("GDBM_File::store", 0, XS_GDBM_File_gdbm_store, file); + newXSUB("GDBM_File::delete", 0, XS_GDBM_File_gdbm_delete, file); + newXSUB("GDBM_File::firstkey", 0, XS_GDBM_File_gdbm_firstkey, file); + newXSUB("GDBM_File::nextkey", 0, XS_GDBM_File_gdbm_nextkey, file); + newXSUB("GDBM_File::reorganize", 0, XS_GDBM_File_gdbm_reorganize, file); +} diff --git a/ext/dbm/GDBM_File.xs b/ext/dbm/GDBM_File.xs new file mode 100644 index 0000000000..2c619cbe42 --- /dev/null +++ b/ext/dbm/GDBM_File.xs @@ -0,0 +1,76 @@ +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +#include <gdbm.h> + +#include <fcntl.h> + +typedef GDBM_FILE GDBM_File; + +#define gdbm_new(dbtype, name, block_size, read_write, mode, fatal_func) \ + gdbm_open(name, block_size, read_write, mode, fatal_func) + +typedef datum gdatum; + +typedef void (*FATALFUNC)(); + +MODULE = GDBM_File PACKAGE = GDBM_File PREFIX = gdbm_ + +GDBM_File +gdbm_new(dbtype, name, block_size, read_write, mode, fatal_func = (FATALFUNC)croak) + char * dbtype + char * name + int block_size + int read_write + int mode + FATALFUNC fatal_func + +GDBM_File +gdbm_open(name, block_size, read_write, mode, fatal_func = (FATALFUNC)croak) + char * name + int block_size + int read_write + int mode + FATALFUNC fatal_func + +void +gdbm_close(db) + GDBM_File db + CLEANUP: + +void +gdbm_DESTROY(db) + GDBM_File db + CODE: + gdbm_close(db); + +gdatum +gdbm_fetch(db, key) + GDBM_File db + datum key + +int +gdbm_store(db, key, value, flags = GDBM_REPLACE) + GDBM_File db + datum key + datum value + int flags + +int +gdbm_delete(db, key) + GDBM_File db + datum key + +gdatum +gdbm_firstkey(db) + GDBM_File db + +gdatum +gdbm_nextkey(db, key) + GDBM_File db + datum key + +int +gdbm_reorganize(db) + GDBM_File db + diff --git a/ext/dbm/GDBM_File.xs.bak b/ext/dbm/GDBM_File.xs.bak new file mode 100644 index 0000000000..03b86c5739 --- /dev/null +++ b/ext/dbm/GDBM_File.xs.bak @@ -0,0 +1,122 @@ +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +#include <gdbm.h> + +#include <fcntl.h> + +typedef GDBM_FILE GDBM_File; + +#define gdbm_new(dbtype,filename,flags,mode) \ + gdbm_open(filename, 0, flags & O_CREAT ? GDBM_WRCREAT : GDBM_WRITER, \ + mode, fatal) + +typedef datum gdatum; + +typedef struct gdbm_file_desc { + GDBM_File ptr; + SV* curkey; +} GDBM_FILE_DESC; + +GDBM_FILE_DESC* GDBM_File_desc; + +GDBM_FILE_DESC* +newGDBM_FILE_DESC(ptr) +void* ptr; +{ + New(0, GDBM_File_desc, 1, GDBM_FILE_DESC); + GDBM_File_desc->ptr = ptr; + GDBM_File_desc->curkey = 0; + return GDBM_File_desc; +} + +void +deleteGDBM_FILE_DESC() +{ + sv_free(GDBM_File_desc->curkey); + Safefree(GDBM_File_desc); +} + +typedef void (*FATALFUNC)(); + +static datum +get_current_key() +{ + datum key; + key.dptr = SvPVn( GDBM_File_desc->curkey, key.dsize); + return key; +} + +static void +set_current_key(sv) +SV *sv; +{ + sv_free(GDBM_File_desc->curkey); + GDBM_File_desc->curkey = sv_ref(sv); +} + + +MODULE = GDBM_File PACKAGE = GDBM_File PREFIX = gdbm_ + +GDBM_File +gdbm_new(dbtype, filename, flags, mode) + char * dbtype + char * filename + int flags + int mode + +GDBM_File +gdbm_open(name, block_size, read_write, mode, fatal_func = (FATALFUNC)fatal) + char * name + int block_size + int read_write + int mode + FATALFUNC fatal_func + +void +gdbm_close(db) + GDBM_File db + CLEANUP: + deleteGDBM_FILE_DESC(); + +void +gdbm_DESTROY(db) + GDBM_File db + CODE: + gdbm_close(db); + deleteGDBM_FILE_DESC(); + +gdatum +gdbm_fetch(db, key) + GDBM_File db + datum key + +int +gdbm_store(db, key, value, flags = GDBM_REPLACE) + GDBM_File db + datum key + datum value + int flags + +int +gdbm_delete(db, key) + GDBM_File db + datum key + +gdatum +gdbm_firstkey(db) + GDBM_File db + CLEANUP: + set_current_key(ST(0)); + +gdatum +gdbm_nextkey(db, key = get_current_key()) + GDBM_File db + datum key + CLEANUP: + set_current_key(ST(0)); + +int +gdbm_reorganize(db) + GDBM_File db + diff --git a/ext/dbm/Makefile b/ext/dbm/Makefile new file mode 100644 index 0000000000..61afe01e64 --- /dev/null +++ b/ext/dbm/Makefile @@ -0,0 +1,14 @@ +all: NDBM_File.c ODBM_File.c GDBM_File.c SDBM_File.c + +NDBM_File.c: NDBM_File.xs + ../xsubpp ../typemap NDBM_File.xs >NDBM_File.c + +SDBM_File.c: SDBM_File.xs + ../xsubpp ../typemap SDBM_File.xs >SDBM_File.c + +ODBM_File.c: ODBM_File.xs + ../xsubpp ../typemap ODBM_File.xs >ODBM_File.c + +GDBM_File.c: GDBM_File.xs + ../xsubpp ../typemap GDBM_File.xs >GDBM_File.c + diff --git a/ext/dbm/NDBM_File.c b/ext/dbm/NDBM_File.c new file mode 100644 index 0000000000..b321ac4252 --- /dev/null +++ b/ext/dbm/NDBM_File.c @@ -0,0 +1,267 @@ +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +#include <ndbm.h> + +typedef DBM* NDBM_File; +#define dbm_new(dbtype,filename,flags,mode) dbm_open(filename,flags,mode) +#define nextkey(db,key) dbm_nextkey(db) + +static int +XS_NDBM_File_dbm_new(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 4 || items > 4) { + fatal("Usage: NDBM_File::new(dbtype, filename, flags, mode)"); + } + { + char * dbtype = SvPV(ST(1),na); + char * filename = SvPV(ST(2),na); + int flags = (int)SvIV(ST(3)); + int mode = (int)SvIV(ST(4)); + NDBM_File RETVAL; + + RETVAL = dbm_new(dbtype, filename, flags, mode); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setptrobj(ST(0), RETVAL, "NDBM_File"); + } + return sp; +} + +static int +XS_NDBM_File_dbm_DESTROY(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 1 || items > 1) { + fatal("Usage: NDBM_File::DESTROY(db)"); + } + { + NDBM_File db; + + if (sv_isa(ST(1), "NDBM_File")) + db = (NDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type NDBM_File"); + dbm_close(db); + } + return sp; +} + +static int +XS_NDBM_File_dbm_fetch(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 2 || items > 2) { + fatal("Usage: NDBM_File::fetch(db, key)"); + } + { + NDBM_File db; + datum key; + datum RETVAL; + + if (sv_isa(ST(1), "NDBM_File")) + db = (NDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type NDBM_File"); + + key.dptr = SvPV(ST(2), key.dsize);; + + RETVAL = dbm_fetch(db, key); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setpvn(ST(0), RETVAL.dptr, RETVAL.dsize); + } + return sp; +} + +static int +XS_NDBM_File_dbm_store(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 3 || items > 4) { + fatal("Usage: NDBM_File::store(db, key, value, flags = DBM_REPLACE)"); + } + { + NDBM_File db; + datum key; + datum value; + int flags; + int RETVAL; + + if (sv_isa(ST(1), "NDBM_File")) + db = (NDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type NDBM_File"); + + key.dptr = SvPV(ST(2), key.dsize);; + + value.dptr = SvPV(ST(3), value.dsize);; + + if (items < 4) + flags = DBM_REPLACE; + else { + flags = (int)SvIV(ST(4)); + } + + RETVAL = dbm_store(db, key, value, flags); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setiv(ST(0), (I32)RETVAL); + } + return sp; +} + +static int +XS_NDBM_File_dbm_delete(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 2 || items > 2) { + fatal("Usage: NDBM_File::delete(db, key)"); + } + { + NDBM_File db; + datum key; + int RETVAL; + + if (sv_isa(ST(1), "NDBM_File")) + db = (NDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type NDBM_File"); + + key.dptr = SvPV(ST(2), key.dsize);; + + RETVAL = dbm_delete(db, key); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setiv(ST(0), (I32)RETVAL); + } + return sp; +} + +static int +XS_NDBM_File_dbm_firstkey(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 1 || items > 1) { + fatal("Usage: NDBM_File::firstkey(db)"); + } + { + NDBM_File db; + datum RETVAL; + + if (sv_isa(ST(1), "NDBM_File")) + db = (NDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type NDBM_File"); + + RETVAL = dbm_firstkey(db); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setpvn(ST(0), RETVAL.dptr, RETVAL.dsize); + } + return sp; +} + +static int +XS_NDBM_File_nextkey(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 2 || items > 2) { + fatal("Usage: NDBM_File::nextkey(db, key)"); + } + { + NDBM_File db; + datum key; + datum RETVAL; + + if (sv_isa(ST(1), "NDBM_File")) + db = (NDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type NDBM_File"); + + key.dptr = SvPV(ST(2), key.dsize);; + + RETVAL = nextkey(db, key); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setpvn(ST(0), RETVAL.dptr, RETVAL.dsize); + } + return sp; +} + +static int +XS_NDBM_File_dbm_error(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 1 || items > 1) { + fatal("Usage: NDBM_File::error(db)"); + } + { + NDBM_File db; + int RETVAL; + + if (sv_isa(ST(1), "NDBM_File")) + db = (NDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type NDBM_File"); + + RETVAL = dbm_error(db); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setiv(ST(0), (I32)RETVAL); + } + return sp; +} + +static int +XS_NDBM_File_dbm_clearerr(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 1 || items > 1) { + fatal("Usage: NDBM_File::clearerr(db)"); + } + { + NDBM_File db; + int RETVAL; + + if (sv_isa(ST(1), "NDBM_File")) + db = (NDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type NDBM_File"); + + RETVAL = dbm_clearerr(db); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setiv(ST(0), (I32)RETVAL); + } + return sp; +} + +int init_NDBM_File(ix,sp,items) +int ix; +int sp; +int items; +{ + char* file = __FILE__; + + newXSUB("NDBM_File::new", 0, XS_NDBM_File_dbm_new, file); + newXSUB("NDBM_File::DESTROY", 0, XS_NDBM_File_dbm_DESTROY, file); + newXSUB("NDBM_File::fetch", 0, XS_NDBM_File_dbm_fetch, file); + newXSUB("NDBM_File::store", 0, XS_NDBM_File_dbm_store, file); + newXSUB("NDBM_File::delete", 0, XS_NDBM_File_dbm_delete, file); + newXSUB("NDBM_File::firstkey", 0, XS_NDBM_File_dbm_firstkey, file); + newXSUB("NDBM_File::nextkey", 0, XS_NDBM_File_nextkey, file); + newXSUB("NDBM_File::error", 0, XS_NDBM_File_dbm_error, file); + newXSUB("NDBM_File::clearerr", 0, XS_NDBM_File_dbm_clearerr, file); +} diff --git a/ext/dbm/NDBM_File.xs b/ext/dbm/NDBM_File.xs new file mode 100644 index 0000000000..5f4f78b974 --- /dev/null +++ b/ext/dbm/NDBM_File.xs @@ -0,0 +1,58 @@ +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +#include <ndbm.h> + +typedef DBM* NDBM_File; +#define dbm_new(dbtype,filename,flags,mode) dbm_open(filename,flags,mode) +#define nextkey(db,key) dbm_nextkey(db) + +MODULE = NDBM_File PACKAGE = NDBM_File PREFIX = dbm_ + +NDBM_File +dbm_new(dbtype, filename, flags, mode) + char * dbtype + char * filename + int flags + int mode + +void +dbm_DESTROY(db) + NDBM_File db + CODE: + dbm_close(db); + +datum +dbm_fetch(db, key) + NDBM_File db + datum key + +int +dbm_store(db, key, value, flags = DBM_REPLACE) + NDBM_File db + datum key + datum value + int flags + +int +dbm_delete(db, key) + NDBM_File db + datum key + +datum +dbm_firstkey(db) + NDBM_File db + +datum +nextkey(db, key) + NDBM_File db + datum key + +int +dbm_error(db) + NDBM_File db + +int +dbm_clearerr(db) + NDBM_File db + diff --git a/ext/dbm/ODBM_File.c b/ext/dbm/ODBM_File.c new file mode 100644 index 0000000000..b2fa7ddcba --- /dev/null +++ b/ext/dbm/ODBM_File.c @@ -0,0 +1,246 @@ +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +#ifdef NULL +#undef NULL +#endif +#include <dbm.h> + +#include <fcntl.h> + +typedef void* ODBM_File; + +#define odbm_fetch(db,key) fetch(key) +#define odbm_store(db,key,value,flags) store(key,value) +#define odbm_delete(db,key) delete(key) +#define odbm_firstkey(db) firstkey() +#define odbm_nextkey(db,key) nextkey(key) + +static int dbmrefcnt; + +#define DBM_REPLACE 0 + +static int +XS_ODBM_File_odbm_new(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 4 || items > 4) { + fatal("Usage: ODBM_File::new(dbtype, filename, flags, mode)"); + } + { + char * dbtype = SvPV(ST(1),na); + char * filename = SvPV(ST(2),na); + int flags = (int)SvIV(ST(3)); + int mode = (int)SvIV(ST(4)); + ODBM_File RETVAL; + { + char tmpbuf[1025]; + if (dbmrefcnt++) + fatal("Old dbm can only open one database"); + sprintf(tmpbuf,"%s.dir",filename); + if (stat(tmpbuf, &statbuf) < 0) { + if (flags & O_CREAT) { + if (mode < 0 || close(creat(tmpbuf,mode)) < 0) + fatal("ODBM_File: Can't create %s", filename); + sprintf(tmpbuf,"%s.pag",filename); + if (close(creat(tmpbuf,mode)) < 0) + fatal("ODBM_File: Can't create %s", filename); + } + else + fatal("ODBM_FILE: Can't open %s", filename); + } + RETVAL = (void*)(dbminit(filename) >= 0 ? &dbmrefcnt : 0); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setptrobj(ST(0), RETVAL, "ODBM_File"); + } + } + return sp; +} + +static int +XS_ODBM_File_DESTROY(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 1 || items > 1) { + fatal("Usage: ODBM_File::DESTROY(db)"); + } + { + ODBM_File db; + + if (sv_isa(ST(1), "ODBM_File")) + db = (ODBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type ODBM_File"); + dbmrefcnt--; + dbmclose(); + } + return sp; +} + +static int +XS_ODBM_File_odbm_fetch(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 2 || items > 2) { + fatal("Usage: ODBM_File::fetch(db, key)"); + } + { + ODBM_File db; + datum key; + datum RETVAL; + + if (sv_isa(ST(1), "ODBM_File")) + db = (ODBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type ODBM_File"); + + key.dptr = SvPV(ST(2), key.dsize);; + + RETVAL = odbm_fetch(db, key); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setpvn(ST(0), RETVAL.dptr, RETVAL.dsize); + } + return sp; +} + +static int +XS_ODBM_File_odbm_store(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 3 || items > 4) { + fatal("Usage: ODBM_File::store(db, key, value, flags = DBM_REPLACE)"); + } + { + ODBM_File db; + datum key; + datum value; + int flags; + int RETVAL; + + if (sv_isa(ST(1), "ODBM_File")) + db = (ODBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type ODBM_File"); + + key.dptr = SvPV(ST(2), key.dsize);; + + value.dptr = SvPV(ST(3), value.dsize);; + + if (items < 4) + flags = DBM_REPLACE; + else { + flags = (int)SvIV(ST(4)); + } + + RETVAL = odbm_store(db, key, value, flags); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setiv(ST(0), (I32)RETVAL); + } + return sp; +} + +static int +XS_ODBM_File_odbm_delete(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 2 || items > 2) { + fatal("Usage: ODBM_File::delete(db, key)"); + } + { + ODBM_File db; + datum key; + int RETVAL; + + if (sv_isa(ST(1), "ODBM_File")) + db = (ODBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type ODBM_File"); + + key.dptr = SvPV(ST(2), key.dsize);; + + RETVAL = odbm_delete(db, key); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setiv(ST(0), (I32)RETVAL); + } + return sp; +} + +static int +XS_ODBM_File_odbm_firstkey(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 1 || items > 1) { + fatal("Usage: ODBM_File::firstkey(db)"); + } + { + ODBM_File db; + datum RETVAL; + + if (sv_isa(ST(1), "ODBM_File")) + db = (ODBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type ODBM_File"); + + RETVAL = odbm_firstkey(db); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setpvn(ST(0), RETVAL.dptr, RETVAL.dsize); + } + return sp; +} + +static int +XS_ODBM_File_odbm_nextkey(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 2 || items > 2) { + fatal("Usage: ODBM_File::nextkey(db, key)"); + } + { + ODBM_File db; + datum key; + datum RETVAL; + + if (sv_isa(ST(1), "ODBM_File")) + db = (ODBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type ODBM_File"); + + key.dptr = SvPV(ST(2), key.dsize);; + + RETVAL = odbm_nextkey(db, key); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setpvn(ST(0), RETVAL.dptr, RETVAL.dsize); + } + return sp; +} + +int init_ODBM_File(ix,sp,items) +int ix; +int sp; +int items; +{ + char* file = __FILE__; + + newXSUB("ODBM_File::new", 0, XS_ODBM_File_odbm_new, file); + newXSUB("ODBM_File::DESTROY", 0, XS_ODBM_File_DESTROY, file); + newXSUB("ODBM_File::fetch", 0, XS_ODBM_File_odbm_fetch, file); + newXSUB("ODBM_File::store", 0, XS_ODBM_File_odbm_store, file); + newXSUB("ODBM_File::delete", 0, XS_ODBM_File_odbm_delete, file); + newXSUB("ODBM_File::firstkey", 0, XS_ODBM_File_odbm_firstkey, file); + newXSUB("ODBM_File::nextkey", 0, XS_ODBM_File_odbm_nextkey, file); +} diff --git a/ext/dbm/ODBM_File.xs b/ext/dbm/ODBM_File.xs new file mode 100644 index 0000000000..74554c71e6 --- /dev/null +++ b/ext/dbm/ODBM_File.xs @@ -0,0 +1,86 @@ +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +#ifdef NULL +#undef NULL +#endif +#include <dbm.h> + +#include <fcntl.h> + +typedef void* ODBM_File; + +#define odbm_fetch(db,key) fetch(key) +#define odbm_store(db,key,value,flags) store(key,value) +#define odbm_delete(db,key) delete(key) +#define odbm_firstkey(db) firstkey() +#define odbm_nextkey(db,key) nextkey(key) + +static int dbmrefcnt; + +#define DBM_REPLACE 0 + +MODULE = ODBM_File PACKAGE = ODBM_File PREFIX = odbm_ + +ODBM_File +odbm_new(dbtype, filename, flags, mode) + char * dbtype + char * filename + int flags + int mode + CODE: + { + char tmpbuf[1025]; + if (dbmrefcnt++) + croak("Old dbm can only open one database"); + sprintf(tmpbuf,"%s.dir",filename); + if (stat(tmpbuf, &statbuf) < 0) { + if (flags & O_CREAT) { + if (mode < 0 || close(creat(tmpbuf,mode)) < 0) + croak("ODBM_File: Can't create %s", filename); + sprintf(tmpbuf,"%s.pag",filename); + if (close(creat(tmpbuf,mode)) < 0) + croak("ODBM_File: Can't create %s", filename); + } + else + croak("ODBM_FILE: Can't open %s", filename); + } + RETVAL = (void*)(dbminit(filename) >= 0 ? &dbmrefcnt : 0); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setptrobj(ST(0), RETVAL, "ODBM_File"); + } + +void +DESTROY(db) + ODBM_File db + CODE: + dbmrefcnt--; + dbmclose(); + +datum +odbm_fetch(db, key) + ODBM_File db + datum key + +int +odbm_store(db, key, value, flags = DBM_REPLACE) + ODBM_File db + datum key + datum value + int flags + +int +odbm_delete(db, key) + ODBM_File db + datum key + +datum +odbm_firstkey(db) + ODBM_File db + +datum +odbm_nextkey(db, key) + ODBM_File db + datum key + diff --git a/ext/dbm/SDBM_File.c b/ext/dbm/SDBM_File.c new file mode 100644 index 0000000000..7baafc4a98 --- /dev/null +++ b/ext/dbm/SDBM_File.c @@ -0,0 +1,266 @@ +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +#include "ext/dbm/sdbm/sdbm.h" + +typedef DBM* SDBM_File; +#define sdbm_new(dbtype,filename,flags,mode) sdbm_open(filename,flags,mode) + +static int +XS_SDBM_File_sdbm_new(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 4 || items > 4) { + fatal("Usage: SDBM_File::new(dbtype, filename, flags, mode)"); + } + { + char * dbtype = SvPV(ST(1),na); + char * filename = SvPV(ST(2),na); + int flags = (int)SvIV(ST(3)); + int mode = (int)SvIV(ST(4)); + SDBM_File RETVAL; + + RETVAL = sdbm_new(dbtype, filename, flags, mode); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setptrobj(ST(0), RETVAL, "SDBM_File"); + } + return sp; +} + +static int +XS_SDBM_File_sdbm_DESTROY(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 1 || items > 1) { + fatal("Usage: SDBM_File::DESTROY(db)"); + } + { + SDBM_File db; + + if (sv_isa(ST(1), "SDBM_File")) + db = (SDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type SDBM_File"); + sdbm_close(db); + } + return sp; +} + +static int +XS_SDBM_File_sdbm_fetch(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 2 || items > 2) { + fatal("Usage: SDBM_File::fetch(db, key)"); + } + { + SDBM_File db; + datum key; + datum RETVAL; + + if (sv_isa(ST(1), "SDBM_File")) + db = (SDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type SDBM_File"); + + key.dptr = SvPV(ST(2), key.dsize);; + + RETVAL = sdbm_fetch(db, key); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setpvn(ST(0), RETVAL.dptr, RETVAL.dsize); + } + return sp; +} + +static int +XS_SDBM_File_sdbm_store(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 3 || items > 4) { + fatal("Usage: SDBM_File::store(db, key, value, flags = DBM_REPLACE)"); + } + { + SDBM_File db; + datum key; + datum value; + int flags; + int RETVAL; + + if (sv_isa(ST(1), "SDBM_File")) + db = (SDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type SDBM_File"); + + key.dptr = SvPV(ST(2), key.dsize);; + + value.dptr = SvPV(ST(3), value.dsize);; + + if (items < 4) + flags = DBM_REPLACE; + else { + flags = (int)SvIV(ST(4)); + } + + RETVAL = sdbm_store(db, key, value, flags); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setiv(ST(0), (I32)RETVAL); + } + return sp; +} + +static int +XS_SDBM_File_sdbm_delete(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 2 || items > 2) { + fatal("Usage: SDBM_File::delete(db, key)"); + } + { + SDBM_File db; + datum key; + int RETVAL; + + if (sv_isa(ST(1), "SDBM_File")) + db = (SDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type SDBM_File"); + + key.dptr = SvPV(ST(2), key.dsize);; + + RETVAL = sdbm_delete(db, key); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setiv(ST(0), (I32)RETVAL); + } + return sp; +} + +static int +XS_SDBM_File_sdbm_firstkey(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 1 || items > 1) { + fatal("Usage: SDBM_File::firstkey(db)"); + } + { + SDBM_File db; + datum RETVAL; + + if (sv_isa(ST(1), "SDBM_File")) + db = (SDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type SDBM_File"); + + RETVAL = sdbm_firstkey(db); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setpvn(ST(0), RETVAL.dptr, RETVAL.dsize); + } + return sp; +} + +static int +XS_SDBM_File_sdbm_nextkey(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 2 || items > 2) { + fatal("Usage: SDBM_File::nextkey(db, key)"); + } + { + SDBM_File db; + datum key; + datum RETVAL; + + if (sv_isa(ST(1), "SDBM_File")) + db = (SDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type SDBM_File"); + + key.dptr = SvPV(ST(2), key.dsize);; + + RETVAL = sdbm_nextkey(db, key); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setpvn(ST(0), RETVAL.dptr, RETVAL.dsize); + } + return sp; +} + +static int +XS_SDBM_File_sdbm_error(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 1 || items > 1) { + fatal("Usage: SDBM_File::error(db)"); + } + { + SDBM_File db; + int RETVAL; + + if (sv_isa(ST(1), "SDBM_File")) + db = (SDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type SDBM_File"); + + RETVAL = sdbm_error(db); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setiv(ST(0), (I32)RETVAL); + } + return sp; +} + +static int +XS_SDBM_File_sdbm_clearerr(ix, sp, items) +register int ix; +register int sp; +register int items; +{ + if (items < 1 || items > 1) { + fatal("Usage: SDBM_File::clearerr(db)"); + } + { + SDBM_File db; + int RETVAL; + + if (sv_isa(ST(1), "SDBM_File")) + db = (SDBM_File)(unsigned long)SvNV((SV*)SvANY(ST(1))); + else + fatal("db is not of type SDBM_File"); + + RETVAL = sdbm_clearerr(db); + ST(0) = sv_mortalcopy(&sv_undef); + sv_setiv(ST(0), (I32)RETVAL); + } + return sp; +} + +int init_SDBM_File(ix,sp,items) +int ix; +int sp; +int items; +{ + char* file = __FILE__; + + newXSUB("SDBM_File::new", 0, XS_SDBM_File_sdbm_new, file); + newXSUB("SDBM_File::DESTROY", 0, XS_SDBM_File_sdbm_DESTROY, file); + newXSUB("SDBM_File::fetch", 0, XS_SDBM_File_sdbm_fetch, file); + newXSUB("SDBM_File::store", 0, XS_SDBM_File_sdbm_store, file); + newXSUB("SDBM_File::delete", 0, XS_SDBM_File_sdbm_delete, file); + newXSUB("SDBM_File::firstkey", 0, XS_SDBM_File_sdbm_firstkey, file); + newXSUB("SDBM_File::nextkey", 0, XS_SDBM_File_sdbm_nextkey, file); + newXSUB("SDBM_File::error", 0, XS_SDBM_File_sdbm_error, file); + newXSUB("SDBM_File::clearerr", 0, XS_SDBM_File_sdbm_clearerr, file); +} diff --git a/ext/dbm/SDBM_File.xs b/ext/dbm/SDBM_File.xs new file mode 100644 index 0000000000..0b898ad171 --- /dev/null +++ b/ext/dbm/SDBM_File.xs @@ -0,0 +1,57 @@ +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +#include "ext/dbm/sdbm/sdbm.h" + +typedef DBM* SDBM_File; +#define sdbm_new(dbtype,filename,flags,mode) sdbm_open(filename,flags,mode) + +MODULE = SDBM_File PACKAGE = SDBM_File PREFIX = sdbm_ + +SDBM_File +sdbm_new(dbtype, filename, flags, mode) + char * dbtype + char * filename + int flags + int mode + +void +sdbm_DESTROY(db) + SDBM_File db + CODE: + sdbm_close(db); + +datum +sdbm_fetch(db, key) + SDBM_File db + datum key + +int +sdbm_store(db, key, value, flags = DBM_REPLACE) + SDBM_File db + datum key + datum value + int flags + +int +sdbm_delete(db, key) + SDBM_File db + datum key + +datum +sdbm_firstkey(db) + SDBM_File db + +datum +sdbm_nextkey(db, key) + SDBM_File db + datum key + +int +sdbm_error(db) + SDBM_File db + +int +sdbm_clearerr(db) + SDBM_File db + diff --git a/ext/dbm/sdbm/.pure b/ext/dbm/sdbm/.pure new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/ext/dbm/sdbm/.pure diff --git a/ext/dbm/sdbm/.r b/ext/dbm/sdbm/.r new file mode 100755 index 0000000000..c72dbf15f5 --- /dev/null +++ b/ext/dbm/sdbm/.r @@ -0,0 +1,5884 @@ +if test -f 'CHANGES' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'CHANGES'\" +else +echo shar: Extracting \"'CHANGES'\" \(900 characters\) +sed "s/^X//" >'CHANGES' <<'END_OF_FILE' +XChanges from the earlier BETA releases. +X +Xo dbm_prep does everything now, so dbm_open is just a simple +X wrapper that builds the default filenames. dbm_prep no longer +X requires a (DBM *) db parameter: it allocates one itself. It +X returns (DBM *) db or (DBM *) NULL. +X +Xo makroom is now reliable. In the common-case optimization of the page +X split, the page into which the incoming key/value pair is to be inserted +X is write-deferred (if the split is successful), thereby saving a cosly +X write. BUT, if the split does not make enough room (unsuccessful), the +X deferred page is written out, as the failure-window is now dependent on +X the number of split attempts. +X +Xo if -DDUFF is defined, hash function will also use the DUFF construct. +X This may look like a micro-performance tweak (maybe it is), but in fact, +X the hash function is the third most-heavily used function, after read +X and write. +END_OF_FILE +if test 900 -ne `wc -c <'CHANGES'`; then + echo shar: \"'CHANGES'\" unpacked with wrong size! +fi +# end of 'CHANGES' +fi +if test -f 'COMPARE' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'COMPARE'\" +else +echo shar: Extracting \"'COMPARE'\" \(2832 characters\) +sed "s/^X//" >'COMPARE' <<'END_OF_FILE' +X +XScript started on Thu Sep 28 15:41:06 1989 +X% uname -a +Xtitan titan 4_0 UMIPS mips +X% make all x-dbm +X cc -O -DSDBM -DDUFF -DDUPERROR -DSPLITFAIL -c dbm.c +X cc -O -DSDBM -DDUFF -DDUPERROR -DSPLITFAIL -c sdbm.c +X cc -O -DSDBM -DDUFF -DDUPERROR -DSPLITFAIL -c pair.c +X cc -O -DSDBM -DDUFF -DDUPERROR -DSPLITFAIL -c hash.c +X ar cr libsdbm.a sdbm.o pair.o hash.o +X ranlib libsdbm.a +X cc -o dbm dbm.o libsdbm.a +X cc -O -DSDBM -DDUFF -DDUPERROR -DSPLITFAIL -c dba.c +X cc -o dba dba.o +X cc -O -DSDBM -DDUFF -DDUPERROR -DSPLITFAIL -c dbd.c +X cc -o dbd dbd.o +X cc -O -DSDBM -DDUFF -DDUPERROR -DSPLITFAIL -o x-dbm dbm.o +X% +X% +X% wc history +X 65110 218344 3204883 history +X% +X% /bin/time dbm build foo <history +X +Xreal 5:56.9 +Xuser 13.3 +Xsys 26.3 +X% ls -s +Xtotal 14251 +X 5 README 2 dbd.c 1 hash.c 1 pair.h +X 0 SCRIPT 5 dbd.o 1 hash.o 5 pair.o +X 1 WISHLIST 62 dbm 3130 history 1 port.h +X 46 dba 5 dbm.c 11 howtodbm.txt 11 sdbm.c +X 3 dba.c 8 dbm.o 14 libsdbm.a 2 sdbm.h +X 6 dba.o 4 foo.dir 1 makefile 8 sdbm.o +X 46 dbd 10810 foo.pag 6 pair.c 60 x-dbm +X% ls -l foo.* +X-rw-r--r-- 1 oz 4096 Sep 28 15:48 foo.dir +X-rw-r--r-- 1 oz 11069440 Sep 28 15:48 foo.pag +X% +X% /bin/time x-dbm build bar <history +X +Xreal 5:59.4 +Xuser 24.7 +Xsys 29.1 +X% +X% ls -s +Xtotal 27612 +X 5 README 46 dbd 1 hash.c 5 pair.o +X 1 SCRIPT 2 dbd.c 1 hash.o 1 port.h +X 1 WISHLIST 5 dbd.o 3130 history 11 sdbm.c +X 4 bar.dir 62 dbm 11 howtodbm.txt 2 sdbm.h +X13356 bar.pag 5 dbm.c 14 libsdbm.a 8 sdbm.o +X 46 dba 8 dbm.o 1 makefile 60 x-dbm +X 3 dba.c 4 foo.dir 6 pair.c +X 6 dba.o 10810 foo.pag 1 pair.h +X% +X% ls -l bar.* +X-rw-r--r-- 1 oz 4096 Sep 28 15:54 bar.dir +X-rw-r--r-- 1 oz 13676544 Sep 28 15:54 bar.pag +X% +X% dba foo | tail +X#10801: ok. no entries. +X#10802: ok. no entries. +X#10803: ok. no entries. +X#10804: ok. no entries. +X#10805: ok. no entries. +X#10806: ok. no entries. +X#10807: ok. no entries. +X#10808: ok. no entries. +X#10809: ok. 11 entries 67% used free 337. +X10810 pages (6036 holes): 65073 entries +X% +X% dba bar | tail +X#13347: ok. no entries. +X#13348: ok. no entries. +X#13349: ok. no entries. +X#13350: ok. no entries. +X#13351: ok. no entries. +X#13352: ok. no entries. +X#13353: ok. no entries. +X#13354: ok. no entries. +X#13355: ok. 7 entries 33% used free 676. +X13356 pages (8643 holes): 65073 entries +X% +X% exit +Xscript done on Thu Sep 28 16:08:45 1989 +X +END_OF_FILE +if test 2832 -ne `wc -c <'COMPARE'`; then + echo shar: \"'COMPARE'\" unpacked with wrong size! +fi +# end of 'COMPARE' +fi +if test -f 'README' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'README'\" +else +echo shar: Extracting \"'README'\" \(11457 characters\) +sed "s/^X//" >'README' <<'END_OF_FILE' +X +X +X +X +X +X +X sdbm - Substitute DBM +X or +X Berkeley ndbm for Every UN*X[1] Made Simple +X +X Ozan (oz) Yigit +X +X The Guild of PD Software Toolmakers +X Toronto - Canada +X +X oz@nexus.yorku.ca +X +X +X +XImplementation is the sincerest form of flattery. - L. Peter +XDeutsch +X +XA The Clone of the ndbm library +X +X The sources accompanying this notice - sdbm - consti- +Xtute the first public release (Dec. 1990) of a complete +Xclone of the Berkeley UN*X ndbm library. The sdbm library is +Xmeant to clone the proven functionality of ndbm as closely +Xas possible, including a few improvements. It is practical, +Xeasy to understand, and compatible. The sdbm library is not +Xderived from any licensed, proprietary or copyrighted +Xsoftware. +X +X The sdbm implementation is based on a 1978 algorithm +X[Lar78] by P.-A. (Paul) Larson known as ``Dynamic Hashing''. +XIn the course of searching for a substitute for ndbm, I pro- +Xtotyped three different external-hashing algorithms [Lar78, +XFag79, Lit80] and ultimately chose Larson's algorithm as a +Xbasis of the sdbm implementation. The Bell Labs dbm (and +Xtherefore ndbm) is based on an algorithm invented by Ken +XThompson, [Tho90, Tor87] and predates Larson's work. +X +X The sdbm programming interface is totally compatible +Xwith ndbm and includes a slight improvement in database ini- +Xtialization. It is also expected to be binary-compatible +Xunder most UN*X versions that support the ndbm library. +X +X The sdbm implementation shares the shortcomings of the +Xndbm library, as a side effect of various simplifications to +Xthe original Larson algorithm. It does produce holes in the +Xpage file as it writes pages past the end of file. (Larson's +Xpaper include a clever solution to this problem that is a +Xresult of using the hash value directly as a block address.) +XOn the other hand, extensive tests seem to indicate that +Xsdbm creates fewer holes in general, and the resulting page- +Xfiles are smaller. The sdbm implementation is also faster +Xthan ndbm in database creation. Unlike the ndbm, the sdbm +X_________________________ +X +X [1] UN*X is not a trademark of any (dis)organization. +X +X +X +X +X +X +X +X +X +X - 2 - +X +X +Xstore operation will not ``wander away'' trying to split its +Xdata pages to insert a datum that cannot (due to elaborate +Xworst-case situations) be inserted. (It will fail after a +Xpre-defined number of attempts.) +X +XImportant Compatibility Warning +X +X The sdbm and ndbm libraries cannot share databases: one +Xcannot read the (dir/pag) database created by the other. +XThis is due to the differences between the ndbm and sdbm +Xalgorithms[2], and the hash functions used. It is easy to +Xconvert between the dbm/ndbm databases and sdbm by ignoring +Xthe index completely: see dbd, dbu etc. +X +X +XNotice of Intellectual Property +X +XThe entire sdbm library package, as authored by me, Ozan S. +XYigit, is hereby placed in the public domain. As such, the +Xauthor is not responsible for the consequences of use of +Xthis software, no matter how awful, even if they arise from +Xdefects in it. There is no expressed or implied warranty for +Xthe sdbm library. +X +X Since the sdbm library package is in the public domain, +Xthis original release or any additional public-domain +Xreleases of the modified original cannot possibly (by defin- +Xition) be withheld from you. Also by definition, You (singu- +Xlar) have all the rights to this code (including the right +Xto sell without permission, the right to hoard[3] and the +Xright to do other icky things as you see fit) but those +Xrights are also granted to everyone else. +X +X Please note that all previous distributions of this +Xsoftware contained a copyright (which is now dropped) to +Xprotect its origins and its current public domain status +Xagainst any possible claims and/or challenges. +X +XAcknowledgments +X +X Many people have been very helpful and supportive. A +Xpartial list would necessarily include Rayan Zacherissen +X(who contributed the man page, and also hacked a MMAP +X_________________________ +X +X [2] Torek's discussion [Tor87] indicates that +Xdbm/ndbm implementations use the hash value to traverse +Xthe radix trie differently than sdbm and as a result, +Xthe page indexes are generated in different order. For +Xmore information, send e-mail to the author. +X [3] You cannot really hoard something that is avail- +Xable to the public at large, but try if it makes you +Xfeel any better. +X +X +X +X +X +X +X +X +X +X +X - 3 - +X +X +Xversion of sdbm), Arnold Robbins, Chris Lewis, Bill David- +Xsen, Henry Spencer, Geoff Collyer, Rich Salz (who got me +Xstarted in the first place), Johannes Ruschein (who did the +Xminix port) and David Tilbrook. I thank you all. +X +XDistribution Manifest and Notes +X +XThis distribution of sdbm includes (at least) the following: +X +X CHANGES change log +X README this file. +X biblio a small bibliography on external hashing +X dba.c a crude (n/s)dbm page file analyzer +X dbd.c a crude (n/s)dbm page file dumper (for conversion) +X dbe.1 man page for dbe.c +X dbe.c Janick's database editor +X dbm.c a dbm library emulation wrapper for ndbm/sdbm +X dbm.h header file for the above +X dbu.c a crude db management utility +X hash.c hashing function +X makefile guess. +X pair.c page-level routines (posted earlier) +X pair.h header file for the above +X readme.ms troff source for the README file +X sdbm.3 man page +X sdbm.c the real thing +X sdbm.h header file for the above +X tune.h place for tuning & portability thingies +X util.c miscellaneous +X +X dbu is a simple database manipulation program[4] that +Xtries to look like Bell Labs' cbt utility. It is currently +Xincomplete in functionality. I use dbu to test out the rou- +Xtines: it takes (from stdin) tab separated key/value pairs +Xfor commands like build or insert or takes keys for commands +Xlike delete or look. +X +X dbu <build|creat|look|insert|cat|delete> dbmfile +X +X dba is a crude analyzer of dbm/sdbm/ndbm page files. It +Xscans the entire page file, reporting page level statistics, +Xand totals at the end. +X +X dbd is a crude dump program for dbm/ndbm/sdbm data- +Xbases. It ignores the bitmap, and dumps the data pages in +Xsequence. It can be used to create input for the dbu util- +Xity. Note that dbd will skip any NULLs in the key and data +Xfields, thus is unsuitable to convert some peculiar +X_________________________ +X +X [4] The dbd, dba, dbu utilities are quick hacks and +Xare not fit for production use. They were developed +Xlate one night, just to test out sdbm, and convert some +Xdatabases. +X +X +X +X +X +X +X +X +X +X - 4 - +X +X +Xdatabases that insist in including the terminating null. +X +X I have also included a copy of the dbe (ndbm DataBase +XEditor) by Janick Bergeron [janick@bnr.ca] for your pleas- +Xure. You may find it more useful than the little dbu util- +Xity. +X +X dbm.[ch] is a dbm library emulation on top of ndbm (and +Xhence suitable for sdbm). Written by Robert Elz. +X +X The sdbm library has been around in beta test for quite +Xa long time, and from whatever little feedback I received +X(maybe no news is good news), I believe it has been func- +Xtioning without any significant problems. I would, of +Xcourse, appreciate all fixes and/or improvements. Portabil- +Xity enhancements would especially be useful. +X +XImplementation Issues +X +X Hash functions: The algorithm behind sdbm implementa- +Xtion needs a good bit-scrambling hash function to be effec- +Xtive. I ran into a set of constants for a simple hash func- +Xtion that seem to help sdbm perform better than ndbm for +Xvarious inputs: +X +X /* +X * polynomial conversion ignoring overflows +X * 65599 nice. 65587 even better. +X */ +X long +X dbm_hash(char *str, int len) { +X register unsigned long n = 0; +X +X while (len--) +X n = n * 65599 + *str++; +X return n; +X } +X +X There may be better hash functions for the purposes of +Xdynamic hashing. Try your favorite, and check the pagefile. +XIf it contains too many pages with too many holes, (in rela- +Xtion to this one for example) or if sdbm simply stops work- +Xing (fails after SPLTMAX attempts to split) when you feed +Xyour NEWS history file to it, you probably do not have a +Xgood hashing function. If you do better (for different +Xtypes of input), I would like to know about the function you +Xuse. +X +X Block sizes: It seems (from various tests on a few +Xmachines) that a page file block size PBLKSIZ of 1024 is by +Xfar the best for performance, but this also happens to limit +Xthe size of a key/value pair. Depending on your needs, you +Xmay wish to increase the page size, and also adjust PAIRMAX +X(the maximum size of a key/value pair allowed: should always +X +X +X +X +X +X +X +X +X +X - 5 - +X +X +Xbe at least three words smaller than PBLKSIZ.) accordingly. +XThe system-wide version of the library should probably be +Xconfigured with 1024 (distribution default), as this appears +Xto be sufficient for most common uses of sdbm. +X +XPortability +X +X This package has been tested in many different UN*Xes +Xeven including minix, and appears to be reasonably portable. +XThis does not mean it will port easily to non-UN*X systems. +X +XNotes and Miscellaneous +X +X The sdbm is not a very complicated package, at least +Xnot after you familiarize yourself with the literature on +Xexternal hashing. There are other interesting algorithms in +Xexistence that ensure (approximately) single-read access to +Xa data value associated with any key. These are directory- +Xless schemes such as linear hashing [Lit80] (+ Larson varia- +Xtions), spiral storage [Mar79] or directory schemes such as +Xextensible hashing [Fag79] by Fagin et al. I do hope these +Xsources provide a reasonable playground for experimentation +Xwith other algorithms. See the June 1988 issue of ACM Com- +Xputing Surveys [Enb88] for an excellent overview of the +Xfield. +X +XReferences +X +X +X[Lar78] +X P.-A. Larson, ``Dynamic Hashing'', BIT, vol. 18, pp. +X 184-201, 1978. +X +X[Tho90] +X Ken Thompson, private communication, Nov. 1990 +X +X[Lit80] +X W. Litwin, `` Linear Hashing: A new tool for file and +X table addressing'', Proceedings of the 6th Conference on +X Very Large Dabatases (Montreal), pp. 212-223, Very +X Large Database Foundation, Saratoga, Calif., 1980. +X +X[Fag79] +X R. Fagin, J. Nievergelt, N. Pippinger, and H. R. +X Strong, ``Extendible Hashing - A Fast Access Method for +X Dynamic Files'', ACM Trans. Database Syst., vol. 4, +X no.3, pp. 315-344, Sept. 1979. +X +X[Wal84] +X Rich Wales, ``Discussion of "dbm" data base system'', +X USENET newsgroup unix.wizards, Jan. 1984. +X +X[Tor87] +X Chris Torek, ``Re: dbm.a and ndbm.a archives'', +X +X +X +X +X +X +X +X +X +X - 6 - +X +X +X USENET newsgroup comp.unix, 1987. +X +X[Mar79] +X G. N. Martin, ``Spiral Storage: Incrementally Augment- +X able Hash Addressed Storage'', Technical Report #27, +X University of Varwick, Coventry, U.K., 1979. +X +X[Enb88] +X R. J. Enbody and H. C. Du, ``Dynamic Hashing +X Schemes'',ACM Computing Surveys, vol. 20, no. 2, pp. +X 85-113, June 1988. +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +X +END_OF_FILE +if test 11457 -ne `wc -c <'README'`; then + echo shar: \"'README'\" unpacked with wrong size! +fi +# end of 'README' +fi +if test -f 'biblio' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'biblio'\" +else +echo shar: Extracting \"'biblio'\" \(1012 characters\) +sed "s/^X//" >'biblio' <<'END_OF_FILE' +X%A R. J. Enbody +X%A H. C. Du +X%T Dynamic Hashing Schemes +X%J ACM Computing Surveys +X%V 20 +X%N 2 +X%D June 1988 +X%P 85-113 +X%K surveys +X +X%A P.-A. Larson +X%T Dynamic Hashing +X%J BIT +X%V 18 +X%P 184-201 +X%D 1978 +X%K dynamic +X +X%A W. Litwin +X%T Linear Hashing: A new tool for file and table addressing +X%J Proceedings of the 6th Conference on Very Large Dabatases (Montreal) +X%I Very Large Database Foundation +X%C Saratoga, Calif. +X%P 212-223 +X%D 1980 +X%K linear +X +X%A R. Fagin +X%A J. Nievergelt +X%A N. Pippinger +X%A H. R. Strong +X%T Extendible Hashing - A Fast Access Method for Dynamic Files +X%J ACM Trans. Database Syst. +X%V 4 +X%N 3 +X%D Sept. 1979 +X%P 315-344 +X%K extend +X +X%A G. N. Martin +X%T Spiral Storage: Incrementally Augmentable Hash Addressed Storage +X%J Technical Report #27 +X%I University of Varwick +X%C Coventry, U.K. +X%D 1979 +X%K spiral +X +X%A Chris Torek +X%T Re: dbm.a and ndbm.a archives +X%B USENET newsgroup comp.unix +X%D 1987 +X%K torek +X +X%A Rich Wales +X%T Discusson of "dbm" data base system +X%B USENET newsgroup unix.wizards +X%D Jan. 1984 +X%K rich +X +X +X +X +X +X +END_OF_FILE +if test 1012 -ne `wc -c <'biblio'`; then + echo shar: \"'biblio'\" unpacked with wrong size! +fi +# end of 'biblio' +fi +if test -f 'dba.c' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'dba.c'\" +else +echo shar: Extracting \"'dba.c'\" \(1273 characters\) +sed "s/^X//" >'dba.c' <<'END_OF_FILE' +X/* +X * dba dbm analysis/recovery +X */ +X +X#include <stdio.h> +X#include <sys/file.h> +X#include "sdbm.h" +X +Xchar *progname; +Xextern void oops(); +X +Xint +Xmain(argc, argv) +Xchar **argv; +X{ +X int n; +X char *p; +X char *name; +X int pagf; +X +X progname = argv[0]; +X +X if (p = argv[1]) { +X name = (char *) malloc((n = strlen(p)) + 5); +X strcpy(name, p); +X strcpy(name + n, ".pag"); +X +X if ((pagf = open(name, O_RDONLY)) < 0) +X oops("cannot open %s.", name); +X +X sdump(pagf); +X } +X else +X oops("usage: %s dbname", progname); +X +X return 0; +X} +X +Xsdump(pagf) +Xint pagf; +X{ +X register b; +X register n = 0; +X register t = 0; +X register o = 0; +X register e; +X char pag[PBLKSIZ]; +X +X while ((b = read(pagf, pag, PBLKSIZ)) > 0) { +X printf("#%d: ", n); +X if (!okpage(pag)) +X printf("bad\n"); +X else { +X printf("ok. "); +X if (!(e = pagestat(pag))) +X o++; +X else +X t += e; +X } +X n++; +X } +X +X if (b == 0) +X printf("%d pages (%d holes): %d entries\n", n, o, t); +X else +X oops("read failed: block %d", n); +X} +X +Xpagestat(pag) +Xchar *pag; +X{ +X register n; +X register free; +X register short *ino = (short *) pag; +X +X if (!(n = ino[0])) +X printf("no entries.\n"); +X else { +X free = ino[n] - (n + 1) * sizeof(short); +X printf("%3d entries %2d%% used free %d.\n", +X n / 2, ((PBLKSIZ - free) * 100) / PBLKSIZ, free); +X } +X return n / 2; +X} +END_OF_FILE +if test 1273 -ne `wc -c <'dba.c'`; then + echo shar: \"'dba.c'\" unpacked with wrong size! +fi +# end of 'dba.c' +fi +if test -f 'dbd.c' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'dbd.c'\" +else +echo shar: Extracting \"'dbd.c'\" \(1719 characters\) +sed "s/^X//" >'dbd.c' <<'END_OF_FILE' +X/* +X * dbd - dump a dbm data file +X */ +X +X#include <stdio.h> +X#include <sys/file.h> +X#include "sdbm.h" +X +Xchar *progname; +Xextern void oops(); +X +X +X#define empty(page) (((short *) page)[0] == 0) +X +Xint +Xmain(argc, argv) +Xchar **argv; +X{ +X int n; +X char *p; +X char *name; +X int pagf; +X +X progname = argv[0]; +X +X if (p = argv[1]) { +X name = (char *) malloc((n = strlen(p)) + 5); +X strcpy(name, p); +X strcpy(name + n, ".pag"); +X +X if ((pagf = open(name, O_RDONLY)) < 0) +X oops("cannot open %s.", name); +X +X sdump(pagf); +X } +X else +X oops("usage: %s dbname", progname); +X return 0; +X} +X +Xsdump(pagf) +Xint pagf; +X{ +X register r; +X register n = 0; +X register o = 0; +X char pag[PBLKSIZ]; +X +X while ((r = read(pagf, pag, PBLKSIZ)) > 0) { +X if (!okpage(pag)) +X fprintf(stderr, "%d: bad page.\n", n); +X else if (empty(pag)) +X o++; +X else +X dispage(pag); +X n++; +X } +X +X if (r == 0) +X fprintf(stderr, "%d pages (%d holes).\n", n, o); +X else +X oops("read failed: block %d", n); +X} +X +X +X#ifdef OLD +Xdispage(pag) +Xchar *pag; +X{ +X register i, n; +X register off; +X register short *ino = (short *) pag; +X +X off = PBLKSIZ; +X for (i = 1; i < ino[0]; i += 2) { +X printf("\t[%d]: ", ino[i]); +X for (n = ino[i]; n < off; n++) +X putchar(pag[n]); +X putchar(' '); +X off = ino[i]; +X printf("[%d]: ", ino[i + 1]); +X for (n = ino[i + 1]; n < off; n++) +X putchar(pag[n]); +X off = ino[i + 1]; +X putchar('\n'); +X } +X} +X#else +Xdispage(pag) +Xchar *pag; +X{ +X register i, n; +X register off; +X register short *ino = (short *) pag; +X +X off = PBLKSIZ; +X for (i = 1; i < ino[0]; i += 2) { +X for (n = ino[i]; n < off; n++) +X if (pag[n] != 0) +X putchar(pag[n]); +X putchar('\t'); +X off = ino[i]; +X for (n = ino[i + 1]; n < off; n++) +X if (pag[n] != 0) +X putchar(pag[n]); +X putchar('\n'); +X off = ino[i + 1]; +X } +X} +X#endif +END_OF_FILE +if test 1719 -ne `wc -c <'dbd.c'`; then + echo shar: \"'dbd.c'\" unpacked with wrong size! +fi +# end of 'dbd.c' +fi +if test -f 'dbe.1' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'dbe.1'\" +else +echo shar: Extracting \"'dbe.1'\" \(1454 characters\) +sed "s/^X//" >'dbe.1' <<'END_OF_FILE' +X.TH dbe 1 "ndbm(3) EDITOR" +X.SH NAME +Xdbe \- Edit a ndbm(3) database +X.SH USAGE +Xdbe <database> [-m r|w|rw] [-crtvx] -a|-d|-f|-F|-s [<key> [<content>]] +X.SH DESCRIPTION +X\fIdbme\fP operates on ndbm(3) databases. +XIt can be used to create them, look at them or change them. +XWhen specifying the value of a key or the content of its associated entry, +X\\nnn, \\0, \\n, \\t, \\f and \\r are interpreted as usual. +XWhen displaying key/content pairs, non-printable characters are displayed +Xusing the \\nnn notation. +X.SH OPTIONS +X.IP -a +XList all entries in the database. +X.IP -c +XCreate the database if it does not exist. +X.IP -d +XDelete the entry associated with the specified key. +X.IP -f +XFetch and display the entry associated with the specified key. +X.IP -F +XFetch and display all the entries whose key match the specified +Xregular-expression +X.IP "-m r|w|rw" +XOpen the database in read-only, write-only or read-write mode +X.IP -r +XReplace the entry associated with the specified key if it already exists. +XSee option -s. +X.IP -s +XStore an entry under a specific key. +XAn error occurs if the key already exists and the option -r was not specified. +X.IP -t +XRe-initialize the database before executing the command. +X.IP -v +XVerbose mode. +XConfirm stores and deletions. +X.IP -x +XIf option -x is used with option -c, then if the database already exists, +Xan error occurs. +XThis can be used to implement a simple exclusive access locking mechanism. +X.SH SEE ALSO +Xndbm(3) +X.SH AUTHOR +Xjanick@bnr.ca +X +END_OF_FILE +if test 1454 -ne `wc -c <'dbe.1'`; then + echo shar: \"'dbe.1'\" unpacked with wrong size! +fi +# end of 'dbe.1' +fi +if test -f 'dbe.c' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'dbe.c'\" +else +echo shar: Extracting \"'dbe.c'\" \(9799 characters\) +sed "s/^X//" >'dbe.c' <<'END_OF_FILE' +X#include <stdio.h> +X#ifndef VMS +X#include <sys/file.h> +X#include <ndbm.h> +X#else +X#include "file.h" +X#include "ndbm.h" +X#endif +X#include <ctype.h> +X +X/***************************************************************************\ +X** ** +X** Function name: getopt() ** +X** Author: Henry Spencer, UofT ** +X** Coding date: 84/04/28 ** +X** ** +X** Description: ** +X** ** +X** Parses argv[] for arguments. ** +X** Works with Whitesmith's C compiler. ** +X** ** +X** Inputs - The number of arguments ** +X** - The base address of the array of arguments ** +X** - A string listing the valid options (':' indicates an ** +X** argument to the preceding option is required, a ';' ** +X** indicates an argument to the preceding option is optional) ** +X** ** +X** Outputs - Returns the next option character, ** +X** '?' for non '-' arguments ** +X** or ':' when there is no more arguments. ** +X** ** +X** Side Effects + The argument to an option is pointed to by 'optarg' ** +X** ** +X***************************************************************************** +X** ** +X** REVISION HISTORY: ** +X** ** +X** DATE NAME DESCRIPTION ** +X** YY/MM/DD ------------------ ------------------------------------ ** +X** 88/10/20 Janick Bergeron Returns '?' on unamed arguments ** +X** returns '!' on unknown options ** +X** and 'EOF' only when exhausted. ** +X** 88/11/18 Janick Bergeron Return ':' when no more arguments ** +X** 89/08/11 Janick Bergeron Optional optarg when ';' in optstring ** +X** ** +X\***************************************************************************/ +X +Xchar *optarg; /* Global argument pointer. */ +X +X#ifdef VMS +X#define index strchr +X#endif +X +Xchar +Xgetopt(argc, argv, optstring) +Xint argc; +Xchar **argv; +Xchar *optstring; +X{ +X register int c; +X register char *place; +X extern char *index(); +X static int optind = 0; +X static char *scan = NULL; +X +X optarg = NULL; +X +X if (scan == NULL || *scan == '\0') { +X +X if (optind == 0) +X optind++; +X if (optind >= argc) +X return ':'; +X +X optarg = place = argv[optind++]; +X if (place[0] != '-' || place[1] == '\0') +X return '?'; +X if (place[1] == '-' && place[2] == '\0') +X return '?'; +X scan = place + 1; +X } +X +X c = *scan++; +X place = index(optstring, c); +X if (place == NULL || c == ':' || c == ';') { +X +X (void) fprintf(stderr, "%s: unknown option %c\n", argv[0], c); +X scan = NULL; +X return '!'; +X } +X if (*++place == ':') { +X +X if (*scan != '\0') { +X +X optarg = scan; +X scan = NULL; +X +X } +X else { +X +X if (optind >= argc) { +X +X (void) fprintf(stderr, "%s: %c requires an argument\n", +X argv[0], c); +X return '!'; +X } +X optarg = argv[optind]; +X optind++; +X } +X } +X else if (*place == ';') { +X +X if (*scan != '\0') { +X +X optarg = scan; +X scan = NULL; +X +X } +X else { +X +X if (optind >= argc || *argv[optind] == '-') +X optarg = NULL; +X else { +X optarg = argv[optind]; +X optind++; +X } +X } +X } +X return c; +X} +X +X +Xvoid +Xprint_datum(db) +Xdatum db; +X{ +X int i; +X +X putchar('"'); +X for (i = 0; i < db.dsize; i++) { +X if (isprint(db.dptr[i])) +X putchar(db.dptr[i]); +X else { +X putchar('\\'); +X putchar('0' + ((db.dptr[i] >> 6) & 0x07)); +X putchar('0' + ((db.dptr[i] >> 3) & 0x07)); +X putchar('0' + (db.dptr[i] & 0x07)); +X } +X } +X putchar('"'); +X} +X +X +Xdatum +Xread_datum(s) +Xchar *s; +X{ +X datum db; +X char *p; +X int i; +X +X db.dsize = 0; +X db.dptr = (char *) malloc(strlen(s) * sizeof(char)); +X for (p = db.dptr; *s != '\0'; p++, db.dsize++, s++) { +X if (*s == '\\') { +X if (*++s == 'n') +X *p = '\n'; +X else if (*s == 'r') +X *p = '\r'; +X else if (*s == 'f') +X *p = '\f'; +X else if (*s == 't') +X *p = '\t'; +X else if (isdigit(*s) && isdigit(*(s + 1)) && isdigit(*(s + 2))) { +X i = (*s++ - '0') << 6; +X i |= (*s++ - '0') << 3; +X i |= *s - '0'; +X *p = i; +X } +X else if (*s == '0') +X *p = '\0'; +X else +X *p = *s; +X } +X else +X *p = *s; +X } +X +X return db; +X} +X +X +Xchar * +Xkey2s(db) +Xdatum db; +X{ +X char *buf; +X char *p1, *p2; +X +X buf = (char *) malloc((db.dsize + 1) * sizeof(char)); +X for (p1 = buf, p2 = db.dptr; *p2 != '\0'; *p1++ = *p2++); +X *p1 = '\0'; +X return buf; +X} +X +X +Xmain(argc, argv) +Xint argc; +Xchar **argv; +X{ +X typedef enum { +X YOW, FETCH, STORE, DELETE, SCAN, REGEXP +X } commands; +X char opt; +X int flags; +X int giveusage = 0; +X int verbose = 0; +X commands what = YOW; +X char *comarg[3]; +X int st_flag = DBM_INSERT; +X int argn; +X DBM *db; +X datum key; +X datum content; +X +X flags = O_RDWR; +X argn = 0; +X +X while ((opt = getopt(argc, argv, "acdfFm:rstvx")) != ':') { +X switch (opt) { +X case 'a': +X what = SCAN; +X break; +X case 'c': +X flags |= O_CREAT; +X break; +X case 'd': +X what = DELETE; +X break; +X case 'f': +X what = FETCH; +X break; +X case 'F': +X what = REGEXP; +X break; +X case 'm': +X flags &= ~(000007); +X if (strcmp(optarg, "r") == 0) +X flags |= O_RDONLY; +X else if (strcmp(optarg, "w") == 0) +X flags |= O_WRONLY; +X else if (strcmp(optarg, "rw") == 0) +X flags |= O_RDWR; +X else { +X fprintf(stderr, "Invalid mode: \"%s\"\n", optarg); +X giveusage = 1; +X } +X break; +X case 'r': +X st_flag = DBM_REPLACE; +X break; +X case 's': +X what = STORE; +X break; +X case 't': +X flags |= O_TRUNC; +X break; +X case 'v': +X verbose = 1; +X break; +X case 'x': +X flags |= O_EXCL; +X break; +X case '!': +X giveusage = 1; +X break; +X case '?': +X if (argn < 3) +X comarg[argn++] = optarg; +X else { +X fprintf(stderr, "Too many arguments.\n"); +X giveusage = 1; +X } +X break; +X } +X } +X +X if (giveusage | what == YOW | argn < 1) { +X fprintf(stderr, "Usage: %s databse [-m r|w|rw] [-crtx] -a|-d|-f|-F|-s [key [content]]\n", argv[0]); +X exit(-1); +X } +X +X if ((db = dbm_open(comarg[0], flags, 0777)) == NULL) { +X fprintf(stderr, "Error opening database \"%s\"\n", comarg[0]); +X exit(-1); +X } +X +X if (argn > 1) +X key = read_datum(comarg[1]); +X if (argn > 2) +X content = read_datum(comarg[2]); +X +X switch (what) { +X +X case SCAN: +X key = dbm_firstkey(db); +X if (dbm_error(db)) { +X fprintf(stderr, "Error when fetching first key\n"); +X goto db_exit; +X } +X while (key.dptr != NULL) { +X content = dbm_fetch(db, key); +X if (dbm_error(db)) { +X fprintf(stderr, "Error when fetching "); +X print_datum(key); +X printf("\n"); +X goto db_exit; +X } +X print_datum(key); +X printf(": "); +X print_datum(content); +X printf("\n"); +X if (dbm_error(db)) { +X fprintf(stderr, "Error when fetching next key\n"); +X goto db_exit; +X } +X key = dbm_nextkey(db); +X } +X break; +X +X case REGEXP: +X if (argn < 2) { +X fprintf(stderr, "Missing regular expression.\n"); +X goto db_exit; +X } +X if (re_comp(comarg[1])) { +X fprintf(stderr, "Invalid regular expression\n"); +X goto db_exit; +X } +X key = dbm_firstkey(db); +X if (dbm_error(db)) { +X fprintf(stderr, "Error when fetching first key\n"); +X goto db_exit; +X } +X while (key.dptr != NULL) { +X if (re_exec(key2s(key))) { +X content = dbm_fetch(db, key); +X if (dbm_error(db)) { +X fprintf(stderr, "Error when fetching "); +X print_datum(key); +X printf("\n"); +X goto db_exit; +X } +X print_datum(key); +X printf(": "); +X print_datum(content); +X printf("\n"); +X if (dbm_error(db)) { +X fprintf(stderr, "Error when fetching next key\n"); +X goto db_exit; +X } +X } +X key = dbm_nextkey(db); +X } +X break; +X +X case FETCH: +X if (argn < 2) { +X fprintf(stderr, "Missing fetch key.\n"); +X goto db_exit; +X } +X content = dbm_fetch(db, key); +X if (dbm_error(db)) { +X fprintf(stderr, "Error when fetching "); +X print_datum(key); +X printf("\n"); +X goto db_exit; +X } +X if (content.dptr == NULL) { +X fprintf(stderr, "Cannot find "); +X print_datum(key); +X printf("\n"); +X goto db_exit; +X } +X print_datum(key); +X printf(": "); +X print_datum(content); +X printf("\n"); +X break; +X +X case DELETE: +X if (argn < 2) { +X fprintf(stderr, "Missing delete key.\n"); +X goto db_exit; +X } +X if (dbm_delete(db, key) || dbm_error(db)) { +X fprintf(stderr, "Error when deleting "); +X print_datum(key); +X printf("\n"); +X goto db_exit; +X } +X if (verbose) { +X print_datum(key); +X printf(": DELETED\n"); +X } +X break; +X +X case STORE: +X if (argn < 3) { +X fprintf(stderr, "Missing key and/or content.\n"); +X goto db_exit; +X } +X if (dbm_store(db, key, content, st_flag) || dbm_error(db)) { +X fprintf(stderr, "Error when storing "); +X print_datum(key); +X printf("\n"); +X goto db_exit; +X } +X if (verbose) { +X print_datum(key); +X printf(": "); +X print_datum(content); +X printf(" STORED\n"); +X } +X break; +X } +X +Xdb_exit: +X dbm_clearerr(db); +X dbm_close(db); +X if (dbm_error(db)) { +X fprintf(stderr, "Error closing database \"%s\"\n", comarg[0]); +X exit(-1); +X } +X} +END_OF_FILE +if test 9799 -ne `wc -c <'dbe.c'`; then + echo shar: \"'dbe.c'\" unpacked with wrong size! +fi +# end of 'dbe.c' +fi +if test -f 'dbm.c' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'dbm.c'\" +else +echo shar: Extracting \"'dbm.c'\" \(2426 characters\) +sed "s/^X//" >'dbm.c' <<'END_OF_FILE' +X/* +X * Copyright (c) 1985 The Regents of the University of California. +X * All rights reserved. +X * +X * Redistribution and use in source and binary forms are permitted +X * provided that the above copyright notice and this paragraph are +X * duplicated in all such forms and that any documentation, +X * advertising materials, and other materials related to such +X * distribution and use acknowledge that the software was developed +X * by the University of California, Berkeley. The name of the +X * University may not be used to endorse or promote products derived +X * from this software without specific prior written permission. +X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +X */ +X +X#ifndef lint +Xstatic char sccsid[] = "@(#)dbm.c 5.4 (Berkeley) 5/24/89"; +X#endif /* not lint */ +X +X#include "dbm.h" +X +X#define NODB ((DBM *)0) +X +Xstatic DBM *cur_db = NODB; +X +Xstatic char no_db[] = "dbm: no open database\n"; +X +Xdbminit(file) +X char *file; +X{ +X if (cur_db != NODB) +X dbm_close(cur_db); +X +X cur_db = dbm_open(file, 2, 0); +X if (cur_db == NODB) { +X cur_db = dbm_open(file, 0, 0); +X if (cur_db == NODB) +X return (-1); +X } +X return (0); +X} +X +Xlong +Xforder(key) +Xdatum key; +X{ +X if (cur_db == NODB) { +X printf(no_db); +X return (0L); +X } +X return (dbm_forder(cur_db, key)); +X} +X +Xdatum +Xfetch(key) +Xdatum key; +X{ +X datum item; +X +X if (cur_db == NODB) { +X printf(no_db); +X item.dptr = 0; +X return (item); +X } +X return (dbm_fetch(cur_db, key)); +X} +X +Xdelete(key) +Xdatum key; +X{ +X if (cur_db == NODB) { +X printf(no_db); +X return (-1); +X } +X if (dbm_rdonly(cur_db)) +X return (-1); +X return (dbm_delete(cur_db, key)); +X} +X +Xstore(key, dat) +Xdatum key, dat; +X{ +X if (cur_db == NODB) { +X printf(no_db); +X return (-1); +X } +X if (dbm_rdonly(cur_db)) +X return (-1); +X +X return (dbm_store(cur_db, key, dat, DBM_REPLACE)); +X} +X +Xdatum +Xfirstkey() +X{ +X datum item; +X +X if (cur_db == NODB) { +X printf(no_db); +X item.dptr = 0; +X return (item); +X } +X return (dbm_firstkey(cur_db)); +X} +X +Xdatum +Xnextkey(key) +Xdatum key; +X{ +X datum item; +X +X if (cur_db == NODB) { +X printf(no_db); +X item.dptr = 0; +X return (item); +X } +X return (dbm_nextkey(cur_db, key)); +X} +END_OF_FILE +if test 2426 -ne `wc -c <'dbm.c'`; then + echo shar: \"'dbm.c'\" unpacked with wrong size! +fi +# end of 'dbm.c' +fi +if test -f 'dbm.h' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'dbm.h'\" +else +echo shar: Extracting \"'dbm.h'\" \(1186 characters\) +sed "s/^X//" >'dbm.h' <<'END_OF_FILE' +X/* +X * Copyright (c) 1983 The Regents of the University of California. +X * All rights reserved. +X * +X * Redistribution and use in source and binary forms are permitted +X * provided that the above copyright notice and this paragraph are +X * duplicated in all such forms and that any documentation, +X * advertising materials, and other materials related to such +X * distribution and use acknowledge that the software was developed +X * by the University of California, Berkeley. The name of the +X * University may not be used to endorse or promote products derived +X * from this software without specific prior written permission. +X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +X * +X * @(#)dbm.h 5.2 (Berkeley) 5/24/89 +X */ +X +X#ifndef NULL +X/* +X * this is lunacy, we no longer use it (and never should have +X * unconditionally defined it), but, this whole file is for +X * backwards compatability - someone may rely on this. +X */ +X#define NULL ((char *) 0) +X#endif +X +X#include <ndbm.h> +X +Xdatum fetch(); +Xdatum firstkey(); +Xdatum nextkey(); +END_OF_FILE +if test 1186 -ne `wc -c <'dbm.h'`; then + echo shar: \"'dbm.h'\" unpacked with wrong size! +fi +# end of 'dbm.h' +fi +if test -f 'dbu.c' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'dbu.c'\" +else +echo shar: Extracting \"'dbu.c'\" \(4408 characters\) +sed "s/^X//" >'dbu.c' <<'END_OF_FILE' +X#include <stdio.h> +X#include <sys/file.h> +X#ifdef SDBM +X#include "sdbm.h" +X#else +X#include <ndbm.h> +X#endif +X#include <string.h> +X +X#ifdef BSD42 +X#define strchr index +X#endif +X +Xextern int getopt(); +Xextern char *strchr(); +Xextern void oops(); +X +Xchar *progname; +X +Xstatic int rflag; +Xstatic char *usage = "%s [-R] cat | look |... dbmname"; +X +X#define DERROR 0 +X#define DLOOK 1 +X#define DINSERT 2 +X#define DDELETE 3 +X#define DCAT 4 +X#define DBUILD 5 +X#define DPRESS 6 +X#define DCREAT 7 +X +X#define LINEMAX 8192 +X +Xtypedef struct { +X char *sname; +X int scode; +X int flags; +X} cmd; +X +Xstatic cmd cmds[] = { +X +X "fetch", DLOOK, O_RDONLY, +X "get", DLOOK, O_RDONLY, +X "look", DLOOK, O_RDONLY, +X "add", DINSERT, O_RDWR, +X "insert", DINSERT, O_RDWR, +X "store", DINSERT, O_RDWR, +X "delete", DDELETE, O_RDWR, +X "remove", DDELETE, O_RDWR, +X "dump", DCAT, O_RDONLY, +X "list", DCAT, O_RDONLY, +X "cat", DCAT, O_RDONLY, +X "creat", DCREAT, O_RDWR | O_CREAT | O_TRUNC, +X "new", DCREAT, O_RDWR | O_CREAT | O_TRUNC, +X "build", DBUILD, O_RDWR | O_CREAT, +X "squash", DPRESS, O_RDWR, +X "compact", DPRESS, O_RDWR, +X "compress", DPRESS, O_RDWR +X}; +X +X#define CTABSIZ (sizeof (cmds)/sizeof (cmd)) +X +Xstatic cmd *parse(); +Xstatic void badk(), doit(), prdatum(); +X +Xint +Xmain(argc, argv) +Xint argc; +Xchar *argv[]; +X{ +X int c; +X register cmd *act; +X extern int optind; +X extern char *optarg; +X +X progname = argv[0]; +X +X while ((c = getopt(argc, argv, "R")) != EOF) +X switch (c) { +X case 'R': /* raw processing */ +X rflag++; +X break; +X +X default: +X oops("usage: %s", usage); +X break; +X } +X +X if ((argc -= optind) < 2) +X oops("usage: %s", usage); +X +X if ((act = parse(argv[optind])) == NULL) +X badk(argv[optind]); +X optind++; +X doit(act, argv[optind]); +X return 0; +X} +X +Xstatic void +Xdoit(act, file) +Xregister cmd *act; +Xchar *file; +X{ +X datum key; +X datum val; +X register DBM *db; +X register char *op; +X register int n; +X char *line; +X#ifdef TIME +X long start; +X extern long time(); +X#endif +X +X if ((db = dbm_open(file, act->flags, 0644)) == NULL) +X oops("cannot open: %s", file); +X +X if ((line = (char *) malloc(LINEMAX)) == NULL) +X oops("%s: cannot get memory", "line alloc"); +X +X switch (act->scode) { +X +X case DLOOK: +X while (fgets(line, LINEMAX, stdin) != NULL) { +X n = strlen(line) - 1; +X line[n] = 0; +X key.dptr = line; +X key.dsize = n; +X val = dbm_fetch(db, key); +X if (val.dptr != NULL) { +X prdatum(stdout, val); +X putchar('\n'); +X continue; +X } +X prdatum(stderr, key); +X fprintf(stderr, ": not found.\n"); +X } +X break; +X case DINSERT: +X break; +X case DDELETE: +X while (fgets(line, LINEMAX, stdin) != NULL) { +X n = strlen(line) - 1; +X line[n] = 0; +X key.dptr = line; +X key.dsize = n; +X if (dbm_delete(db, key) == -1) { +X prdatum(stderr, key); +X fprintf(stderr, ": not found.\n"); +X } +X } +X break; +X case DCAT: +X for (key = dbm_firstkey(db); key.dptr != 0; +X key = dbm_nextkey(db)) { +X prdatum(stdout, key); +X putchar('\t'); +X prdatum(stdout, dbm_fetch(db, key)); +X putchar('\n'); +X } +X break; +X case DBUILD: +X#ifdef TIME +X start = time(0); +X#endif +X while (fgets(line, LINEMAX, stdin) != NULL) { +X n = strlen(line) - 1; +X line[n] = 0; +X key.dptr = line; +X if ((op = strchr(line, '\t')) != 0) { +X key.dsize = op - line; +X *op++ = 0; +X val.dptr = op; +X val.dsize = line + n - op; +X } +X else +X oops("bad input; %s", line); +X +X if (dbm_store(db, key, val, DBM_REPLACE) < 0) { +X prdatum(stderr, key); +X fprintf(stderr, ": "); +X oops("store: %s", "failed"); +X } +X } +X#ifdef TIME +X printf("done: %d seconds.\n", time(0) - start); +X#endif +X break; +X case DPRESS: +X break; +X case DCREAT: +X break; +X } +X +X dbm_close(db); +X} +X +Xstatic void +Xbadk(word) +Xchar *word; +X{ +X register int i; +X +X if (progname) +X fprintf(stderr, "%s: ", progname); +X fprintf(stderr, "bad keywd %s. use one of\n", word); +X for (i = 0; i < (int)CTABSIZ; i++) +X fprintf(stderr, "%-8s%c", cmds[i].sname, +X ((i + 1) % 6 == 0) ? '\n' : ' '); +X fprintf(stderr, "\n"); +X exit(1); +X /*NOTREACHED*/ +X} +X +Xstatic cmd * +Xparse(str) +Xregister char *str; +X{ +X register int i = CTABSIZ; +X register cmd *p; +X +X for (p = cmds; i--; p++) +X if (strcmp(p->sname, str) == 0) +X return p; +X return NULL; +X} +X +Xstatic void +Xprdatum(stream, d) +XFILE *stream; +Xdatum d; +X{ +X register int c; +X register char *p = d.dptr; +X register int n = d.dsize; +X +X while (n--) { +X c = *p++ & 0377; +X if (c & 0200) { +X fprintf(stream, "M-"); +X c &= 0177; +X } +X if (c == 0177 || c < ' ') +X fprintf(stream, "^%c", (c == 0177) ? '?' : c + '@'); +X else +X putc(c, stream); +X } +X} +X +X +END_OF_FILE +if test 4408 -ne `wc -c <'dbu.c'`; then + echo shar: \"'dbu.c'\" unpacked with wrong size! +fi +# end of 'dbu.c' +fi +if test -f 'grind' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'grind'\" +else +echo shar: Extracting \"'grind'\" \(201 characters\) +sed "s/^X//" >'grind' <<'END_OF_FILE' +X#!/bin/sh +Xrm -f /tmp/*.dir /tmp/*.pag +Xawk -e '{ +X printf "%s\t", $0 +X for (i = 0; i < 40; i++) +X printf "%s.", $0 +X printf "\n" +X}' < /usr/dict/words | $1 build /tmp/$2 +X +END_OF_FILE +if test 201 -ne `wc -c <'grind'`; then + echo shar: \"'grind'\" unpacked with wrong size! +fi +chmod +x 'grind' +# end of 'grind' +fi +if test -f 'hash.c' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'hash.c'\" +else +echo shar: Extracting \"'hash.c'\" \(922 characters\) +sed "s/^X//" >'hash.c' <<'END_OF_FILE' +X/* +X * sdbm - ndbm work-alike hashed database library +X * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978). +X * author: oz@nexus.yorku.ca +X * status: public domain. keep it that way. +X * +X * hashing routine +X */ +X +X#include "sdbm.h" +X/* +X * polynomial conversion ignoring overflows +X * [this seems to work remarkably well, in fact better +X * then the ndbm hash function. Replace at your own risk] +X * use: 65599 nice. +X * 65587 even better. +X */ +Xlong +Xdbm_hash(str, len) +Xregister char *str; +Xregister int len; +X{ +X register unsigned long n = 0; +X +X#ifdef DUFF +X +X#define HASHC n = *str++ + 65599 * n +X +X if (len > 0) { +X register int loop = (len + 8 - 1) >> 3; +X +X switch(len & (8 - 1)) { +X case 0: do { +X HASHC; case 7: HASHC; +X case 6: HASHC; case 5: HASHC; +X case 4: HASHC; case 3: HASHC; +X case 2: HASHC; case 1: HASHC; +X } while (--loop); +X } +X +X } +X#else +X while (len--) +X n = *str++ + 65599 * n; +X#endif +X return n; +X} +END_OF_FILE +if test 922 -ne `wc -c <'hash.c'`; then + echo shar: \"'hash.c'\" unpacked with wrong size! +fi +# end of 'hash.c' +fi +if test -f 'makefile' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'makefile'\" +else +echo shar: Extracting \"'makefile'\" \(1147 characters\) +sed "s/^X//" >'makefile' <<'END_OF_FILE' +X# +X# makefile for public domain ndbm-clone: sdbm +X# DUFF: use duff's device (loop unroll) in parts of the code +X# +XCFLAGS = -O -DSDBM -DDUFF -DBSD42 +X#LDFLAGS = -p +X +XOBJS = sdbm.o pair.o hash.o +XSRCS = sdbm.c pair.c hash.c dbu.c dba.c dbd.c util.c +XHDRS = tune.h sdbm.h pair.h +XMISC = README CHANGES COMPARE sdbm.3 dbe.c dbe.1 dbm.c dbm.h biblio \ +X readme.ms readme.ps +X +Xall: dbu dba dbd dbe +X +Xdbu: dbu.o sdbm util.o +X cc $(LDFLAGS) -o dbu dbu.o util.o libsdbm.a +X +Xdba: dba.o util.o +X cc $(LDFLAGS) -o dba dba.o util.o +Xdbd: dbd.o util.o +X cc $(LDFLAGS) -o dbd dbd.o util.o +Xdbe: dbe.o sdbm +X cc $(LDFLAGS) -o dbe dbe.o libsdbm.a +X +Xsdbm: $(OBJS) +X ar cr libsdbm.a $(OBJS) +X ranlib libsdbm.a +X### cp libsdbm.a /usr/lib/libsdbm.a +X +Xdba.o: sdbm.h +Xdbu.o: sdbm.h +Xutil.o:sdbm.h +X +X$(OBJS): sdbm.h tune.h pair.h +X +X# +X# dbu using berkelezoid ndbm routines [if you have them] for testing +X# +X#x-dbu: dbu.o util.o +X# cc $(CFLAGS) -o x-dbu dbu.o util.o +Xlint: +X lint -abchx $(SRCS) +X +Xclean: +X rm -f *.o mon.out core +X +Xpurge: clean +X rm -f dbu libsdbm.a dbd dba dbe x-dbu *.dir *.pag +X +Xshar: +X shar $(MISC) makefile $(SRCS) $(HDRS) >SDBM.SHAR +X +Xreadme: +X nroff -ms readme.ms | col -b >README +END_OF_FILE +if test 1147 -ne `wc -c <'makefile'`; then + echo shar: \"'makefile'\" unpacked with wrong size! +fi +# end of 'makefile' +fi +if test -f 'pair.c' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'pair.c'\" +else +echo shar: Extracting \"'pair.c'\" \(5720 characters\) +sed "s/^X//" >'pair.c' <<'END_OF_FILE' +X/* +X * sdbm - ndbm work-alike hashed database library +X * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978). +X * author: oz@nexus.yorku.ca +X * status: public domain. +X * +X * page-level routines +X */ +X +X#ifndef lint +Xstatic char rcsid[] = "$Id: pair.c,v 1.10 90/12/13 13:00:35 oz Exp $"; +X#endif +X +X#include "sdbm.h" +X#include "tune.h" +X#include "pair.h" +X +X#ifndef BSD42 +X#include <memory.h> +X#endif +X +X#define exhash(item) dbm_hash((item).dptr, (item).dsize) +X +X/* +X * forward +X */ +Xstatic int seepair proto((char *, int, char *, int)); +X +X/* +X * page format: +X * +------------------------------+ +X * ino | n | keyoff | datoff | keyoff | +X * +------------+--------+--------+ +X * | datoff | - - - ----> | +X * +--------+---------------------+ +X * | F R E E A R E A | +X * +--------------+---------------+ +X * | <---- - - - | data | +X * +--------+-----+----+----------+ +X * | key | data | key | +X * +--------+----------+----------+ +X * +X * calculating the offsets for free area: if the number +X * of entries (ino[0]) is zero, the offset to the END of +X * the free area is the block size. Otherwise, it is the +X * nth (ino[ino[0]]) entry's offset. +X */ +X +Xint +Xfitpair(pag, need) +Xchar *pag; +Xint need; +X{ +X register int n; +X register int off; +X register int free; +X register short *ino = (short *) pag; +X +X off = ((n = ino[0]) > 0) ? ino[n] : PBLKSIZ; +X free = off - (n + 1) * sizeof(short); +X need += 2 * sizeof(short); +X +X debug(("free %d need %d\n", free, need)); +X +X return need <= free; +X} +X +Xvoid +Xputpair(pag, key, val) +Xchar *pag; +Xdatum key; +Xdatum val; +X{ +X register int n; +X register int off; +X register short *ino = (short *) pag; +X +X off = ((n = ino[0]) > 0) ? ino[n] : PBLKSIZ; +X/* +X * enter the key first +X */ +X off -= key.dsize; +X (void) memcpy(pag + off, key.dptr, key.dsize); +X ino[n + 1] = off; +X/* +X * now the data +X */ +X off -= val.dsize; +X (void) memcpy(pag + off, val.dptr, val.dsize); +X ino[n + 2] = off; +X/* +X * adjust item count +X */ +X ino[0] += 2; +X} +X +Xdatum +Xgetpair(pag, key) +Xchar *pag; +Xdatum key; +X{ +X register int i; +X register int n; +X datum val; +X register short *ino = (short *) pag; +X +X if ((n = ino[0]) == 0) +X return nullitem; +X +X if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0) +X return nullitem; +X +X val.dptr = pag + ino[i + 1]; +X val.dsize = ino[i] - ino[i + 1]; +X return val; +X} +X +X#ifdef SEEDUPS +Xint +Xduppair(pag, key) +Xchar *pag; +Xdatum key; +X{ +X register short *ino = (short *) pag; +X return ino[0] > 0 && seepair(pag, ino[0], key.dptr, key.dsize) > 0; +X} +X#endif +X +Xdatum +Xgetnkey(pag, num) +Xchar *pag; +Xint num; +X{ +X datum key; +X register int off; +X register short *ino = (short *) pag; +X +X num = num * 2 - 1; +X if (ino[0] == 0 || num > ino[0]) +X return nullitem; +X +X off = (num > 1) ? ino[num - 1] : PBLKSIZ; +X +X key.dptr = pag + ino[num]; +X key.dsize = off - ino[num]; +X +X return key; +X} +X +Xint +Xdelpair(pag, key) +Xchar *pag; +Xdatum key; +X{ +X register int n; +X register int i; +X register short *ino = (short *) pag; +X +X if ((n = ino[0]) == 0) +X return 0; +X +X if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0) +X return 0; +X/* +X * found the key. if it is the last entry +X * [i.e. i == n - 1] we just adjust the entry count. +X * hard case: move all data down onto the deleted pair, +X * shift offsets onto deleted offsets, and adjust them. +X * [note: 0 < i < n] +X */ +X if (i < n - 1) { +X register int m; +X register char *dst = pag + (i == 1 ? PBLKSIZ : ino[i - 1]); +X register char *src = pag + ino[i + 1]; +X register int zoo = dst - src; +X +X debug(("free-up %d ", zoo)); +X/* +X * shift data/keys down +X */ +X m = ino[i + 1] - ino[n]; +X#ifdef DUFF +X#define MOVB *--dst = *--src +X +X if (m > 0) { +X register int loop = (m + 8 - 1) >> 3; +X +X switch (m & (8 - 1)) { +X case 0: do { +X MOVB; case 7: MOVB; +X case 6: MOVB; case 5: MOVB; +X case 4: MOVB; case 3: MOVB; +X case 2: MOVB; case 1: MOVB; +X } while (--loop); +X } +X } +X#else +X#ifdef MEMMOVE +X memmove(dst, src, m); +X#else +X while (m--) +X *--dst = *--src; +X#endif +X#endif +X/* +X * adjust offset index up +X */ +X while (i < n - 1) { +X ino[i] = ino[i + 2] + zoo; +X i++; +X } +X } +X ino[0] -= 2; +X return 1; +X} +X +X/* +X * search for the key in the page. +X * return offset index in the range 0 < i < n. +X * return 0 if not found. +X */ +Xstatic int +Xseepair(pag, n, key, siz) +Xchar *pag; +Xregister int n; +Xregister char *key; +Xregister int siz; +X{ +X register int i; +X register int off = PBLKSIZ; +X register short *ino = (short *) pag; +X +X for (i = 1; i < n; i += 2) { +X if (siz == off - ino[i] && +X memcmp(key, pag + ino[i], siz) == 0) +X return i; +X off = ino[i + 1]; +X } +X return 0; +X} +X +Xvoid +Xsplpage(pag, new, sbit) +Xchar *pag; +Xchar *new; +Xlong sbit; +X{ +X datum key; +X datum val; +X +X register int n; +X register int off = PBLKSIZ; +X char cur[PBLKSIZ]; +X register short *ino = (short *) cur; +X +X (void) memcpy(cur, pag, PBLKSIZ); +X (void) memset(pag, 0, PBLKSIZ); +X (void) memset(new, 0, PBLKSIZ); +X +X n = ino[0]; +X for (ino++; n > 0; ino += 2) { +X key.dptr = cur + ino[0]; +X key.dsize = off - ino[0]; +X val.dptr = cur + ino[1]; +X val.dsize = ino[0] - ino[1]; +X/* +X * select the page pointer (by looking at sbit) and insert +X */ +X (void) putpair((exhash(key) & sbit) ? new : pag, key, val); +X +X off = ino[1]; +X n -= 2; +X } +X +X debug(("%d split %d/%d\n", ((short *) cur)[0] / 2, +X ((short *) new)[0] / 2, +X ((short *) pag)[0] / 2)); +X} +X +X/* +X * check page sanity: +X * number of entries should be something +X * reasonable, and all offsets in the index should be in order. +X * this could be made more rigorous. +X */ +Xint +Xchkpage(pag) +Xchar *pag; +X{ +X register int n; +X register int off; +X register short *ino = (short *) pag; +X +X if ((n = ino[0]) < 0 || n > PBLKSIZ / sizeof(short)) +X return 0; +X +X if (n > 0) { +X off = PBLKSIZ; +X for (ino++; n > 0; ino += 2) { +X if (ino[0] > off || ino[1] > off || +X ino[1] > ino[0]) +X return 0; +X off = ino[1]; +X n -= 2; +X } +X } +X return 1; +X} +END_OF_FILE +if test 5720 -ne `wc -c <'pair.c'`; then + echo shar: \"'pair.c'\" unpacked with wrong size! +fi +# end of 'pair.c' +fi +if test -f 'pair.h' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'pair.h'\" +else +echo shar: Extracting \"'pair.h'\" \(378 characters\) +sed "s/^X//" >'pair.h' <<'END_OF_FILE' +Xextern int fitpair proto((char *, int)); +Xextern void putpair proto((char *, datum, datum)); +Xextern datum getpair proto((char *, datum)); +Xextern int delpair proto((char *, datum)); +Xextern int chkpage proto((char *)); +Xextern datum getnkey proto((char *, int)); +Xextern void splpage proto((char *, char *, long)); +X#ifdef SEEDUPS +Xextern int duppair proto((char *, datum)); +X#endif +END_OF_FILE +if test 378 -ne `wc -c <'pair.h'`; then + echo shar: \"'pair.h'\" unpacked with wrong size! +fi +# end of 'pair.h' +fi +if test -f 'readme.ms' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'readme.ms'\" +else +echo shar: Extracting \"'readme.ms'\" \(11691 characters\) +sed "s/^X//" >'readme.ms' <<'END_OF_FILE' +X.\" tbl | readme.ms | [tn]roff -ms | ... +X.\" note the "C" (courier) and "CB" fonts: you will probably have to +X.\" change these. +X.\" $Id: readme.ms,v 1.1 90/12/13 13:09:15 oz Exp Locker: oz $ +X +X.de P1 +X.br +X.nr dT 4 +X.nf +X.ft C +X.sp .5 +X.nr t \\n(dT*\\w'x'u +X.ta 1u*\\ntu 2u*\\ntu 3u*\\ntu 4u*\\ntu 5u*\\ntu 6u*\\ntu 7u*\\ntu 8u*\\ntu 9u*\\ntu 10u*\\ntu 11u*\\ntu 12u*\\ntu 13u*\\ntu 14u*\\ntu +X.. +X.de P2 +X.br +X.ft 1 +X.br +X.sp .5 +X.br +X.fi +X.. +X.\" CW uses the typewriter/courier font. +X.de CW +X\fC\\$1\\fP\\$2 +X.. +X +X.\" Footnote numbering [by Henry Spencer] +X.\" <text>\*f for a footnote number.. +X.\" .FS +X.\" \*F <footnote text> +X.\" .FE +X.\" +X.ds f \\u\\s-2\\n+f\\s+2\\d +X.nr f 0 1 +X.ds F \\n+F. +X.nr F 0 1 +X +X.ND +X.LP +X.TL +X\fIsdbm\fP \(em Substitute DBM +X.br +Xor +X.br +XBerkeley \fIndbm\fP for Every UN*X\** Made Simple +X.AU +XOzan (oz) Yigit +X.AI +XThe Guild of PD Software Toolmakers +XToronto - Canada +X.sp +Xoz@nexus.yorku.ca +X.LP +X.FS +XUN*X is not a trademark of any (dis)organization. +X.FE +X.sp 2 +X\fIImplementation is the sincerest form of flattery. \(em L. Peter Deutsch\fP +X.SH +XA The Clone of the \fIndbm\fP library +X.PP +XThe sources accompanying this notice \(em \fIsdbm\fP \(em constitute +Xthe first public release (Dec. 1990) of a complete clone of +Xthe Berkeley UN*X \fIndbm\fP library. The \fIsdbm\fP library is meant to +Xclone the proven functionality of \fIndbm\fP as closely as possible, +Xincluding a few improvements. It is practical, easy to understand, and +Xcompatible. +XThe \fIsdbm\fP library is not derived from any licensed, proprietary or +Xcopyrighted software. +X.PP +XThe \fIsdbm\fP implementation is based on a 1978 algorithm +X[Lar78] by P.-A. (Paul) Larson known as ``Dynamic Hashing''. +XIn the course of searching for a substitute for \fIndbm\fP, I +Xprototyped three different external-hashing algorithms [Lar78, Fag79, Lit80] +Xand ultimately chose Larson's algorithm as a basis of the \fIsdbm\fP +Ximplementation. The Bell Labs +X\fIdbm\fP (and therefore \fIndbm\fP) is based on an algorithm invented by +XKen Thompson, [Tho90, Tor87] and predates Larson's work. +X.PP +XThe \fIsdbm\fR programming interface is totally compatible +Xwith \fIndbm\fP and includes a slight improvement in database initialization. +XIt is also expected to be binary-compatible under most UN*X versions that +Xsupport the \fIndbm\fP library. +X.PP +XThe \fIsdbm\fP implementation shares the shortcomings of the \fIndbm\fP +Xlibrary, as a side effect of various simplifications to the original Larson +Xalgorithm. It does produce \fIholes\fP in the page file as it writes +Xpages past the end of file. (Larson's paper include a clever solution to +Xthis problem that is a result of using the hash value directly as a block +Xaddress.) On the other hand, extensive tests seem to indicate that \fIsdbm\fP +Xcreates fewer holes in general, and the resulting pagefiles are +Xsmaller. The \fIsdbm\fP implementation is also faster than \fIndbm\fP +Xin database creation. +XUnlike the \fIndbm\fP, the \fIsdbm\fP +X.CW store +Xoperation will not ``wander away'' trying to split its +Xdata pages to insert a datum that \fIcannot\fP (due to elaborate worst-case +Xsituations) be inserted. (It will fail after a pre-defined number of attempts.) +X.SH +XImportant Compatibility Warning +X.PP +XThe \fIsdbm\fP and \fIndbm\fP +Xlibraries \fIcannot\fP share databases: one cannot read the (dir/pag) +Xdatabase created by the other. This is due to the differences +Xbetween the \fIndbm\fP and \fIsdbm\fP algorithms\**, +X.FS +XTorek's discussion [Tor87] +Xindicates that \fIdbm/ndbm\fP implementations use the hash +Xvalue to traverse the radix trie differently than \fIsdbm\fP +Xand as a result, the page indexes are generated in \fIdifferent\fP order. +XFor more information, send e-mail to the author. +X.FE +Xand the hash functions +Xused. +XIt is easy to convert between the \fIdbm/ndbm\fP databases and \fIsdbm\fP +Xby ignoring the index completely: see +X.CW dbd , +X.CW dbu +Xetc. +X.R +X.LP +X.SH +XNotice of Intellectual Property +X.LP +X\fIThe entire\fP sdbm \fIlibrary package, as authored by me,\fP Ozan S. Yigit, +X\fIis hereby placed in the public domain.\fP As such, the author is not +Xresponsible for the consequences of use of this software, no matter how +Xawful, even if they arise from defects in it. There is no expressed or +Ximplied warranty for the \fIsdbm\fP library. +X.PP +XSince the \fIsdbm\fP +Xlibrary package is in the public domain, this \fIoriginal\fP +Xrelease or any additional public-domain releases of the modified original +Xcannot possibly (by definition) be withheld from you. Also by definition, +XYou (singular) have all the rights to this code (including the right to +Xsell without permission, the right to hoard\** +X.FS +XYou cannot really hoard something that is available to the public at +Xlarge, but try if it makes you feel any better. +X.FE +Xand the right to do other icky things as +Xyou see fit) but those rights are also granted to everyone else. +X.PP +XPlease note that all previous distributions of this software contained +Xa copyright (which is now dropped) to protect its +Xorigins and its current public domain status against any possible claims +Xand/or challenges. +X.SH +XAcknowledgments +X.PP +XMany people have been very helpful and supportive. A partial list would +Xnecessarily include Rayan Zacherissen (who contributed the man page, +Xand also hacked a MMAP version of \fIsdbm\fP), +XArnold Robbins, Chris Lewis, +XBill Davidsen, Henry Spencer, Geoff Collyer, Rich Salz (who got me started +Xin the first place), Johannes Ruschein +X(who did the minix port) and David Tilbrook. I thank you all. +X.SH +XDistribution Manifest and Notes +X.LP +XThis distribution of \fIsdbm\fP includes (at least) the following: +X.P1 +X CHANGES change log +X README this file. +X biblio a small bibliography on external hashing +X dba.c a crude (n/s)dbm page file analyzer +X dbd.c a crude (n/s)dbm page file dumper (for conversion) +X dbe.1 man page for dbe.c +X dbe.c Janick's database editor +X dbm.c a dbm library emulation wrapper for ndbm/sdbm +X dbm.h header file for the above +X dbu.c a crude db management utility +X hash.c hashing function +X makefile guess. +X pair.c page-level routines (posted earlier) +X pair.h header file for the above +X readme.ms troff source for the README file +X sdbm.3 man page +X sdbm.c the real thing +X sdbm.h header file for the above +X tune.h place for tuning & portability thingies +X util.c miscellaneous +X.P2 +X.PP +X.CW dbu +Xis a simple database manipulation program\** that tries to look +X.FS +XThe +X.CW dbd , +X.CW dba , +X.CW dbu +Xutilities are quick hacks and are not fit for production use. They were +Xdeveloped late one night, just to test out \fIsdbm\fP, and convert some +Xdatabases. +X.FE +Xlike Bell Labs' +X.CW cbt +Xutility. It is currently incomplete in functionality. +XI use +X.CW dbu +Xto test out the routines: it takes (from stdin) tab separated +Xkey/value pairs for commands like +X.CW build +Xor +X.CW insert +Xor takes keys for +Xcommands like +X.CW delete +Xor +X.CW look . +X.P1 +X dbu <build|creat|look|insert|cat|delete> dbmfile +X.P2 +X.PP +X.CW dba +Xis a crude analyzer of \fIdbm/sdbm/ndbm\fP +Xpage files. It scans the entire +Xpage file, reporting page level statistics, and totals at the end. +X.PP +X.CW dbd +Xis a crude dump program for \fIdbm/ndbm/sdbm\fP +Xdatabases. It ignores the +Xbitmap, and dumps the data pages in sequence. It can be used to create +Xinput for the +X.CW dbu +Xutility. +XNote that +X.CW dbd +Xwill skip any NULLs in the key and data +Xfields, thus is unsuitable to convert some peculiar databases that +Xinsist in including the terminating null. +X.PP +XI have also included a copy of the +X.CW dbe +X(\fIndbm\fP DataBase Editor) by Janick Bergeron [janick@bnr.ca] for +Xyour pleasure. You may find it more useful than the little +X.CW dbu +Xutility. +X.PP +X.CW dbm.[ch] +Xis a \fIdbm\fP library emulation on top of \fIndbm\fP +X(and hence suitable for \fIsdbm\fP). Written by Robert Elz. +X.PP +XThe \fIsdbm\fP +Xlibrary has been around in beta test for quite a long time, and from whatever +Xlittle feedback I received (maybe no news is good news), I believe it has been +Xfunctioning without any significant problems. I would, of course, appreciate +Xall fixes and/or improvements. Portability enhancements would especially be +Xuseful. +X.SH +XImplementation Issues +X.PP +XHash functions: +XThe algorithm behind \fIsdbm\fP implementation needs a good bit-scrambling +Xhash function to be effective. I ran into a set of constants for a simple +Xhash function that seem to help \fIsdbm\fP perform better than \fIndbm\fP +Xfor various inputs: +X.P1 +X /* +X * polynomial conversion ignoring overflows +X * 65599 nice. 65587 even better. +X */ +X long +X dbm_hash(char *str, int len) { +X register unsigned long n = 0; +X +X while (len--) +X n = n * 65599 + *str++; +X return n; +X } +X.P2 +X.PP +XThere may be better hash functions for the purposes of dynamic hashing. +XTry your favorite, and check the pagefile. If it contains too many pages +Xwith too many holes, (in relation to this one for example) or if +X\fIsdbm\fP +Xsimply stops working (fails after +X.CW SPLTMAX +Xattempts to split) when you feed your +XNEWS +X.CW history +Xfile to it, you probably do not have a good hashing function. +XIf you do better (for different types of input), I would like to know +Xabout the function you use. +X.PP +XBlock sizes: It seems (from various tests on a few machines) that a page +Xfile block size +X.CW PBLKSIZ +Xof 1024 is by far the best for performance, but +Xthis also happens to limit the size of a key/value pair. Depending on your +Xneeds, you may wish to increase the page size, and also adjust +X.CW PAIRMAX +X(the maximum size of a key/value pair allowed: should always be at least +Xthree words smaller than +X.CW PBLKSIZ .) +Xaccordingly. The system-wide version of the library +Xshould probably be +Xconfigured with 1024 (distribution default), as this appears to be sufficient +Xfor most common uses of \fIsdbm\fP. +X.SH +XPortability +X.PP +XThis package has been tested in many different UN*Xes even including minix, +Xand appears to be reasonably portable. This does not mean it will port +Xeasily to non-UN*X systems. +X.SH +XNotes and Miscellaneous +X.PP +XThe \fIsdbm\fP is not a very complicated package, at least not after you +Xfamiliarize yourself with the literature on external hashing. There are +Xother interesting algorithms in existence that ensure (approximately) +Xsingle-read access to a data value associated with any key. These are +Xdirectory-less schemes such as \fIlinear hashing\fP [Lit80] (+ Larson +Xvariations), \fIspiral storage\fP [Mar79] or directory schemes such as +X\fIextensible hashing\fP [Fag79] by Fagin et al. I do hope these sources +Xprovide a reasonable playground for experimentation with other algorithms. +XSee the June 1988 issue of ACM Computing Surveys [Enb88] for an +Xexcellent overview of the field. +X.PG +X.SH +XReferences +X.LP +X.IP [Lar78] 4m +XP.-A. Larson, +X``Dynamic Hashing'', \fIBIT\fP, vol. 18, pp. 184-201, 1978. +X.IP [Tho90] 4m +XKen Thompson, \fIprivate communication\fP, Nov. 1990 +X.IP [Lit80] 4m +XW. Litwin, +X`` Linear Hashing: A new tool for file and table addressing'', +X\fIProceedings of the 6th Conference on Very Large Dabatases (Montreal)\fP, +Xpp. 212-223, Very Large Database Foundation, Saratoga, Calif., 1980. +X.IP [Fag79] 4m +XR. Fagin, J. Nievergelt, N. Pippinger, and H. R. Strong, +X``Extendible Hashing - A Fast Access Method for Dynamic Files'', +X\fIACM Trans. Database Syst.\fP, vol. 4, no.3, pp. 315-344, Sept. 1979. +X.IP [Wal84] 4m +XRich Wales, +X``Discussion of "dbm" data base system'', \fIUSENET newsgroup unix.wizards\fP, +XJan. 1984. +X.IP [Tor87] 4m +XChris Torek, +X``Re: dbm.a and ndbm.a archives'', \fIUSENET newsgroup comp.unix\fP, +X1987. +X.IP [Mar79] 4m +XG. N. Martin, +X``Spiral Storage: Incrementally Augmentable Hash Addressed Storage'', +X\fITechnical Report #27\fP, University of Varwick, Coventry, U.K., 1979. +X.IP [Enb88] 4m +XR. J. Enbody and H. C. Du, +X``Dynamic Hashing Schemes'',\fIACM Computing Surveys\fP, +Xvol. 20, no. 2, pp. 85-113, June 1988. +END_OF_FILE +if test 11691 -ne `wc -c <'readme.ms'`; then + echo shar: \"'readme.ms'\" unpacked with wrong size! +fi +# end of 'readme.ms' +fi +if test -f 'readme.ps' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'readme.ps'\" +else +echo shar: Extracting \"'readme.ps'\" \(33302 characters\) +sed "s/^X//" >'readme.ps' <<'END_OF_FILE' +X%!PS-Adobe-1.0 +X%%Creator: yetti:oz (Ozan Yigit) +X%%Title: stdin (ditroff) +X%%CreationDate: Thu Dec 13 15:56:08 1990 +X%%EndComments +X% lib/psdit.pro -- prolog for psdit (ditroff) files +X% Copyright (c) 1984, 1985 Adobe Systems Incorporated. All Rights Reserved. +X% last edit: shore Sat Nov 23 20:28:03 1985 +X% RCSID: $Header: psdit.pro,v 2.1 85/11/24 12:19:43 shore Rel $ +X +X/$DITroff 140 dict def $DITroff begin +X/fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def +X/xi {0 72 11 mul translate 72 resolution div dup neg scale 0 0 moveto +X /fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def F +X /pagesave save def}def +X/PB{save /psv exch def currentpoint translate +X resolution 72 div dup neg scale 0 0 moveto}def +X/PE{psv restore}def +X/arctoobig 90 def /arctoosmall .05 def +X/m1 matrix def /m2 matrix def /m3 matrix def /oldmat matrix def +X/tan{dup sin exch cos div}def +X/point{resolution 72 div mul}def +X/dround {transform round exch round exch itransform}def +X/xT{/devname exch def}def +X/xr{/mh exch def /my exch def /resolution exch def}def +X/xp{}def +X/xs{docsave restore end}def +X/xt{}def +X/xf{/fontname exch def /slotno exch def fontnames slotno get fontname eq not +X {fonts slotno fontname findfont put fontnames slotno fontname put}if}def +X/xH{/fontheight exch def F}def +X/xS{/fontslant exch def F}def +X/s{/fontsize exch def /fontheight fontsize def F}def +X/f{/fontnum exch def F}def +X/F{fontheight 0 le {/fontheight fontsize def}if +X fonts fontnum get fontsize point 0 0 fontheight point neg 0 0 m1 astore +X fontslant 0 ne{1 0 fontslant tan 1 0 0 m2 astore m3 concatmatrix}if +X makefont setfont .04 fontsize point mul 0 dround pop setlinewidth}def +X/X{exch currentpoint exch pop moveto show}def +X/N{3 1 roll moveto show}def +X/Y{exch currentpoint pop exch moveto show}def +X/S{show}def +X/ditpush{}def/ditpop{}def +X/AX{3 -1 roll currentpoint exch pop moveto 0 exch ashow}def +X/AN{4 2 roll moveto 0 exch ashow}def +X/AY{3 -1 roll currentpoint pop exch moveto 0 exch ashow}def +X/AS{0 exch ashow}def +X/MX{currentpoint exch pop moveto}def +X/MY{currentpoint pop exch moveto}def +X/MXY{moveto}def +X/cb{pop}def % action on unknown char -- nothing for now +X/n{}def/w{}def +X/p{pop showpage pagesave restore /pagesave save def}def +X/abspoint{currentpoint exch pop add exch currentpoint pop add exch}def +X/distance{dup mul exch dup mul add sqrt}def +X/dstroke{currentpoint stroke moveto}def +X/Dl{2 copy gsave rlineto stroke grestore rmoveto}def +X/arcellipse{/diamv exch def /diamh exch def oldmat currentmatrix pop +X currentpoint translate 1 diamv diamh div scale /rad diamh 2 div def +X currentpoint exch rad add exch rad -180 180 arc oldmat setmatrix}def +X/Dc{dup arcellipse dstroke}def +X/De{arcellipse dstroke}def +X/Da{/endv exch def /endh exch def /centerv exch def /centerh exch def +X /cradius centerv centerv mul centerh centerh mul add sqrt def +X /eradius endv endv mul endh endh mul add sqrt def +X /endang endv endh atan def +X /startang centerv neg centerh neg atan def +X /sweep startang endang sub dup 0 lt{360 add}if def +X sweep arctoobig gt +X {/midang startang sweep 2 div sub def /midrad cradius eradius add 2 div def +X /midh midang cos midrad mul def /midv midang sin midrad mul def +X midh neg midv neg endh endv centerh centerv midh midv Da +X currentpoint moveto Da} +X {sweep arctoosmall ge +X {/controldelt 1 sweep 2 div cos sub 3 sweep 2 div sin mul div 4 mul def +X centerv neg controldelt mul centerh controldelt mul +X endv neg controldelt mul centerh add endh add +X endh controldelt mul centerv add endv add +X centerh endh add centerv endv add rcurveto dstroke} +X {centerh endh add centerv endv add rlineto dstroke}ifelse}ifelse}def +X +X/Barray 200 array def % 200 values in a wiggle +X/D~{mark}def +X/D~~{counttomark Barray exch 0 exch getinterval astore /Bcontrol exch def pop +X /Blen Bcontrol length def Blen 4 ge Blen 2 mod 0 eq and +X {Bcontrol 0 get Bcontrol 1 get abspoint /Ycont exch def /Xcont exch def +X Bcontrol 0 2 copy get 2 mul put Bcontrol 1 2 copy get 2 mul put +X Bcontrol Blen 2 sub 2 copy get 2 mul put +X Bcontrol Blen 1 sub 2 copy get 2 mul put +X /Ybi /Xbi currentpoint 3 1 roll def def 0 2 Blen 4 sub +X {/i exch def +X Bcontrol i get 3 div Bcontrol i 1 add get 3 div +X Bcontrol i get 3 mul Bcontrol i 2 add get add 6 div +X Bcontrol i 1 add get 3 mul Bcontrol i 3 add get add 6 div +X /Xbi Xcont Bcontrol i 2 add get 2 div add def +X /Ybi Ycont Bcontrol i 3 add get 2 div add def +X /Xcont Xcont Bcontrol i 2 add get add def +X /Ycont Ycont Bcontrol i 3 add get add def +X Xbi currentpoint pop sub Ybi currentpoint exch pop sub rcurveto +X }for dstroke}if}def +Xend +X/ditstart{$DITroff begin +X /nfonts 60 def % NFONTS makedev/ditroff dependent! +X /fonts[nfonts{0}repeat]def +X /fontnames[nfonts{()}repeat]def +X/docsave save def +X}def +X +X% character outcalls +X/oc {/pswid exch def /cc exch def /name exch def +X /ditwid pswid fontsize mul resolution mul 72000 div def +X /ditsiz fontsize resolution mul 72 div def +X ocprocs name known{ocprocs name get exec}{name cb} +X ifelse}def +X/fractm [.65 0 0 .6 0 0] def +X/fraction +X {/fden exch def /fnum exch def gsave /cf currentfont def +X cf fractm makefont setfont 0 .3 dm 2 copy neg rmoveto +X fnum show rmoveto currentfont cf setfont(\244)show setfont fden show +X grestore ditwid 0 rmoveto} def +X/oce {grestore ditwid 0 rmoveto}def +X/dm {ditsiz mul}def +X/ocprocs 50 dict def ocprocs begin +X(14){(1)(4)fraction}def +X(12){(1)(2)fraction}def +X(34){(3)(4)fraction}def +X(13){(1)(3)fraction}def +X(23){(2)(3)fraction}def +X(18){(1)(8)fraction}def +X(38){(3)(8)fraction}def +X(58){(5)(8)fraction}def +X(78){(7)(8)fraction}def +X(sr){gsave 0 .06 dm rmoveto(\326)show oce}def +X(is){gsave 0 .15 dm rmoveto(\362)show oce}def +X(->){gsave 0 .02 dm rmoveto(\256)show oce}def +X(<-){gsave 0 .02 dm rmoveto(\254)show oce}def +X(==){gsave 0 .05 dm rmoveto(\272)show oce}def +Xend +X +X% an attempt at a PostScript FONT to implement ditroff special chars +X% this will enable us to +X% cache the little buggers +X% generate faster, more compact PS out of psdit +X% confuse everyone (including myself)! +X50 dict dup begin +X/FontType 3 def +X/FontName /DIThacks def +X/FontMatrix [.001 0 0 .001 0 0] def +X/FontBBox [-260 -260 900 900] def% a lie but ... +X/Encoding 256 array def +X0 1 255{Encoding exch /.notdef put}for +XEncoding +X dup 8#040/space put %space +X dup 8#110/rc put %right ceil +X dup 8#111/lt put %left top curl +X dup 8#112/bv put %bold vert +X dup 8#113/lk put %left mid curl +X dup 8#114/lb put %left bot curl +X dup 8#115/rt put %right top curl +X dup 8#116/rk put %right mid curl +X dup 8#117/rb put %right bot curl +X dup 8#120/rf put %right floor +X dup 8#121/lf put %left floor +X dup 8#122/lc put %left ceil +X dup 8#140/sq put %square +X dup 8#141/bx put %box +X dup 8#142/ci put %circle +X dup 8#143/br put %box rule +X dup 8#144/rn put %root extender +X dup 8#145/vr put %vertical rule +X dup 8#146/ob put %outline bullet +X dup 8#147/bu put %bullet +X dup 8#150/ru put %rule +X dup 8#151/ul put %underline +X pop +X/DITfd 100 dict def +X/BuildChar{0 begin +X /cc exch def /fd exch def +X /charname fd /Encoding get cc get def +X /charwid fd /Metrics get charname get def +X /charproc fd /CharProcs get charname get def +X charwid 0 fd /FontBBox get aload pop setcachedevice +X 2 setlinejoin 40 setlinewidth +X newpath 0 0 moveto gsave charproc grestore +X end}def +X/BuildChar load 0 DITfd put +X%/UniqueID 5 def +X/CharProcs 50 dict def +XCharProcs begin +X/space{}def +X/.notdef{}def +X/ru{500 0 rls}def +X/rn{0 840 moveto 500 0 rls}def +X/vr{0 800 moveto 0 -770 rls}def +X/bv{0 800 moveto 0 -1000 rls}def +X/br{0 750 moveto 0 -1000 rls}def +X/ul{0 -140 moveto 500 0 rls}def +X/ob{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath stroke}def +X/bu{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath fill}def +X/sq{80 0 rmoveto currentpoint dround newpath moveto +X 640 0 rlineto 0 640 rlineto -640 0 rlineto closepath stroke}def +X/bx{80 0 rmoveto currentpoint dround newpath moveto +X 640 0 rlineto 0 640 rlineto -640 0 rlineto closepath fill}def +X/ci{500 360 rmoveto currentpoint newpath 333 0 360 arc +X 50 setlinewidth stroke}def +X +X/lt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 add exch s4 a4p stroke}def +X/lb{0 800 moveto 0 -550 rlineto currx -200 2cx s4 add exch s4 a4p stroke}def +X/rt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 sub exch s4 a4p stroke}def +X/rb{0 800 moveto 0 -500 rlineto currx -200 2cx s4 sub exch s4 a4p stroke}def +X/lk{0 800 moveto 0 300 -300 300 s4 arcto pop pop 1000 sub +X 0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def +X/rk{0 800 moveto 0 300 s2 300 s4 arcto pop pop 1000 sub +X 0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def +X/lf{0 800 moveto 0 -1000 rlineto s4 0 rls}def +X/rf{0 800 moveto 0 -1000 rlineto s4 neg 0 rls}def +X/lc{0 -200 moveto 0 1000 rlineto s4 0 rls}def +X/rc{0 -200 moveto 0 1000 rlineto s4 neg 0 rls}def +Xend +X +X/Metrics 50 dict def Metrics begin +X/.notdef 0 def +X/space 500 def +X/ru 500 def +X/br 0 def +X/lt 416 def +X/lb 416 def +X/rt 416 def +X/rb 416 def +X/lk 416 def +X/rk 416 def +X/rc 416 def +X/lc 416 def +X/rf 416 def +X/lf 416 def +X/bv 416 def +X/ob 350 def +X/bu 350 def +X/ci 750 def +X/bx 750 def +X/sq 750 def +X/rn 500 def +X/ul 500 def +X/vr 0 def +Xend +X +XDITfd begin +X/s2 500 def /s4 250 def /s3 333 def +X/a4p{arcto pop pop pop pop}def +X/2cx{2 copy exch}def +X/rls{rlineto stroke}def +X/currx{currentpoint pop}def +X/dround{transform round exch round exch itransform} def +Xend +Xend +X/DIThacks exch definefont pop +Xditstart +X(psc)xT +X576 1 1 xr +X1(Times-Roman)xf 1 f +X2(Times-Italic)xf 2 f +X3(Times-Bold)xf 3 f +X4(Times-BoldItalic)xf 4 f +X5(Helvetica)xf 5 f +X6(Helvetica-Bold)xf 6 f +X7(Courier)xf 7 f +X8(Courier-Bold)xf 8 f +X9(Symbol)xf 9 f +X10(DIThacks)xf 10 f +X10 s +X1 f +Xxi +X%%EndProlog +X +X%%Page: 1 1 +X10 s 0 xH 0 xS 1 f +X8 s +X2 f +X12 s +X1778 672(sdbm)N +X3 f +X2004(\320)X +X2124(Substitute)X +X2563(DBM)X +X2237 768(or)N +X1331 864(Berkeley)N +X2 f +X1719(ndbm)X +X3 f +X1956(for)X +X2103(Every)X +X2373(UN*X)X +X1 f +X10 s +X2628 832(1)N +X3 f +X12 s +X2692 864(Made)N +X2951(Simple)X +X2 f +X10 s +X2041 1056(Ozan)N +X2230(\(oz\))X +X2375(Yigit)X +X1 f +X1658 1200(The)N +X1803(Guild)X +X2005(of)X +X2092(PD)X +X2214(Software)X +X2524(Toolmakers)X +X2000 1296(Toronto)N +X2278(-)X +X2325(Canada)X +X1965 1488(oz@nexus.yorku.ca)N +X2 f +X555 1804(Implementation)N +X1078(is)X +X1151(the)X +X1269(sincerest)X +X1574(form)X +X1745(of)X +X1827(\257attery.)X +X2094(\320)X +X2185(L.)X +X2269(Peter)X +X2463(Deutsch)X +X3 f +X555 1996(A)N +X633(The)X +X786(Clone)X +X1006(of)X +X1093(the)X +X2 f +X1220(ndbm)X +X3 f +X1418(library)X +X1 f +X755 2120(The)N +X903(sources)X +X1167(accompanying)X +X1658(this)X +X1796(notice)X +X2015(\320)X +X2 f +X2118(sdbm)X +X1 f +X2309(\320)X +X2411(constitute)X +X2744(the)X +X2864(\256rst)X +X3010(public)X +X3232(release)X +X3478(\(Dec.)X +X3677(1990\))X +X3886(of)X +X3975(a)X +X555 2216(complete)N +X874(clone)X +X1073(of)X +X1165(the)X +X1288(Berkeley)X +X1603(UN*X)X +X2 f +X1842(ndbm)X +X1 f +X2045(library.)X +X2304(The)X +X2 f +X2454(sdbm)X +X1 f +X2648(library)X +X2887(is)X +X2965(meant)X +X3186(to)X +X3273(clone)X +X3472(the)X +X3594(proven)X +X3841(func-)X +X555 2312(tionality)N +X846(of)X +X2 f +X938(ndbm)X +X1 f +X1141(as)X +X1233(closely)X +X1485(as)X +X1576(possible,)X +X1882(including)X +X2208(a)X +X2268(few)X +X2413(improvements.)X +X2915(It)X +X2988(is)X +X3065(practical,)X +X3386(easy)X +X3553(to)X +X3639(understand,)X +X555 2408(and)N +X691(compatible.)X +X1107(The)X +X2 f +X1252(sdbm)X +X1 f +X1441(library)X +X1675(is)X +X1748(not)X +X1870(derived)X +X2131(from)X +X2307(any)X +X2443(licensed,)X +X2746(proprietary)X +X3123(or)X +X3210(copyrighted)X +X3613(software.)X +X755 2532(The)N +X2 f +X910(sdbm)X +X1 f +X1109(implementation)X +X1641(is)X +X1723(based)X +X1935(on)X +X2044(a)X +X2109(1978)X +X2298(algorithm)X +X2638([Lar78])X +X2913(by)X +X3022(P.-A.)X +X3220(\(Paul\))X +X3445(Larson)X +X3697(known)X +X3944(as)X +X555 2628(``Dynamic)N +X934(Hashing''.)X +X1326(In)X +X1424(the)X +X1553(course)X +X1794(of)X +X1892(searching)X +X2231(for)X +X2355(a)X +X2421(substitute)X +X2757(for)X +X2 f +X2881(ndbm)X +X1 f +X3059(,)X +X3109(I)X +X3166(prototyped)X +X3543(three)X +X3734(different)X +X555 2724(external-hashing)N +X1119(algorithms)X +X1490([Lar78,)X +X1758(Fag79,)X +X2007(Lit80])X +X2236(and)X +X2381(ultimately)X +X2734(chose)X +X2946(Larson's)X +X3256(algorithm)X +X3596(as)X +X3692(a)X +X3756(basis)X +X3944(of)X +X555 2820(the)N +X2 f +X680(sdbm)X +X1 f +X875(implementation.)X +X1423(The)X +X1574(Bell)X +X1733(Labs)X +X2 f +X1915(dbm)X +X1 f +X2079(\(and)X +X2248(therefore)X +X2 f +X2565(ndbm)X +X1 f +X2743(\))X +X2796(is)X +X2875(based)X +X3084(on)X +X3190(an)X +X3292(algorithm)X +X3629(invented)X +X3931(by)X +X555 2916(Ken)N +X709(Thompson,)X +X1091([Tho90,)X +X1367(Tor87])X +X1610(and)X +X1746(predates)X +X2034(Larson's)X +X2335(work.)X +X755 3040(The)N +X2 f +X903(sdbm)X +X1 f +X1095(programming)X +X1553(interface)X +X1857(is)X +X1932(totally)X +X2158(compatible)X +X2536(with)X +X2 f +X2700(ndbm)X +X1 f +X2900(and)X +X3038(includes)X +X3327(a)X +X3385(slight)X +X3584(improvement)X +X555 3136(in)N +X641(database)X +X942(initialization.)X +X1410(It)X +X1483(is)X +X1560(also)X +X1713(expected)X +X2023(to)X +X2109(be)X +X2208(binary-compatible)X +X2819(under)X +X3025(most)X +X3203(UN*X)X +X3440(versions)X +X3730(that)X +X3873(sup-)X +X555 3232(port)N +X704(the)X +X2 f +X822(ndbm)X +X1 f +X1020(library.)X +X755 3356(The)N +X2 f +X909(sdbm)X +X1 f +X1107(implementation)X +X1638(shares)X +X1868(the)X +X1995(shortcomings)X +X2455(of)X +X2551(the)X +X2 f +X2678(ndbm)X +X1 f +X2885(library,)X +X3148(as)X +X3244(a)X +X3309(side)X +X3467(effect)X +X3680(of)X +X3775(various)X +X555 3452(simpli\256cations)N +X1046(to)X +X1129(the)X +X1248(original)X +X1518(Larson)X +X1762(algorithm.)X +X2114(It)X +X2183(does)X +X2350(produce)X +X2 f +X2629(holes)X +X1 f +X2818(in)X +X2900(the)X +X3018(page)X +X3190(\256le)X +X3312(as)X +X3399(it)X +X3463(writes)X +X3679(pages)X +X3882(past)X +X555 3548(the)N +X680(end)X +X823(of)X +X917(\256le.)X +X1066(\(Larson's)X +X1400(paper)X +X1605(include)X +X1867(a)X +X1929(clever)X +X2152(solution)X +X2435(to)X +X2523(this)X +X2664(problem)X +X2957(that)X +X3103(is)X +X3182(a)X +X3244(result)X +X3448(of)X +X3541(using)X +X3740(the)X +X3864(hash)X +X555 3644(value)N +X758(directly)X +X1032(as)X +X1128(a)X +X1193(block)X +X1400(address.\))X +X1717(On)X +X1844(the)X +X1971(other)X +X2165(hand,)X +X2370(extensive)X +X2702(tests)X +X2873(seem)X +X3067(to)X +X3158(indicate)X +X3441(that)X +X2 f +X3590(sdbm)X +X1 f +X3787(creates)X +X555 3740(fewer)N +X762(holes)X +X954(in)X +X1039(general,)X +X1318(and)X +X1456(the)X +X1576(resulting)X +X1878(page\256les)X +X2185(are)X +X2306(smaller.)X +X2584(The)X +X2 f +X2731(sdbm)X +X1 f +X2922(implementation)X +X3446(is)X +X3521(also)X +X3672(faster)X +X3873(than)X +X2 f +X555 3836(ndbm)N +X1 f +X757(in)X +X843(database)X +X1144(creation.)X +X1467(Unlike)X +X1709(the)X +X2 f +X1831(ndbm)X +X1 f +X2009(,)X +X2053(the)X +X2 f +X2175(sdbm)X +X7 f +X2396(store)X +X1 f +X2660(operation)X +X2987(will)X +X3134(not)X +X3259(``wander)X +X3573(away'')X +X3820(trying)X +X555 3932(to)N +X642(split)X +X804(its)X +X904(data)X +X1063(pages)X +X1271(to)X +X1358(insert)X +X1561(a)X +X1622(datum)X +X1847(that)X +X2 f +X1992(cannot)X +X1 f +X2235(\(due)X +X2403(to)X +X2490(elaborate)X +X2810(worst-case)X +X3179(situations\))X +X3537(be)X +X3637(inserted.)X +X3935(\(It)X +X555 4028(will)N +X699(fail)X +X826(after)X +X994(a)X +X1050(pre-de\256ned)X +X1436(number)X +X1701(of)X +X1788(attempts.\))X +X3 f +X555 4220(Important)N +X931(Compatibility)X +X1426(Warning)X +X1 f +X755 4344(The)N +X2 f +X904(sdbm)X +X1 f +X1097(and)X +X2 f +X1237(ndbm)X +X1 f +X1439(libraries)X +X2 f +X1726(cannot)X +X1 f +X1968(share)X +X2162(databases:)X +X2515(one)X +X2654(cannot)X +X2891(read)X +X3053(the)X +X3174(\(dir/pag\))X +X3478(database)X +X3778(created)X +X555 4440(by)N +X657(the)X +X777(other.)X +X984(This)X +X1148(is)X +X1222(due)X +X1359(to)X +X1442(the)X +X1561(differences)X +X1940(between)X +X2229(the)X +X2 f +X2348(ndbm)X +X1 f +X2547(and)X +X2 f +X2684(sdbm)X +X1 f +X2874(algorithms)X +X8 s +X3216 4415(2)N +X10 s +X4440(,)Y +X3289(and)X +X3426(the)X +X3545(hash)X +X3713(functions)X +X555 4536(used.)N +X769(It)X +X845(is)X +X925(easy)X +X1094(to)X +X1182(convert)X +X1449(between)X +X1743(the)X +X2 f +X1867(dbm/ndbm)X +X1 f +X2231(databases)X +X2565(and)X +X2 f +X2707(sdbm)X +X1 f +X2902(by)X +X3008(ignoring)X +X3305(the)X +X3429(index)X +X3633(completely:)X +X555 4632(see)N +X7 f +X706(dbd)X +X1 f +X(,)S +X7 f +X918(dbu)X +X1 f +X1082(etc.)X +X3 f +X555 4852(Notice)N +X794(of)X +X881(Intellectual)X +X1288(Property)X +X2 f +X555 4976(The)N +X696(entire)X +X1 f +X904(sdbm)X +X2 f +X1118(library)X +X1361(package,)X +X1670(as)X +X1762(authored)X +X2072(by)X +X2169(me,)X +X1 f +X2304(Ozan)X +X2495(S.)X +X2580(Yigit,)X +X2 f +X2785(is)X +X2858(hereby)X +X3097(placed)X +X3331(in)X +X3413(the)X +X3531(public)X +X3751(domain.)X +X1 f +X555 5072(As)N +X670(such,)X +X863(the)X +X987(author)X +X1218(is)X +X1297(not)X +X1425(responsible)X +X1816(for)X +X1936(the)X +X2060(consequences)X +X2528(of)X +X2621(use)X +X2754(of)X +X2847(this)X +X2988(software,)X +X3310(no)X +X3415(matter)X +X3645(how)X +X3808(awful,)X +X555 5168(even)N +X727(if)X +X796(they)X +X954(arise)X +X1126(from)X +X1302(defects)X +X1550(in)X +X1632(it.)X +X1716(There)X +X1924(is)X +X1997(no)X +X2097(expressed)X +X2434(or)X +X2521(implied)X +X2785(warranty)X +X3091(for)X +X3205(the)X +X2 f +X3323(sdbm)X +X1 f +X3512(library.)X +X8 s +X10 f +X555 5316(hhhhhhhhhhhhhhhhhh)N +X6 s +X1 f +X635 5391(1)N +X8 s +X691 5410(UN*X)N +X877(is)X +X936(not)X +X1034(a)X +X1078(trademark)X +X1352(of)X +X1421(any)X +X1529(\(dis\)organization.)X +X6 s +X635 5485(2)N +X8 s +X691 5504(Torek's)N +X908(discussion)X +X1194([Tor87])X +X1411(indicates)X +X1657(that)X +X2 f +X1772(dbm/ndbm)X +X1 f +X2061(implementations)X +X2506(use)X +X2609(the)X +X2705(hash)X +X2840(value)X +X2996(to)X +X3064(traverse)X +X3283(the)X +X3379(radix)X +X3528(trie)X +X3631(dif-)X +X555 5584(ferently)N +X772(than)X +X2 f +X901(sdbm)X +X1 f +X1055(and)X +X1166(as)X +X1238(a)X +X1285(result,)X +X1462(the)X +X1559(page)X +X1698(indexes)X +X1912(are)X +X2008(generated)X +X2274(in)X +X2 f +X2343(different)X +X1 f +X2579(order.)X +X2764(For)X +X2872(more)X +X3021(information,)X +X3357(send)X +X3492(e-mail)X +X3673(to)X +X555 5664(the)N +X649(author.)X +X +X2 p +X%%Page: 2 2 +X8 s 0 xH 0 xS 1 f +X10 s +X2216 384(-)N +X2263(2)X +X2323(-)X +X755 672(Since)N +X971(the)X +X2 f +X1107(sdbm)X +X1 f +X1314(library)X +X1566(package)X +X1868(is)X +X1959(in)X +X2058(the)X +X2193(public)X +X2430(domain,)X +X2727(this)X +X2 f +X2879(original)X +X1 f +X3173(release)X +X3434(or)X +X3538(any)X +X3691(additional)X +X555 768(public-domain)N +X1045(releases)X +X1323(of)X +X1413(the)X +X1534(modi\256ed)X +X1841(original)X +X2112(cannot)X +X2348(possibly)X +X2636(\(by)X +X2765(de\256nition\))X +X3120(be)X +X3218(withheld)X +X3520(from)X +X3698(you.)X +X3860(Also)X +X555 864(by)N +X659(de\256nition,)X +X1009(You)X +X1170(\(singular\))X +X1505(have)X +X1680(all)X +X1783(the)X +X1904(rights)X +X2109(to)X +X2194(this)X +X2332(code)X +X2507(\(including)X +X2859(the)X +X2980(right)X +X3154(to)X +X3239(sell)X +X3373(without)X +X3640(permission,)X +X555 960(the)N +X679(right)X +X856(to)X +X944(hoard)X +X8 s +X1127 935(3)N +X10 s +X1185 960(and)N +X1327(the)X +X1451(right)X +X1628(to)X +X1716(do)X +X1821(other)X +X2011(icky)X +X2174(things)X +X2394(as)X +X2486(you)X +X2631(see)X +X2759(\256t\))X +X2877(but)X +X3004(those)X +X3198(rights)X +X3405(are)X +X3529(also)X +X3683(granted)X +X3949(to)X +X555 1056(everyone)N +X870(else.)X +X755 1180(Please)N +X997(note)X +X1172(that)X +X1329(all)X +X1446(previous)X +X1759(distributions)X +X2195(of)X +X2298(this)X +X2449(software)X +X2762(contained)X +X3110(a)X +X3182(copyright)X +X3525(\(which)X +X3784(is)X +X3873(now)X +X555 1276(dropped\))N +X868(to)X +X953(protect)X +X1199(its)X +X1297(origins)X +X1542(and)X +X1681(its)X +X1779(current)X +X2030(public)X +X2253(domain)X +X2516(status)X +X2721(against)X +X2970(any)X +X3108(possible)X +X3392(claims)X +X3623(and/or)X +X3850(chal-)X +X555 1372(lenges.)N +X3 f +X555 1564(Acknowledgments)N +X1 f +X755 1688(Many)N +X966(people)X +X1204(have)X +X1380(been)X +X1556(very)X +X1723(helpful)X +X1974(and)X +X2114(supportive.)X +X2515(A)X +X2596(partial)X +X2824(list)X +X2944(would)X +X3167(necessarily)X +X3547(include)X +X3806(Rayan)X +X555 1784(Zacherissen)N +X963(\(who)X +X1152(contributed)X +X1541(the)X +X1663(man)X +X1824(page,)X +X2019(and)X +X2158(also)X +X2310(hacked)X +X2561(a)X +X2620(MMAP)X +X2887(version)X +X3146(of)X +X2 f +X3236(sdbm)X +X1 f +X3405(\),)X +X3475(Arnold)X +X3725(Robbins,)X +X555 1880(Chris)N +X763(Lewis,)X +X1013(Bill)X +X1166(Davidsen,)X +X1523(Henry)X +X1758(Spencer,)X +X2071(Geoff)X +X2293(Collyer,)X +X2587(Rich)X +X2772(Salz)X +X2944(\(who)X +X3143(got)X +X3279(me)X +X3411(started)X +X3659(in)X +X3755(the)X +X3887(\256rst)X +X555 1976(place\),)N +X792(Johannes)X +X1106(Ruschein)X +X1424(\(who)X +X1609(did)X +X1731(the)X +X1849(minix)X +X2055(port\))X +X2231(and)X +X2367(David)X +X2583(Tilbrook.)X +X2903(I)X +X2950(thank)X +X3148(you)X +X3288(all.)X +X3 f +X555 2168(Distribution)N +X992(Manifest)X +X1315(and)X +X1463(Notes)X +X1 f +X555 2292(This)N +X717(distribution)X +X1105(of)X +X2 f +X1192(sdbm)X +X1 f +X1381(includes)X +X1668(\(at)X +X1773(least\))X +X1967(the)X +X2085(following:)X +X7 f +X747 2436(CHANGES)N +X1323(change)X +X1659(log)X +X747 2532(README)N +X1323(this)X +X1563(file.)X +X747 2628(biblio)N +X1323(a)X +X1419(small)X +X1707(bibliography)X +X2331(on)X +X2475(external)X +X2907(hashing)X +X747 2724(dba.c)N +X1323(a)X +X1419(crude)X +X1707(\(n/s\)dbm)X +X2139(page)X +X2379(file)X +X2619(analyzer)X +X747 2820(dbd.c)N +X1323(a)X +X1419(crude)X +X1707(\(n/s\)dbm)X +X2139(page)X +X2379(file)X +X2619(dumper)X +X2955(\(for)X +X3195(conversion\))X +X747 2916(dbe.1)N +X1323(man)X +X1515(page)X +X1755(for)X +X1947(dbe.c)X +X747 3012(dbe.c)N +X1323(Janick's)X +X1755(database)X +X2187(editor)X +X747 3108(dbm.c)N +X1323(a)X +X1419(dbm)X +X1611(library)X +X1995(emulation)X +X2475(wrapper)X +X2859(for)X +X3051(ndbm/sdbm)X +X747 3204(dbm.h)N +X1323(header)X +X1659(file)X +X1899(for)X +X2091(the)X +X2283(above)X +X747 3300(dbu.c)N +X1323(a)X +X1419(crude)X +X1707(db)X +X1851(management)X +X2379(utility)X +X747 3396(hash.c)N +X1323(hashing)X +X1707(function)X +X747 3492(makefile)N +X1323(guess.)X +X747 3588(pair.c)N +X1323(page-level)X +X1851(routines)X +X2283(\(posted)X +X2667(earlier\))X +X747 3684(pair.h)N +X1323(header)X +X1659(file)X +X1899(for)X +X2091(the)X +X2283(above)X +X747 3780(readme.ms)N +X1323(troff)X +X1611(source)X +X1947(for)X +X2139(the)X +X2331(README)X +X2667(file)X +X747 3876(sdbm.3)N +X1323(man)X +X1515(page)X +X747 3972(sdbm.c)N +X1323(the)X +X1515(real)X +X1755(thing)X +X747 4068(sdbm.h)N +X1323(header)X +X1659(file)X +X1899(for)X +X2091(the)X +X2283(above)X +X747 4164(tune.h)N +X1323(place)X +X1611(for)X +X1803(tuning)X +X2139(&)X +X2235(portability)X +X2811(thingies)X +X747 4260(util.c)N +X1323(miscellaneous)X +X755 4432(dbu)N +X1 f +X924(is)X +X1002(a)X +X1063(simple)X +X1301(database)X +X1603(manipulation)X +X2050(program)X +X8 s +X2322 4407(4)N +X10 s +X2379 4432(that)N +X2524(tries)X +X2687(to)X +X2774(look)X +X2941(like)X +X3086(Bell)X +X3244(Labs')X +X7 f +X3480(cbt)X +X1 f +X3649(utility.)X +X3884(It)X +X3958(is)X +X555 4528(currently)N +X867(incomplete)X +X1245(in)X +X1329(functionality.)X +X1800(I)X +X1849(use)X +X7 f +X2006(dbu)X +X1 f +X2172(to)X +X2255(test)X +X2387(out)X +X2510(the)X +X2629(routines:)X +X2930(it)X +X2995(takes)X +X3181(\(from)X +X3385(stdin\))X +X3588(tab)X +X3707(separated)X +X555 4624(key/value)N +X898(pairs)X +X1085(for)X +X1210(commands)X +X1587(like)X +X7 f +X1765(build)X +X1 f +X2035(or)X +X7 f +X2160(insert)X +X1 f +X2478(or)X +X2575(takes)X +X2770(keys)X +X2947(for)X +X3071(commands)X +X3448(like)X +X7 f +X3626(delete)X +X1 f +X3944(or)X +X7 f +X555 4720(look)N +X1 f +X(.)S +X7 f +X747 4864(dbu)N +X939(<build|creat|look|insert|cat|delete>)X +X2715(dbmfile)X +X755 5036(dba)N +X1 f +X927(is)X +X1008(a)X +X1072(crude)X +X1279(analyzer)X +X1580(of)X +X2 f +X1675(dbm/sdbm/ndbm)X +X1 f +X2232(page)X +X2412(\256les.)X +X2593(It)X +X2670(scans)X +X2872(the)X +X2998(entire)X +X3209(page)X +X3389(\256le,)X +X3538(reporting)X +X3859(page)X +X555 5132(level)N +X731(statistics,)X +X1046(and)X +X1182(totals)X +X1375(at)X +X1453(the)X +X1571(end.)X +X7 f +X755 5256(dbd)N +X1 f +X925(is)X +X1004(a)X +X1066(crude)X +X1271(dump)X +X1479(program)X +X1777(for)X +X2 f +X1897(dbm/ndbm/sdbm)X +X1 f +X2452(databases.)X +X2806(It)X +X2881(ignores)X +X3143(the)X +X3267(bitmap,)X +X3534(and)X +X3675(dumps)X +X3913(the)X +X555 5352(data)N +X717(pages)X +X928(in)X +X1018(sequence.)X +X1361(It)X +X1437(can)X +X1576(be)X +X1679(used)X +X1853(to)X +X1942(create)X +X2162(input)X +X2353(for)X +X2474(the)X +X7 f +X2627(dbu)X +X1 f +X2798(utility.)X +X3055(Note)X +X3238(that)X +X7 f +X3413(dbd)X +X1 f +X3584(will)X +X3735(skip)X +X3895(any)X +X8 s +X10 f +X555 5432(hhhhhhhhhhhhhhhhhh)N +X6 s +X1 f +X635 5507(3)N +X8 s +X691 5526(You)N +X817(cannot)X +X1003(really)X +X1164(hoard)X +X1325(something)X +X1608(that)X +X1720(is)X +X1779(available)X +X2025(to)X +X2091(the)X +X2185(public)X +X2361(at)X +X2423(large,)X +X2582(but)X +X2680(try)X +X2767(if)X +X2822(it)X +X2874(makes)X +X3053(you)X +X3165(feel)X +X3276(any)X +X3384(better.)X +X6 s +X635 5601(4)N +X8 s +X691 5620(The)N +X7 f +X829(dbd)X +X1 f +X943(,)X +X7 f +X998(dba)X +X1 f +X1112(,)X +X7 f +X1167(dbu)X +X1 f +X1298(utilities)X +X1508(are)X +X1602(quick)X +X1761(hacks)X +X1923(and)X +X2032(are)X +X2126(not)X +X2225(\256t)X +X2295(for)X +X2385(production)X +X2678(use.)X +X2795(They)X +X2942(were)X +X3081(developed)X +X3359(late)X +X3467(one)X +X3575(night,)X +X555 5700(just)N +X664(to)X +X730(test)X +X835(out)X +X2 f +X933(sdbm)X +X1 f +X1068(,)X +X1100(and)X +X1208(convert)X +X1415(some)X +X1566(databases.)X +X +X3 p +X%%Page: 3 3 +X8 s 0 xH 0 xS 1 f +X10 s +X2216 384(-)N +X2263(3)X +X2323(-)X +X555 672(NULLs)N +X821(in)X +X903(the)X +X1021(key)X +X1157(and)X +X1293(data)X +X1447(\256elds,)X +X1660(thus)X +X1813(is)X +X1886(unsuitable)X +X2235(to)X +X2317(convert)X +X2578(some)X +X2767(peculiar)X +X3046(databases)X +X3374(that)X +X3514(insist)X +X3702(in)X +X3784(includ-)X +X555 768(ing)N +X677(the)X +X795(terminating)X +X1184(null.)X +X755 892(I)N +X841(have)X +X1052(also)X +X1240(included)X +X1575(a)X +X1670(copy)X +X1885(of)X +X2011(the)X +X7 f +X2195(dbe)X +X1 f +X2397(\()X +X2 f +X2424(ndbm)X +X1 f +X2660(DataBase)X +X3026(Editor\))X +X3311(by)X +X3449(Janick)X +X3712(Bergeron)X +X555 988([janick@bnr.ca])N +X1098(for)X +X1212(your)X +X1379(pleasure.)X +X1687(You)X +X1845(may)X +X2003(\256nd)X +X2147(it)X +X2211(more)X +X2396(useful)X +X2612(than)X +X2770(the)X +X2888(little)X +X7 f +X3082(dbu)X +X1 f +X3246(utility.)X +X7 f +X755 1112(dbm.[ch])N +X1 f +X1169(is)X +X1252(a)X +X2 f +X1318(dbm)X +X1 f +X1486(library)X +X1730(emulation)X +X2079(on)X +X2188(top)X +X2319(of)X +X2 f +X2415(ndbm)X +X1 f +X2622(\(and)X +X2794(hence)X +X3011(suitable)X +X3289(for)X +X2 f +X3412(sdbm)X +X1 f +X3581(\).)X +X3657(Written)X +X3931(by)X +X555 1208(Robert)N +X793(Elz.)X +X755 1332(The)N +X2 f +X901(sdbm)X +X1 f +X1090(library)X +X1324(has)X +X1451(been)X +X1623(around)X +X1866(in)X +X1948(beta)X +X2102(test)X +X2233(for)X +X2347(quite)X +X2527(a)X +X2583(long)X +X2745(time,)X +X2927(and)X +X3063(from)X +X3239(whatever)X +X3554(little)X +X3720(feedback)X +X555 1428(I)N +X609(received)X +X909(\(maybe)X +X1177(no)X +X1284(news)X +X1476(is)X +X1555(good)X +X1741(news\),)X +X1979(I)X +X2032(believe)X +X2290(it)X +X2360(has)X +X2493(been)X +X2671(functioning)X +X3066(without)X +X3336(any)X +X3478(signi\256cant)X +X3837(prob-)X +X555 1524(lems.)N +X752(I)X +X805(would,)X +X1051(of)X +X1144(course,)X +X1400(appreciate)X +X1757(all)X +X1863(\256xes)X +X2040(and/or)X +X2271(improvements.)X +X2774(Portability)X +X3136(enhancements)X +X3616(would)X +X3841(espe-)X +X555 1620(cially)N +X753(be)X +X849(useful.)X +X3 f +X555 1812(Implementation)N +X1122(Issues)X +X1 f +X755 1936(Hash)N +X944(functions:)X +X1288(The)X +X1437(algorithm)X +X1772(behind)X +X2 f +X2014(sdbm)X +X1 f +X2207(implementation)X +X2733(needs)X +X2939(a)X +X2998(good)X +X3181(bit-scrambling)X +X3671(hash)X +X3841(func-)X +X555 2032(tion)N +X702(to)X +X787(be)X +X886(effective.)X +X1211(I)X +X1261(ran)X +X1387(into)X +X1534(a)X +X1593(set)X +X1705(of)X +X1795(constants)X +X2116(for)X +X2233(a)X +X2292(simple)X +X2528(hash)X +X2698(function)X +X2988(that)X +X3130(seem)X +X3317(to)X +X3401(help)X +X2 f +X3561(sdbm)X +X1 f +X3752(perform)X +X555 2128(better)N +X758(than)X +X2 f +X916(ndbm)X +X1 f +X1114(for)X +X1228(various)X +X1484(inputs:)X +X7 f +X747 2272(/*)N +X795 2368(*)N +X891(polynomial)X +X1419(conversion)X +X1947(ignoring)X +X2379(overflows)X +X795 2464(*)N +X891(65599)X +X1179(nice.)X +X1467(65587)X +X1755(even)X +X1995(better.)X +X795 2560(*/)N +X747 2656(long)N +X747 2752(dbm_hash\(char)N +X1419(*str,)X +X1707(int)X +X1899(len\))X +X2139({)X +X939 2848(register)N +X1371(unsigned)X +X1803(long)X +X2043(n)X +X2139(=)X +X2235(0;)X +X939 3040(while)N +X1227(\(len--\))X +X1131 3136(n)N +X1227(=)X +X1323(n)X +X1419(*)X +X1515(65599)X +X1803(+)X +X1899(*str++;)X +X939 3232(return)N +X1275(n;)X +X747 3328(})N +X1 f +X755 3500(There)N +X975(may)X +X1145(be)X +X1253(better)X +X1467(hash)X +X1645(functions)X +X1974(for)X +X2099(the)X +X2228(purposes)X +X2544(of)X +X2642(dynamic)X +X2949(hashing.)X +X3269(Try)X +X3416(your)X +X3594(favorite,)X +X3895(and)X +X555 3596(check)N +X766(the)X +X887(page\256le.)X +X1184(If)X +X1261(it)X +X1328(contains)X +X1618(too)X +X1743(many)X +X1944(pages)X +X2150(with)X +X2315(too)X +X2440(many)X +X2641(holes,)X +X2853(\(in)X +X2965(relation)X +X3233(to)X +X3318(this)X +X3456(one)X +X3595(for)X +X3712(example\))X +X555 3692(or)N +X656(if)X +X2 f +X739(sdbm)X +X1 f +X942(simply)X +X1193(stops)X +X1391(working)X +X1692(\(fails)X +X1891(after)X +X7 f +X2101(SPLTMAX)X +X1 f +X2471(attempts)X +X2776(to)X +X2872(split\))X +X3070(when)X +X3278(you)X +X3432(feed)X +X3604(your)X +X3784(NEWS)X +X7 f +X555 3788(history)N +X1 f +X912(\256le)X +X1035(to)X +X1118(it,)X +X1203(you)X +X1344(probably)X +X1650(do)X +X1751(not)X +X1874(have)X +X2047(a)X +X2104(good)X +X2285(hashing)X +X2555(function.)X +X2883(If)X +X2958(you)X +X3099(do)X +X3200(better)X +X3404(\(for)X +X3545(different)X +X3842(types)X +X555 3884(of)N +X642(input\),)X +X873(I)X +X920(would)X +X1140(like)X +X1280(to)X +X1362(know)X +X1560(about)X +X1758(the)X +X1876(function)X +X2163(you)X +X2303(use.)X +X755 4008(Block)N +X967(sizes:)X +X1166(It)X +X1236(seems)X +X1453(\(from)X +X1657(various)X +X1914(tests)X +X2077(on)X +X2178(a)X +X2235(few)X +X2377(machines\))X +X2727(that)X +X2867(a)X +X2923(page)X +X3095(\256le)X +X3217(block)X +X3415(size)X +X7 f +X3588(PBLKSIZ)X +X1 f +X3944(of)X +X555 4104(1024)N +X738(is)X +X814(by)X +X917(far)X +X1030(the)X +X1150(best)X +X1301(for)X +X1417(performance,)X +X1866(but)X +X1990(this)X +X2127(also)X +X2278(happens)X +X2563(to)X +X2647(limit)X +X2819(the)X +X2939(size)X +X3086(of)X +X3175(a)X +X3233(key/value)X +X3567(pair.)X +X3734(Depend-)X +X555 4200(ing)N +X681(on)X +X785(your)X +X956(needs,)X +X1183(you)X +X1327(may)X +X1489(wish)X +X1663(to)X +X1748(increase)X +X2035(the)X +X2156(page)X +X2331(size,)X +X2499(and)X +X2638(also)X +X2790(adjust)X +X7 f +X3032(PAIRMAX)X +X1 f +X3391(\(the)X +X3539(maximum)X +X3886(size)X +X555 4296(of)N +X648(a)X +X710(key/value)X +X1048(pair)X +X1199(allowed:)X +X1501(should)X +X1740(always)X +X1989(be)X +X2090(at)X +X2173(least)X +X2345(three)X +X2531(words)X +X2752(smaller)X +X3013(than)X +X7 f +X3204(PBLKSIZ)X +X1 f +X(.\))S +X3612(accordingly.)X +X555 4392(The)N +X706(system-wide)X +X1137(version)X +X1399(of)X +X1492(the)X +X1616(library)X +X1856(should)X +X2095(probably)X +X2406(be)X +X2508(con\256gured)X +X2877(with)X +X3044(1024)X +X3229(\(distribution)X +X3649(default\),)X +X3944(as)X +X555 4488(this)N +X690(appears)X +X956(to)X +X1038(be)X +X1134(suf\256cient)X +X1452(for)X +X1566(most)X +X1741(common)X +X2041(uses)X +X2199(of)X +X2 f +X2286(sdbm)X +X1 f +X2455(.)X +X3 f +X555 4680(Portability)N +X1 f +X755 4804(This)N +X917(package)X +X1201(has)X +X1328(been)X +X1500(tested)X +X1707(in)X +X1789(many)X +X1987(different)X +X2284(UN*Xes)X +X2585(even)X +X2757(including)X +X3079(minix,)X +X3305(and)X +X3441(appears)X +X3707(to)X +X3789(be)X +X3885(rea-)X +X555 4900(sonably)N +X824(portable.)X +X1127(This)X +X1289(does)X +X1456(not)X +X1578(mean)X +X1772(it)X +X1836(will)X +X1980(port)X +X2129(easily)X +X2336(to)X +X2418(non-UN*X)X +X2799(systems.)X +X3 f +X555 5092(Notes)N +X767(and)X +X915(Miscellaneous)X +X1 f +X755 5216(The)N +X2 f +X913(sdbm)X +X1 f +X1115(is)X +X1201(not)X +X1336(a)X +X1405(very)X +X1581(complicated)X +X2006(package,)X +X2323(at)X +X2414(least)X +X2594(not)X +X2729(after)X +X2910(you)X +X3063(familiarize)X +X3444(yourself)X +X3739(with)X +X3913(the)X +X555 5312(literature)N +X879(on)X +X993(external)X +X1286(hashing.)X +X1589(There)X +X1811(are)X +X1944(other)X +X2143(interesting)X +X2514(algorithms)X +X2889(in)X +X2984(existence)X +X3316(that)X +X3469(ensure)X +X3712(\(approxi-)X +X555 5408(mately\))N +X825(single-read)X +X1207(access)X +X1438(to)X +X1525(a)X +X1586(data)X +X1745(value)X +X1944(associated)X +X2299(with)X +X2466(any)X +X2607(key.)X +X2768(These)X +X2984(are)X +X3107(directory-less)X +X3568(schemes)X +X3864(such)X +X555 5504(as)N +X2 f +X644(linear)X +X857(hashing)X +X1 f +X1132([Lit80])X +X1381(\(+)X +X1475(Larson)X +X1720(variations\),)X +X2 f +X2105(spiral)X +X2313(storage)X +X1 f +X2575([Mar79])X +X2865(or)X +X2954(directory)X +X3265(schemes)X +X3558(such)X +X3726(as)X +X2 f +X3814(exten-)X +X555 5600(sible)N +X731(hashing)X +X1 f +X1009([Fag79])X +X1288(by)X +X1393(Fagin)X +X1600(et)X +X1683(al.)X +X1786(I)X +X1838(do)X +X1943(hope)X +X2124(these)X +X2314(sources)X +X2579(provide)X +X2848(a)X +X2908(reasonable)X +X3276(playground)X +X3665(for)X +X3783(experi-)X +X555 5696(mentation)N +X907(with)X +X1081(other)X +X1277(algorithms.)X +X1690(See)X +X1837(the)X +X1966(June)X +X2144(1988)X +X2335(issue)X +X2526(of)X +X2624(ACM)X +X2837(Computing)X +X3227(Surveys)X +X3516([Enb88])X +X3810(for)X +X3935(an)X +X555 5792(excellent)N +X865(overview)X +X1184(of)X +X1271(the)X +X1389(\256eld.)X +X +X4 p +X%%Page: 4 4 +X10 s 0 xH 0 xS 1 f +X2216 384(-)N +X2263(4)X +X2323(-)X +X3 f +X555 672(References)N +X1 f +X555 824([Lar78])N +X875(P.-A.)X +X1064(Larson,)X +X1327(``Dynamic)X +X1695(Hashing'',)X +X2 f +X2056(BIT)X +X1 f +X(,)S +X2216(vol.)X +X2378(18,)X +X2518(pp.)X +X2638(184-201,)X +X2945(1978.)X +X555 948([Tho90])N +X875(Ken)X +X1029(Thompson,)X +X2 f +X1411(private)X +X1658(communication)X +X1 f +X2152(,)X +X2192(Nov.)X +X2370(1990)X +X555 1072([Lit80])N +X875(W.)X +X992(Litwin,)X +X1246(``)X +X1321(Linear)X +X1552(Hashing:)X +X1862(A)X +X1941(new)X +X2096(tool)X +X2261(for)X +X2396(\256le)X +X2539(and)X +X2675(table)X +X2851(addressing'',)X +X2 f +X3288(Proceedings)X +X3709(of)X +X3791(the)X +X3909(6th)X +X875 1168(Conference)N +X1269(on)X +X1373(Very)X +X1548(Large)X +X1782(Dabatases)X +X2163(\(Montreal\))X +X1 f +X2515(,)X +X2558(pp.)X +X2701(212-223,)X +X3031(Very)X +X3215(Large)X +X3426(Database)X +X3744(Founda-)X +X875 1264(tion,)N +X1039(Saratoga,)X +X1360(Calif.,)X +X1580(1980.)X +X555 1388([Fag79])N +X875(R.)X +X969(Fagin,)X +X1192(J.)X +X1284(Nievergelt,)X +X1684(N.)X +X1803(Pippinger,)X +X2175(and)X +X2332(H.)X +X2451(R.)X +X2544(Strong,)X +X2797(``Extendible)X +X3218(Hashing)X +X3505(-)X +X3552(A)X +X3630(Fast)X +X3783(Access)X +X875 1484(Method)N +X1144(for)X +X1258(Dynamic)X +X1572(Files'',)X +X2 f +X1821(ACM)X +X2010(Trans.)X +X2236(Database)X +X2563(Syst.)X +X1 f +X2712(,)X +X2752(vol.)X +X2894(4,)X +X2994(no.3,)X +X3174(pp.)X +X3294(315-344,)X +X3601(Sept.)X +X3783(1979.)X +X555 1608([Wal84])N +X875(Rich)X +X1055(Wales,)X +X1305(``Discussion)X +X1739(of)X +X1835("dbm")X +X2072(data)X +X2235(base)X +X2406(system'',)X +X2 f +X2730(USENET)X +X3051(newsgroup)X +X3430(unix.wizards)X +X1 f +X3836(,)X +X3884(Jan.)X +X875 1704(1984.)N +X555 1828([Tor87])N +X875(Chris)X +X1068(Torek,)X +X1300(``Re:)X +X1505(dbm.a)X +X1743(and)X +X1899(ndbm.a)X +X2177(archives'',)X +X2 f +X2539(USENET)X +X2852(newsgroup)X +X3223(comp.unix)X +X1 f +X3555(,)X +X3595(1987.)X +X555 1952([Mar79])N +X875(G.)X +X974(N.)X +X1073(Martin,)X +X1332(``Spiral)X +X1598(Storage:)X +X1885(Incrementally)X +X2371(Augmentable)X +X2843(Hash)X +X3048(Addressed)X +X3427(Storage'',)X +X2 f +X3766(Techni-)X +X875 2048(cal)N +X993(Report)X +X1231(#27)X +X1 f +X(,)S +X1391(University)X +X1749(of)X +X1836(Varwick,)X +X2153(Coventry,)X +X2491(U.K.,)X +X2687(1979.)X +X555 2172([Enb88])N +X875(R.)X +X977(J.)X +X1057(Enbody)X +X1335(and)X +X1480(H.)X +X1586(C.)X +X1687(Du,)X +X1833(``Dynamic)X +X2209(Hashing)X +X2524(Schemes'',)X +X2 f +X2883(ACM)X +X3080(Computing)X +X3463(Surveys)X +X1 f +X3713(,)X +X3761(vol.)X +X3911(20,)X +X875 2268(no.)N +X995(2,)X +X1075(pp.)X +X1195(85-113,)X +X1462(June)X +X1629(1988.)X +X +X4 p +X%%Trailer +Xxt +X +Xxs +END_OF_FILE +if test 33302 -ne `wc -c <'readme.ps'`; then + echo shar: \"'readme.ps'\" unpacked with wrong size! +fi +# end of 'readme.ps' +fi +if test -f 'sdbm.3' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'sdbm.3'\" +else +echo shar: Extracting \"'sdbm.3'\" \(8952 characters\) +sed "s/^X//" >'sdbm.3' <<'END_OF_FILE' +X.\" $Id: sdbm.3,v 1.2 90/12/13 13:00:57 oz Exp $ +X.TH SDBM 3 "1 March 1990" +X.SH NAME +Xsdbm, dbm_open, dbm_prep, dbm_close, dbm_fetch, dbm_store, dbm_delete, dbm_firstkey, dbm_nextkey, dbm_hash, dbm_rdonly, dbm_error, dbm_clearerr, dbm_dirfno, dbm_pagfno \- data base subroutines +X.SH SYNOPSIS +X.nf +X.ft B +X#include <sdbm.h> +X.sp +Xtypedef struct { +X char *dptr; +X int dsize; +X} datum; +X.sp +Xdatum nullitem = { NULL, 0 }; +X.sp +X\s-1DBM\s0 *dbm_open(char *file, int flags, int mode) +X.sp +X\s-1DBM\s0 *dbm_prep(char *dirname, char *pagname, int flags, int mode) +X.sp +Xvoid dbm_close(\s-1DBM\s0 *db) +X.sp +Xdatum dbm_fetch(\s-1DBM\s0 *db, key) +X.sp +Xint dbm_store(\s-1DBM\s0 *db, datum key, datum val, int flags) +X.sp +Xint dbm_delete(\s-1DBM\s0 *db, datum key) +X.sp +Xdatum dbm_firstkey(\s-1DBM\s0 *db) +X.sp +Xdatum dbm_nextkey(\s-1DBM\s0 *db) +X.sp +Xlong dbm_hash(char *string, int len) +X.sp +Xint dbm_rdonly(\s-1DBM\s0 *db) +Xint dbm_error(\s-1DBM\s0 *db) +Xdbm_clearerr(\s-1DBM\s0 *db) +Xint dbm_dirfno(\s-1DBM\s0 *db) +Xint dbm_pagfno(\s-1DBM\s0 *db) +X.ft R +X.fi +X.SH DESCRIPTION +X.IX "database library" sdbm "" "\fLsdbm\fR" +X.IX dbm_open "" "\fLdbm_open\fR \(em open \fLsdbm\fR database" +X.IX dbm_prep "" "\fLdbm_prep\fR \(em prepare \fLsdbm\fR database" +X.IX dbm_close "" "\fLdbm_close\fR \(em close \fLsdbm\fR routine" +X.IX dbm_fetch "" "\fLdbm_fetch\fR \(em fetch \fLsdbm\fR database data" +X.IX dbm_store "" "\fLdbm_store\fR \(em add data to \fLsdbm\fR database" +X.IX dbm_delete "" "\fLdbm_delete\fR \(em remove data from \fLsdbm\fR database" +X.IX dbm_firstkey "" "\fLdbm_firstkey\fR \(em access \fLsdbm\fR database" +X.IX dbm_nextkey "" "\fLdbm_nextkey\fR \(em access \fLsdbm\fR database" +X.IX dbm_hash "" "\fLdbm_hash\fR \(em string hash for \fLsdbm\fR database" +X.IX dbm_rdonly "" "\fLdbm_rdonly\fR \(em return \fLsdbm\fR database read-only mode" +X.IX dbm_error "" "\fLdbm_error\fR \(em return \fLsdbm\fR database error condition" +X.IX dbm_clearerr "" "\fLdbm_clearerr\fR \(em clear \fLsdbm\fR database error condition" +X.IX dbm_dirfno "" "\fLdbm_dirfno\fR \(em return \fLsdbm\fR database bitmap file descriptor" +X.IX dbm_pagfno "" "\fLdbm_pagfno\fR \(em return \fLsdbm\fR database data file descriptor" +X.IX "database functions \(em \fLsdbm\fR" dbm_open "" \fLdbm_open\fP +X.IX "database functions \(em \fLsdbm\fR" dbm_prep "" \fLdbm_prep\fP +X.IX "database functions \(em \fLsdbm\fR" dbm_close "" \fLdbm_close\fP +X.IX "database functions \(em \fLsdbm\fR" dbm_fetch "" \fLdbm_fetch\fP +X.IX "database functions \(em \fLsdbm\fR" dbm_store "" \fLdbm_store\fP +X.IX "database functions \(em \fLsdbm\fR" dbm_delete "" \fLdbm_delete\fP +X.IX "database functions \(em \fLsdbm\fR" dbm_firstkey "" \fLdbm_firstkey\fP +X.IX "database functions \(em \fLsdbm\fR" dbm_nextkey "" \fLdbm_nextkey\fP +X.IX "database functions \(em \fLsdbm\fR" dbm_rdonly "" \fLdbm_rdonly\fP +X.IX "database functions \(em \fLsdbm\fR" dbm_error "" \fLdbm_error\fP +X.IX "database functions \(em \fLsdbm\fR" dbm_clearerr "" \fLdbm_clearerr\fP +X.IX "database functions \(em \fLsdbm\fR" dbm_dirfno "" \fLdbm_dirfno\fP +X.IX "database functions \(em \fLsdbm\fR" dbm_pagfno "" \fLdbm_pagfno\fP +X.LP +XThis package allows an application to maintain a mapping of <key,value> pairs +Xin disk files. This is not to be considered a real database system, but is +Xstill useful in many simple applications built around fast retrieval of a data +Xvalue from a key. This implementation uses an external hashing scheme, +Xcalled Dynamic Hashing, as described by Per-Aake Larson in BIT 18 (1978) pp. +X184-201. Retrieval of any item usually requires a single disk access. +XThe application interface is compatible with the +X.IR ndbm (3) +Xlibrary. +X.LP +XAn +X.B sdbm +Xdatabase is kept in two files usually given the extensions +X.B \.dir +Xand +X.BR \.pag . +XThe +X.B \.dir +Xfile contains a bitmap representing a forest of binary hash trees, the leaves +Xof which indicate data pages in the +X.B \.pag +Xfile. +X.LP +XThe application interface uses the +X.B datum +Xstructure to describe both +X.I keys +Xand +X.IR value s. +XA +X.B datum +Xspecifies a byte sequence of +X.I dsize +Xsize pointed to by +X.IR dptr . +XIf you use +X.SM ASCII +Xstrings as +X.IR key s +Xor +X.IR value s, +Xthen you must decide whether or not to include the terminating +X.SM NUL +Xbyte which sometimes defines strings. Including it will require larger +Xdatabase files, but it will be possible to get sensible output from a +X.IR strings (1) +Xcommand applied to the data file. +X.LP +XIn order to allow a process using this package to manipulate multiple +Xdatabases, the applications interface always requires a +X.IR handle , +Xa +X.BR "DBM *" , +Xto identify the database to be manipulated. Such a handle can be obtained +Xfrom the only routines that do not require it, namely +X.BR dbm_open (\|) +Xor +X.BR dbm_prep (\|). +XEither of these will open or create the two necessary files. The +Xdifference is that the latter allows explicitly naming the bitmap and data +Xfiles whereas +X.BR dbm_open (\|) +Xwill take a base file name and call +X.BR dbm_prep (\|) +Xwith the default extensions. +XThe +X.I flags +Xand +X.I mode +Xparameters are the same as for +X.BR open (2). +X.LP +XTo free the resources occupied while a database handle is active, call +X.BR dbm_close (\|). +X.LP +XGiven a handle, one can retrieve data associated with a key by using the +X.BR dbm_fetch (\|) +Xroutine, and associate data with a key by using the +X.BR dbm_store (\|) +Xroutine. +X.LP +XThe values of the +X.I flags +Xparameter for +X.BR dbm_store (\|) +Xcan be either +X.BR \s-1DBM_INSERT\s0 , +Xwhich will not change an existing entry with the same key, or +X.BR \s-1DBM_REPLACE\s0 , +Xwhich will replace an existing entry with the same key. +XKeys are unique within the database. +X.LP +XTo delete a key and its associated value use the +X.BR dbm_delete (\|) +Xroutine. +X.LP +XTo retrieve every key in the database, use a loop like: +X.sp +X.nf +X.ft B +Xfor (key = dbm_firstkey(db); key.dptr != NULL; key = dbm_nextkey(db)) +X ; +X.ft R +X.fi +X.LP +XThe order of retrieval is unspecified. +X.LP +XIf you determine that the performance of the database is inadequate or +Xyou notice clustering or other effects that may be due to the hashing +Xalgorithm used by this package, you can override it by supplying your +Xown +X.BR dbm_hash (\|) +Xroutine. Doing so will make the database unintelligable to any other +Xapplications that do not use your specialized hash function. +X.sp +X.LP +XThe following macros are defined in the header file: +X.IP +X.BR dbm_rdonly (\|) +Xreturns true if the database has been opened read\-only. +X.IP +X.BR dbm_error (\|) +Xreturns true if an I/O error has occurred. +X.IP +X.BR dbm_clearerr (\|) +Xallows you to clear the error flag if you think you know what the error +Xwas and insist on ignoring it. +X.IP +X.BR dbm_dirfno (\|) +Xreturns the file descriptor associated with the bitmap file. +X.IP +X.BR dbm_pagfno (\|) +Xreturns the file descriptor associated with the data file. +X.SH SEE ALSO +X.IR open (2). +X.SH DIAGNOSTICS +XFunctions that return a +X.B "DBM *" +Xhandle will use +X.SM NULL +Xto indicate an error. +XFunctions that return an +X.B int +Xwill use \-1 to indicate an error. The normal return value in that case is 0. +XFunctions that return a +X.B datum +Xwill return +X.B nullitem +Xto indicate an error. +X.LP +XAs a special case of +X.BR dbm_store (\|), +Xif it is called with the +X.B \s-1DBM_INSERT\s0 +Xflag and the key already exists in the database, the return value will be 1. +X.LP +XIn general, if a function parameter is invalid, +X.B errno +Xwill be set to +X.BR \s-1EINVAL\s0 . +XIf a write operation is requested on a read-only database, +X.B errno +Xwill be set to +X.BR \s-1ENOPERM\s0 . +XIf a memory allocation (using +X.IR malloc (3)) +Xfailed, +X.B errno +Xwill be set to +X.BR \s-1ENOMEM\s0 . +XFor I/O operation failures +X.B errno +Xwill contain the value set by the relevant failed system call, either +X.IR read (2), +X.IR write (2), +Xor +X.IR lseek (2). +X.SH AUTHOR +X.IP "Ozan S. Yigit" (oz@nexus.yorku.ca) +X.SH BUGS +XThe sum of key and value data sizes must not exceed +X.B \s-1PAIRMAX\s0 +X(1008 bytes). +X.LP +XThe sum of the key and value data sizes where several keys hash to the +Xsame value must fit within one bitmap page. +X.LP +XThe +X.B \.pag +Xfile will contain holes, so its apparent size is larger than its contents. +XWhen copied through the filesystem the holes will be filled. +X.LP +XThe contents of +X.B datum +Xvalues returned are in volatile storage. If you want to retain the values +Xpointed to, you must copy them immediately before another call to this package. +X.LP +XThe only safe way for multiple processes to (read and) update a database at +Xthe same time, is to implement a private locking scheme outside this package +Xand open and close the database between lock acquisitions. It is safe for +Xmultiple processes to concurrently access a database read-only. +X.SH APPLICATIONS PORTABILITY +XFor complete source code compatibility with the Berkeley Unix +X.IR ndbm (3) +Xlibrary, the +X.B sdbm.h +Xheader file should be installed in +X.BR /usr/include/ndbm.h . +X.LP +XThe +X.B nullitem +Xdata item, and the +X.BR dbm_prep (\|), +X.BR dbm_hash (\|), +X.BR dbm_rdonly (\|), +X.BR dbm_dirfno (\|), +Xand +X.BR dbm_pagfno (\|) +Xfunctions are unique to this package. +END_OF_FILE +if test 8952 -ne `wc -c <'sdbm.3'`; then + echo shar: \"'sdbm.3'\" unpacked with wrong size! +fi +# end of 'sdbm.3' +fi +if test -f 'sdbm.c' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'sdbm.c'\" +else +echo shar: Extracting \"'sdbm.c'\" \(11029 characters\) +sed "s/^X//" >'sdbm.c' <<'END_OF_FILE' +X/* +X * sdbm - ndbm work-alike hashed database library +X * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978). +X * author: oz@nexus.yorku.ca +X * status: public domain. +X * +X * core routines +X */ +X +X#ifndef lint +Xstatic char rcsid[] = "$Id: sdbm.c,v 1.16 90/12/13 13:01:31 oz Exp $"; +X#endif +X +X#include "sdbm.h" +X#include "tune.h" +X#include "pair.h" +X +X#include <sys/types.h> +X#include <sys/stat.h> +X#ifdef BSD42 +X#include <sys/file.h> +X#else +X#include <fcntl.h> +X#include <memory.h> +X#endif +X#include <errno.h> +X#include <string.h> +X +X#ifdef __STDC__ +X#include <stddef.h> +X#endif +X +X#ifndef NULL +X#define NULL 0 +X#endif +X +X/* +X * externals +X */ +X#ifndef sun +Xextern int errno; +X#endif +X +Xextern char *malloc proto((unsigned int)); +Xextern void free proto((void *)); +Xextern long lseek(); +X +X/* +X * forward +X */ +Xstatic int getdbit proto((DBM *, long)); +Xstatic int setdbit proto((DBM *, long)); +Xstatic int getpage proto((DBM *, long)); +Xstatic datum getnext proto((DBM *)); +Xstatic int makroom proto((DBM *, long, int)); +X +X/* +X * useful macros +X */ +X#define bad(x) ((x).dptr == NULL || (x).dsize <= 0) +X#define exhash(item) dbm_hash((item).dptr, (item).dsize) +X#define ioerr(db) ((db)->flags |= DBM_IOERR) +X +X#define OFF_PAG(off) (long) (off) * PBLKSIZ +X#define OFF_DIR(off) (long) (off) * DBLKSIZ +X +Xstatic long masks[] = { +X 000000000000, 000000000001, 000000000003, 000000000007, +X 000000000017, 000000000037, 000000000077, 000000000177, +X 000000000377, 000000000777, 000000001777, 000000003777, +X 000000007777, 000000017777, 000000037777, 000000077777, +X 000000177777, 000000377777, 000000777777, 000001777777, +X 000003777777, 000007777777, 000017777777, 000037777777, +X 000077777777, 000177777777, 000377777777, 000777777777, +X 001777777777, 003777777777, 007777777777, 017777777777 +X}; +X +Xdatum nullitem = {NULL, 0}; +X +XDBM * +Xdbm_open(file, flags, mode) +Xregister char *file; +Xregister int flags; +Xregister int mode; +X{ +X register DBM *db; +X register char *dirname; +X register char *pagname; +X register int n; +X +X if (file == NULL || !*file) +X return errno = EINVAL, (DBM *) NULL; +X/* +X * need space for two seperate filenames +X */ +X n = strlen(file) * 2 + strlen(DIRFEXT) + strlen(PAGFEXT) + 2; +X +X if ((dirname = malloc((unsigned) n)) == NULL) +X return errno = ENOMEM, (DBM *) NULL; +X/* +X * build the file names +X */ +X dirname = strcat(strcpy(dirname, file), DIRFEXT); +X pagname = strcpy(dirname + strlen(dirname) + 1, file); +X pagname = strcat(pagname, PAGFEXT); +X +X db = dbm_prep(dirname, pagname, flags, mode); +X free((char *) dirname); +X return db; +X} +X +XDBM * +Xdbm_prep(dirname, pagname, flags, mode) +Xchar *dirname; +Xchar *pagname; +Xint flags; +Xint mode; +X{ +X register DBM *db; +X struct stat dstat; +X +X if ((db = (DBM *) malloc(sizeof(DBM))) == NULL) +X return errno = ENOMEM, (DBM *) NULL; +X +X db->flags = 0; +X db->hmask = 0; +X db->blkptr = 0; +X db->keyptr = 0; +X/* +X * adjust user flags so that WRONLY becomes RDWR, +X * as required by this package. Also set our internal +X * flag for RDONLY if needed. +X */ +X if (flags & O_WRONLY) +X flags = (flags & ~O_WRONLY) | O_RDWR; +X +X else if ((flags & 03) == O_RDONLY) +X db->flags = DBM_RDONLY; +X/* +X * open the files in sequence, and stat the dirfile. +X * If we fail anywhere, undo everything, return NULL. +X */ +X if ((db->pagf = open(pagname, flags, mode)) > -1) { +X if ((db->dirf = open(dirname, flags, mode)) > -1) { +X/* +X * need the dirfile size to establish max bit number. +X */ +X if (fstat(db->dirf, &dstat) == 0) { +X/* +X * zero size: either a fresh database, or one with a single, +X * unsplit data page: dirpage is all zeros. +X */ +X db->dirbno = (!dstat.st_size) ? 0 : -1; +X db->pagbno = -1; +X db->maxbno = dstat.st_size * BYTESIZ; +X +X (void) memset(db->pagbuf, 0, PBLKSIZ); +X (void) memset(db->dirbuf, 0, DBLKSIZ); +X /* +X * success +X */ +X return db; +X } +X (void) close(db->dirf); +X } +X (void) close(db->pagf); +X } +X free((char *) db); +X return (DBM *) NULL; +X} +X +Xvoid +Xdbm_close(db) +Xregister DBM *db; +X{ +X if (db == NULL) +X errno = EINVAL; +X else { +X (void) close(db->dirf); +X (void) close(db->pagf); +X free((char *) db); +X } +X} +X +Xdatum +Xdbm_fetch(db, key) +Xregister DBM *db; +Xdatum key; +X{ +X if (db == NULL || bad(key)) +X return errno = EINVAL, nullitem; +X +X if (getpage(db, exhash(key))) +X return getpair(db->pagbuf, key); +X +X return ioerr(db), nullitem; +X} +X +Xint +Xdbm_delete(db, key) +Xregister DBM *db; +Xdatum key; +X{ +X if (db == NULL || bad(key)) +X return errno = EINVAL, -1; +X if (dbm_rdonly(db)) +X return errno = EPERM, -1; +X +X if (getpage(db, exhash(key))) { +X if (!delpair(db->pagbuf, key)) +X return -1; +X/* +X * update the page file +X */ +X if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0 +X || write(db->pagf, db->pagbuf, PBLKSIZ) < 0) +X return ioerr(db), -1; +X +X return 0; +X } +X +X return ioerr(db), -1; +X} +X +Xint +Xdbm_store(db, key, val, flags) +Xregister DBM *db; +Xdatum key; +Xdatum val; +Xint flags; +X{ +X int need; +X register long hash; +X +X if (db == NULL || bad(key)) +X return errno = EINVAL, -1; +X if (dbm_rdonly(db)) +X return errno = EPERM, -1; +X +X need = key.dsize + val.dsize; +X/* +X * is the pair too big (or too small) for this database ?? +X */ +X if (need < 0 || need > PAIRMAX) +X return errno = EINVAL, -1; +X +X if (getpage(db, (hash = exhash(key)))) { +X/* +X * if we need to replace, delete the key/data pair +X * first. If it is not there, ignore. +X */ +X if (flags == DBM_REPLACE) +X (void) delpair(db->pagbuf, key); +X#ifdef SEEDUPS +X else if (duppair(db->pagbuf, key)) +X return 1; +X#endif +X/* +X * if we do not have enough room, we have to split. +X */ +X if (!fitpair(db->pagbuf, need)) +X if (!makroom(db, hash, need)) +X return ioerr(db), -1; +X/* +X * we have enough room or split is successful. insert the key, +X * and update the page file. +X */ +X (void) putpair(db->pagbuf, key, val); +X +X if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0 +X || write(db->pagf, db->pagbuf, PBLKSIZ) < 0) +X return ioerr(db), -1; +X /* +X * success +X */ +X return 0; +X } +X +X return ioerr(db), -1; +X} +X +X/* +X * makroom - make room by splitting the overfull page +X * this routine will attempt to make room for SPLTMAX times before +X * giving up. +X */ +Xstatic int +Xmakroom(db, hash, need) +Xregister DBM *db; +Xlong hash; +Xint need; +X{ +X long newp; +X char twin[PBLKSIZ]; +X char *pag = db->pagbuf; +X char *new = twin; +X register int smax = SPLTMAX; +X +X do { +X/* +X * split the current page +X */ +X (void) splpage(pag, new, db->hmask + 1); +X/* +X * address of the new page +X */ +X newp = (hash & db->hmask) | (db->hmask + 1); +X +X/* +X * write delay, read avoidence/cache shuffle: +X * select the page for incoming pair: if key is to go to the new page, +X * write out the previous one, and copy the new one over, thus making +X * it the current page. If not, simply write the new page, and we are +X * still looking at the page of interest. current page is not updated +X * here, as dbm_store will do so, after it inserts the incoming pair. +X */ +X if (hash & (db->hmask + 1)) { +X if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0 +X || write(db->pagf, db->pagbuf, PBLKSIZ) < 0) +X return 0; +X db->pagbno = newp; +X (void) memcpy(pag, new, PBLKSIZ); +X } +X else if (lseek(db->pagf, OFF_PAG(newp), SEEK_SET) < 0 +X || write(db->pagf, new, PBLKSIZ) < 0) +X return 0; +X +X if (!setdbit(db, db->curbit)) +X return 0; +X/* +X * see if we have enough room now +X */ +X if (fitpair(pag, need)) +X return 1; +X/* +X * try again... update curbit and hmask as getpage would have +X * done. because of our update of the current page, we do not +X * need to read in anything. BUT we have to write the current +X * [deferred] page out, as the window of failure is too great. +X */ +X db->curbit = 2 * db->curbit + +X ((hash & (db->hmask + 1)) ? 2 : 1); +X db->hmask |= db->hmask + 1; +X +X if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0 +X || write(db->pagf, db->pagbuf, PBLKSIZ) < 0) +X return 0; +X +X } while (--smax); +X/* +X * if we are here, this is real bad news. After SPLTMAX splits, +X * we still cannot fit the key. say goodnight. +X */ +X#ifdef BADMESS +X (void) write(2, "sdbm: cannot insert after SPLTMAX attempts.\n", 44); +X#endif +X return 0; +X +X} +X +X/* +X * the following two routines will break if +X * deletions aren't taken into account. (ndbm bug) +X */ +Xdatum +Xdbm_firstkey(db) +Xregister DBM *db; +X{ +X if (db == NULL) +X return errno = EINVAL, nullitem; +X/* +X * start at page 0 +X */ +X if (lseek(db->pagf, OFF_PAG(0), SEEK_SET) < 0 +X || read(db->pagf, db->pagbuf, PBLKSIZ) < 0) +X return ioerr(db), nullitem; +X db->pagbno = 0; +X db->blkptr = 0; +X db->keyptr = 0; +X +X return getnext(db); +X} +X +Xdatum +Xdbm_nextkey(db) +Xregister DBM *db; +X{ +X if (db == NULL) +X return errno = EINVAL, nullitem; +X return getnext(db); +X} +X +X/* +X * all important binary trie traversal +X */ +Xstatic int +Xgetpage(db, hash) +Xregister DBM *db; +Xregister long hash; +X{ +X register int hbit; +X register long dbit; +X register long pagb; +X +X dbit = 0; +X hbit = 0; +X while (dbit < db->maxbno && getdbit(db, dbit)) +X dbit = 2 * dbit + ((hash & (1 << hbit++)) ? 2 : 1); +X +X debug(("dbit: %d...", dbit)); +X +X db->curbit = dbit; +X db->hmask = masks[hbit]; +X +X pagb = hash & db->hmask; +X/* +X * see if the block we need is already in memory. +X * note: this lookaside cache has about 10% hit rate. +X */ +X if (pagb != db->pagbno) { +X/* +X * note: here, we assume a "hole" is read as 0s. +X * if not, must zero pagbuf first. +X */ +X if (lseek(db->pagf, OFF_PAG(pagb), SEEK_SET) < 0 +X || read(db->pagf, db->pagbuf, PBLKSIZ) < 0) +X return 0; +X if (!chkpage(db->pagbuf)) +X return 0; +X db->pagbno = pagb; +X +X debug(("pag read: %d\n", pagb)); +X } +X return 1; +X} +X +Xstatic int +Xgetdbit(db, dbit) +Xregister DBM *db; +Xregister long dbit; +X{ +X register long c; +X register long dirb; +X +X c = dbit / BYTESIZ; +X dirb = c / DBLKSIZ; +X +X if (dirb != db->dirbno) { +X if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0 +X || read(db->dirf, db->dirbuf, DBLKSIZ) < 0) +X return 0; +X db->dirbno = dirb; +X +X debug(("dir read: %d\n", dirb)); +X } +X +X return db->dirbuf[c % DBLKSIZ] & (1 << dbit % BYTESIZ); +X} +X +Xstatic int +Xsetdbit(db, dbit) +Xregister DBM *db; +Xregister long dbit; +X{ +X register long c; +X register long dirb; +X +X c = dbit / BYTESIZ; +X dirb = c / DBLKSIZ; +X +X if (dirb != db->dirbno) { +X if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0 +X || read(db->dirf, db->dirbuf, DBLKSIZ) < 0) +X return 0; +X db->dirbno = dirb; +X +X debug(("dir read: %d\n", dirb)); +X } +X +X db->dirbuf[c % DBLKSIZ] |= (1 << dbit % BYTESIZ); +X +X if (dbit >= db->maxbno) +X db->maxbno += DBLKSIZ * BYTESIZ; +X +X if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0 +X || write(db->dirf, db->dirbuf, DBLKSIZ) < 0) +X return 0; +X +X return 1; +X} +X +X/* +X * getnext - get the next key in the page, and if done with +X * the page, try the next page in sequence +X */ +Xstatic datum +Xgetnext(db) +Xregister DBM *db; +X{ +X datum key; +X +X for (;;) { +X db->keyptr++; +X key = getnkey(db->pagbuf, db->keyptr); +X if (key.dptr != NULL) +X return key; +X/* +X * we either run out, or there is nothing on this page.. +X * try the next one... If we lost our position on the +X * file, we will have to seek. +X */ +X db->keyptr = 0; +X if (db->pagbno != db->blkptr++) +X if (lseek(db->pagf, OFF_PAG(db->blkptr), SEEK_SET) < 0) +X break; +X db->pagbno = db->blkptr; +X if (read(db->pagf, db->pagbuf, PBLKSIZ) <= 0) +X break; +X if (!chkpage(db->pagbuf)) +X break; +X } +X +X return ioerr(db), nullitem; +X} +END_OF_FILE +if test 11029 -ne `wc -c <'sdbm.c'`; then + echo shar: \"'sdbm.c'\" unpacked with wrong size! +fi +# end of 'sdbm.c' +fi +if test -f 'sdbm.h' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'sdbm.h'\" +else +echo shar: Extracting \"'sdbm.h'\" \(2174 characters\) +sed "s/^X//" >'sdbm.h' <<'END_OF_FILE' +X/* +X * sdbm - ndbm work-alike hashed database library +X * based on Per-Ake Larson's Dynamic Hashing algorithms. BIT 18 (1978). +X * author: oz@nexus.yorku.ca +X * status: public domain. +X */ +X#define DBLKSIZ 4096 +X#define PBLKSIZ 1024 +X#define PAIRMAX 1008 /* arbitrary on PBLKSIZ-N */ +X#define SPLTMAX 10 /* maximum allowed splits */ +X /* for a single insertion */ +X#define DIRFEXT ".dir" +X#define PAGFEXT ".pag" +X +Xtypedef struct { +X int dirf; /* directory file descriptor */ +X int pagf; /* page file descriptor */ +X int flags; /* status/error flags, see below */ +X long maxbno; /* size of dirfile in bits */ +X long curbit; /* current bit number */ +X long hmask; /* current hash mask */ +X long blkptr; /* current block for nextkey */ +X int keyptr; /* current key for nextkey */ +X long blkno; /* current page to read/write */ +X long pagbno; /* current page in pagbuf */ +X char pagbuf[PBLKSIZ]; /* page file block buffer */ +X long dirbno; /* current block in dirbuf */ +X char dirbuf[DBLKSIZ]; /* directory file block buffer */ +X} DBM; +X +X#define DBM_RDONLY 0x1 /* data base open read-only */ +X#define DBM_IOERR 0x2 /* data base I/O error */ +X +X/* +X * utility macros +X */ +X#define dbm_rdonly(db) ((db)->flags & DBM_RDONLY) +X#define dbm_error(db) ((db)->flags & DBM_IOERR) +X +X#define dbm_clearerr(db) ((db)->flags &= ~DBM_IOERR) /* ouch */ +X +X#define dbm_dirfno(db) ((db)->dirf) +X#define dbm_pagfno(db) ((db)->pagf) +X +Xtypedef struct { +X char *dptr; +X int dsize; +X} datum; +X +Xextern datum nullitem; +X +X#ifdef __STDC__ +X#define proto(p) p +X#else +X#define proto(p) () +X#endif +X +X/* +X * flags to dbm_store +X */ +X#define DBM_INSERT 0 +X#define DBM_REPLACE 1 +X +X/* +X * ndbm interface +X */ +Xextern DBM *dbm_open proto((char *, int, int)); +Xextern void dbm_close proto((DBM *)); +Xextern datum dbm_fetch proto((DBM *, datum)); +Xextern int dbm_delete proto((DBM *, datum)); +Xextern int dbm_store proto((DBM *, datum, datum, int)); +Xextern datum dbm_firstkey proto((DBM *)); +Xextern datum dbm_nextkey proto((DBM *)); +X +X/* +X * other +X */ +Xextern DBM *dbm_prep proto((char *, char *, int, int)); +Xextern long dbm_hash proto((char *, int)); +END_OF_FILE +if test 2174 -ne `wc -c <'sdbm.h'`; then + echo shar: \"'sdbm.h'\" unpacked with wrong size! +fi +# end of 'sdbm.h' +fi +if test -f 'tune.h' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'tune.h'\" +else +echo shar: Extracting \"'tune.h'\" \(665 characters\) +sed "s/^X//" >'tune.h' <<'END_OF_FILE' +X/* +X * sdbm - ndbm work-alike hashed database library +X * tuning and portability constructs [not nearly enough] +X * author: oz@nexus.yorku.ca +X */ +X +X#define BYTESIZ 8 +X +X#ifdef SVID +X#include <unistd.h> +X#endif +X +X#ifdef BSD42 +X#define SEEK_SET L_SET +X#define memset(s,c,n) bzero(s, n) /* only when c is zero */ +X#define memcpy(s1,s2,n) bcopy(s2, s1, n) +X#define memcmp(s1,s2,n) bcmp(s1,s2,n) +X#endif +X +X/* +X * important tuning parms (hah) +X */ +X +X#define SEEDUPS /* always detect duplicates */ +X#define BADMESS /* generate a message for worst case: +X cannot make room after SPLTMAX splits */ +X/* +X * misc +X */ +X#ifdef DEBUG +X#define debug(x) printf x +X#else +X#define debug(x) +X#endif +END_OF_FILE +if test 665 -ne `wc -c <'tune.h'`; then + echo shar: \"'tune.h'\" unpacked with wrong size! +fi +# end of 'tune.h' +fi +if test -f 'util.c' -a "${1}" != "-c" ; then + echo shar: Will not clobber existing file \"'util.c'\" +else +echo shar: Extracting \"'util.c'\" \(767 characters\) +sed "s/^X//" >'util.c' <<'END_OF_FILE' +X#include <stdio.h> +X#ifdef SDBM +X#include "sdbm.h" +X#else +X#include "ndbm.h" +X#endif +X +Xvoid +Xoops(s1, s2) +Xregister char *s1; +Xregister char *s2; +X{ +X extern int errno, sys_nerr; +X extern char *sys_errlist[]; +X extern char *progname; +X +X if (progname) +X fprintf(stderr, "%s: ", progname); +X fprintf(stderr, s1, s2); +X if (errno > 0 && errno < sys_nerr) +X fprintf(stderr, " (%s)", sys_errlist[errno]); +X fprintf(stderr, "\n"); +X exit(1); +X} +X +Xint +Xokpage(pag) +Xchar *pag; +X{ +X register unsigned n; +X register off; +X register short *ino = (short *) pag; +X +X if ((n = ino[0]) > PBLKSIZ / sizeof(short)) +X return 0; +X +X if (!n) +X return 1; +X +X off = PBLKSIZ; +X for (ino++; n; ino += 2) { +X if (ino[0] > off || ino[1] > off || +X ino[1] > ino[0]) +X return 0; +X off = ino[1]; +X n -= 2; +X } +X +X return 1; +X} +END_OF_FILE +if test 767 -ne `wc -c <'util.c'`; then + echo shar: \"'util.c'\" unpacked with wrong size! +fi +# end of 'util.c' +fi +echo shar: End of shell archive. +exit 0 diff --git a/ext/dbm/sdbm/CHANGES b/ext/dbm/sdbm/CHANGES new file mode 100644 index 0000000000..f7296d1b3a --- /dev/null +++ b/ext/dbm/sdbm/CHANGES @@ -0,0 +1,18 @@ +Changes from the earlier BETA releases. + +o dbm_prep does everything now, so dbm_open is just a simple + wrapper that builds the default filenames. dbm_prep no longer + requires a (DBM *) db parameter: it allocates one itself. It + returns (DBM *) db or (DBM *) NULL. + +o makroom is now reliable. In the common-case optimization of the page + split, the page into which the incoming key/value pair is to be inserted + is write-deferred (if the split is successful), thereby saving a cosly + write. BUT, if the split does not make enough room (unsuccessful), the + deferred page is written out, as the failure-window is now dependent on + the number of split attempts. + +o if -DDUFF is defined, hash function will also use the DUFF construct. + This may look like a micro-performance tweak (maybe it is), but in fact, + the hash function is the third most-heavily used function, after read + and write. diff --git a/ext/dbm/sdbm/COMPARE b/ext/dbm/sdbm/COMPARE new file mode 100644 index 0000000000..a595e831d2 --- /dev/null +++ b/ext/dbm/sdbm/COMPARE @@ -0,0 +1,88 @@ + +Script started on Thu Sep 28 15:41:06 1989 +% uname -a +titan titan 4_0 UMIPS mips +% make all x-dbm + cc -O -DSDBM -DDUFF -DDUPERROR -DSPLITFAIL -c dbm.c + cc -O -DSDBM -DDUFF -DDUPERROR -DSPLITFAIL -c sdbm.c + cc -O -DSDBM -DDUFF -DDUPERROR -DSPLITFAIL -c pair.c + cc -O -DSDBM -DDUFF -DDUPERROR -DSPLITFAIL -c hash.c + ar cr libsdbm.a sdbm.o pair.o hash.o + ranlib libsdbm.a + cc -o dbm dbm.o libsdbm.a + cc -O -DSDBM -DDUFF -DDUPERROR -DSPLITFAIL -c dba.c + cc -o dba dba.o + cc -O -DSDBM -DDUFF -DDUPERROR -DSPLITFAIL -c dbd.c + cc -o dbd dbd.o + cc -O -DSDBM -DDUFF -DDUPERROR -DSPLITFAIL -o x-dbm dbm.o +% +% +% wc history + 65110 218344 3204883 history +% +% /bin/time dbm build foo <history + +real 5:56.9 +user 13.3 +sys 26.3 +% ls -s +total 14251 + 5 README 2 dbd.c 1 hash.c 1 pair.h + 0 SCRIPT 5 dbd.o 1 hash.o 5 pair.o + 1 WISHLIST 62 dbm 3130 history 1 port.h + 46 dba 5 dbm.c 11 howtodbm.txt 11 sdbm.c + 3 dba.c 8 dbm.o 14 libsdbm.a 2 sdbm.h + 6 dba.o 4 foo.dir 1 makefile 8 sdbm.o + 46 dbd 10810 foo.pag 6 pair.c 60 x-dbm +% ls -l foo.* +-rw-r--r-- 1 oz 4096 Sep 28 15:48 foo.dir +-rw-r--r-- 1 oz 11069440 Sep 28 15:48 foo.pag +% +% /bin/time x-dbm build bar <history + +real 5:59.4 +user 24.7 +sys 29.1 +% +% ls -s +total 27612 + 5 README 46 dbd 1 hash.c 5 pair.o + 1 SCRIPT 2 dbd.c 1 hash.o 1 port.h + 1 WISHLIST 5 dbd.o 3130 history 11 sdbm.c + 4 bar.dir 62 dbm 11 howtodbm.txt 2 sdbm.h +13356 bar.pag 5 dbm.c 14 libsdbm.a 8 sdbm.o + 46 dba 8 dbm.o 1 makefile 60 x-dbm + 3 dba.c 4 foo.dir 6 pair.c + 6 dba.o 10810 foo.pag 1 pair.h +% +% ls -l bar.* +-rw-r--r-- 1 oz 4096 Sep 28 15:54 bar.dir +-rw-r--r-- 1 oz 13676544 Sep 28 15:54 bar.pag +% +% dba foo | tail +#10801: ok. no entries. +#10802: ok. no entries. +#10803: ok. no entries. +#10804: ok. no entries. +#10805: ok. no entries. +#10806: ok. no entries. +#10807: ok. no entries. +#10808: ok. no entries. +#10809: ok. 11 entries 67% used free 337. +10810 pages (6036 holes): 65073 entries +% +% dba bar | tail +#13347: ok. no entries. +#13348: ok. no entries. +#13349: ok. no entries. +#13350: ok. no entries. +#13351: ok. no entries. +#13352: ok. no entries. +#13353: ok. no entries. +#13354: ok. no entries. +#13355: ok. 7 entries 33% used free 676. +13356 pages (8643 holes): 65073 entries +% +% exit +script done on Thu Sep 28 16:08:45 1989 + diff --git a/ext/dbm/sdbm/README b/ext/dbm/sdbm/README new file mode 100644 index 0000000000..cd7312cc57 --- /dev/null +++ b/ext/dbm/sdbm/README @@ -0,0 +1,396 @@ + + + + + + + sdbm - Substitute DBM + or + Berkeley ndbm for Every UN*X[1] Made Simple + + Ozan (oz) Yigit + + The Guild of PD Software Toolmakers + Toronto - Canada + + oz@nexus.yorku.ca + + + +Implementation is the sincerest form of flattery. - L. Peter +Deutsch + +A The Clone of the ndbm library + + The sources accompanying this notice - sdbm - consti- +tute the first public release (Dec. 1990) of a complete +clone of the Berkeley UN*X ndbm library. The sdbm library is +meant to clone the proven functionality of ndbm as closely +as possible, including a few improvements. It is practical, +easy to understand, and compatible. The sdbm library is not +derived from any licensed, proprietary or copyrighted +software. + + The sdbm implementation is based on a 1978 algorithm +[Lar78] by P.-A. (Paul) Larson known as ``Dynamic Hashing''. +In the course of searching for a substitute for ndbm, I pro- +totyped three different external-hashing algorithms [Lar78, +Fag79, Lit80] and ultimately chose Larson's algorithm as a +basis of the sdbm implementation. The Bell Labs dbm (and +therefore ndbm) is based on an algorithm invented by Ken +Thompson, [Tho90, Tor87] and predates Larson's work. + + The sdbm programming interface is totally compatible +with ndbm and includes a slight improvement in database ini- +tialization. It is also expected to be binary-compatible +under most UN*X versions that support the ndbm library. + + The sdbm implementation shares the shortcomings of the +ndbm library, as a side effect of various simplifications to +the original Larson algorithm. It does produce holes in the +page file as it writes pages past the end of file. (Larson's +paper include a clever solution to this problem that is a +result of using the hash value directly as a block address.) +On the other hand, extensive tests seem to indicate that +sdbm creates fewer holes in general, and the resulting page- +files are smaller. The sdbm implementation is also faster +than ndbm in database creation. Unlike the ndbm, the sdbm +_________________________ + + [1] UN*X is not a trademark of any (dis)organization. + + + + + + + + + + - 2 - + + +store operation will not ``wander away'' trying to split its +data pages to insert a datum that cannot (due to elaborate +worst-case situations) be inserted. (It will fail after a +pre-defined number of attempts.) + +Important Compatibility Warning + + The sdbm and ndbm libraries cannot share databases: one +cannot read the (dir/pag) database created by the other. +This is due to the differences between the ndbm and sdbm +algorithms[2], and the hash functions used. It is easy to +convert between the dbm/ndbm databases and sdbm by ignoring +the index completely: see dbd, dbu etc. + + +Notice of Intellectual Property + +The entire sdbm library package, as authored by me, Ozan S. +Yigit, is hereby placed in the public domain. As such, the +author is not responsible for the consequences of use of +this software, no matter how awful, even if they arise from +defects in it. There is no expressed or implied warranty for +the sdbm library. + + Since the sdbm library package is in the public domain, +this original release or any additional public-domain +releases of the modified original cannot possibly (by defin- +ition) be withheld from you. Also by definition, You (singu- +lar) have all the rights to this code (including the right +to sell without permission, the right to hoard[3] and the +right to do other icky things as you see fit) but those +rights are also granted to everyone else. + + Please note that all previous distributions of this +software contained a copyright (which is now dropped) to +protect its origins and its current public domain status +against any possible claims and/or challenges. + +Acknowledgments + + Many people have been very helpful and supportive. A +partial list would necessarily include Rayan Zacherissen +(who contributed the man page, and also hacked a MMAP +_________________________ + + [2] Torek's discussion [Tor87] indicates that +dbm/ndbm implementations use the hash value to traverse +the radix trie differently than sdbm and as a result, +the page indexes are generated in different order. For +more information, send e-mail to the author. + [3] You cannot really hoard something that is avail- +able to the public at large, but try if it makes you +feel any better. + + + + + + + + + + + - 3 - + + +version of sdbm), Arnold Robbins, Chris Lewis, Bill David- +sen, Henry Spencer, Geoff Collyer, Rich Salz (who got me +started in the first place), Johannes Ruschein (who did the +minix port) and David Tilbrook. I thank you all. + +Distribution Manifest and Notes + +This distribution of sdbm includes (at least) the following: + + CHANGES change log + README this file. + biblio a small bibliography on external hashing + dba.c a crude (n/s)dbm page file analyzer + dbd.c a crude (n/s)dbm page file dumper (for conversion) + dbe.1 man page for dbe.c + dbe.c Janick's database editor + dbm.c a dbm library emulation wrapper for ndbm/sdbm + dbm.h header file for the above + dbu.c a crude db management utility + hash.c hashing function + makefile guess. + pair.c page-level routines (posted earlier) + pair.h header file for the above + readme.ms troff source for the README file + sdbm.3 man page + sdbm.c the real thing + sdbm.h header file for the above + tune.h place for tuning & portability thingies + util.c miscellaneous + + dbu is a simple database manipulation program[4] that +tries to look like Bell Labs' cbt utility. It is currently +incomplete in functionality. I use dbu to test out the rou- +tines: it takes (from stdin) tab separated key/value pairs +for commands like build or insert or takes keys for commands +like delete or look. + + dbu <build|creat|look|insert|cat|delete> dbmfile + + dba is a crude analyzer of dbm/sdbm/ndbm page files. It +scans the entire page file, reporting page level statistics, +and totals at the end. + + dbd is a crude dump program for dbm/ndbm/sdbm data- +bases. It ignores the bitmap, and dumps the data pages in +sequence. It can be used to create input for the dbu util- +ity. Note that dbd will skip any NULLs in the key and data +fields, thus is unsuitable to convert some peculiar +_________________________ + + [4] The dbd, dba, dbu utilities are quick hacks and +are not fit for production use. They were developed +late one night, just to test out sdbm, and convert some +databases. + + + + + + + + + + - 4 - + + +databases that insist in including the terminating null. + + I have also included a copy of the dbe (ndbm DataBase +Editor) by Janick Bergeron [janick@bnr.ca] for your pleas- +ure. You may find it more useful than the little dbu util- +ity. + + dbm.[ch] is a dbm library emulation on top of ndbm (and +hence suitable for sdbm). Written by Robert Elz. + + The sdbm library has been around in beta test for quite +a long time, and from whatever little feedback I received +(maybe no news is good news), I believe it has been func- +tioning without any significant problems. I would, of +course, appreciate all fixes and/or improvements. Portabil- +ity enhancements would especially be useful. + +Implementation Issues + + Hash functions: The algorithm behind sdbm implementa- +tion needs a good bit-scrambling hash function to be effec- +tive. I ran into a set of constants for a simple hash func- +tion that seem to help sdbm perform better than ndbm for +various inputs: + + /* + * polynomial conversion ignoring overflows + * 65599 nice. 65587 even better. + */ + long + dbm_hash(char *str, int len) { + register unsigned long n = 0; + + while (len--) + n = n * 65599 + *str++; + return n; + } + + There may be better hash functions for the purposes of +dynamic hashing. Try your favorite, and check the pagefile. +If it contains too many pages with too many holes, (in rela- +tion to this one for example) or if sdbm simply stops work- +ing (fails after SPLTMAX attempts to split) when you feed +your NEWS history file to it, you probably do not have a +good hashing function. If you do better (for different +types of input), I would like to know about the function you +use. + + Block sizes: It seems (from various tests on a few +machines) that a page file block size PBLKSIZ of 1024 is by +far the best for performance, but this also happens to limit +the size of a key/value pair. Depending on your needs, you +may wish to increase the page size, and also adjust PAIRMAX +(the maximum size of a key/value pair allowed: should always + + + + + + + + + + - 5 - + + +be at least three words smaller than PBLKSIZ.) accordingly. +The system-wide version of the library should probably be +configured with 1024 (distribution default), as this appears +to be sufficient for most common uses of sdbm. + +Portability + + This package has been tested in many different UN*Xes +even including minix, and appears to be reasonably portable. +This does not mean it will port easily to non-UN*X systems. + +Notes and Miscellaneous + + The sdbm is not a very complicated package, at least +not after you familiarize yourself with the literature on +external hashing. There are other interesting algorithms in +existence that ensure (approximately) single-read access to +a data value associated with any key. These are directory- +less schemes such as linear hashing [Lit80] (+ Larson varia- +tions), spiral storage [Mar79] or directory schemes such as +extensible hashing [Fag79] by Fagin et al. I do hope these +sources provide a reasonable playground for experimentation +with other algorithms. See the June 1988 issue of ACM Com- +puting Surveys [Enb88] for an excellent overview of the +field. + +References + + +[Lar78] + P.-A. Larson, ``Dynamic Hashing'', BIT, vol. 18, pp. + 184-201, 1978. + +[Tho90] + Ken Thompson, private communication, Nov. 1990 + +[Lit80] + W. Litwin, `` Linear Hashing: A new tool for file and + table addressing'', Proceedings of the 6th Conference on + Very Large Dabatases (Montreal), pp. 212-223, Very + Large Database Foundation, Saratoga, Calif., 1980. + +[Fag79] + R. Fagin, J. Nievergelt, N. Pippinger, and H. R. + Strong, ``Extendible Hashing - A Fast Access Method for + Dynamic Files'', ACM Trans. Database Syst., vol. 4, + no.3, pp. 315-344, Sept. 1979. + +[Wal84] + Rich Wales, ``Discussion of "dbm" data base system'', + USENET newsgroup unix.wizards, Jan. 1984. + +[Tor87] + Chris Torek, ``Re: dbm.a and ndbm.a archives'', + + + + + + + + + + - 6 - + + + USENET newsgroup comp.unix, 1987. + +[Mar79] + G. N. Martin, ``Spiral Storage: Incrementally Augment- + able Hash Addressed Storage'', Technical Report #27, + University of Varwick, Coventry, U.K., 1979. + +[Enb88] + R. J. Enbody and H. C. Du, ``Dynamic Hashing + Schemes'',ACM Computing Surveys, vol. 20, no. 2, pp. + 85-113, June 1988. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ext/dbm/sdbm/README.too b/ext/dbm/sdbm/README.too new file mode 100644 index 0000000000..d60ccf0f4b --- /dev/null +++ b/ext/dbm/sdbm/README.too @@ -0,0 +1,3 @@ +This version of sdbm merely has all the dbm_* names translated to sdbm_* +so that we can link ndbm and sdbm into the same executable. (It also has +the bad() macro redefined to allow a zero-length key.) diff --git a/ext/dbm/sdbm/biblio b/ext/dbm/sdbm/biblio new file mode 100644 index 0000000000..0be09fa005 --- /dev/null +++ b/ext/dbm/sdbm/biblio @@ -0,0 +1,64 @@ +%A R. J. Enbody +%A H. C. Du +%T Dynamic Hashing Schemes +%J ACM Computing Surveys +%V 20 +%N 2 +%D June 1988 +%P 85-113 +%K surveys + +%A P.-A. Larson +%T Dynamic Hashing +%J BIT +%V 18 +%P 184-201 +%D 1978 +%K dynamic + +%A W. Litwin +%T Linear Hashing: A new tool for file and table addressing +%J Proceedings of the 6th Conference on Very Large Dabatases (Montreal) +%I Very Large Database Foundation +%C Saratoga, Calif. +%P 212-223 +%D 1980 +%K linear + +%A R. Fagin +%A J. Nievergelt +%A N. Pippinger +%A H. R. Strong +%T Extendible Hashing - A Fast Access Method for Dynamic Files +%J ACM Trans. Database Syst. +%V 4 +%N 3 +%D Sept. 1979 +%P 315-344 +%K extend + +%A G. N. Martin +%T Spiral Storage: Incrementally Augmentable Hash Addressed Storage +%J Technical Report #27 +%I University of Varwick +%C Coventry, U.K. +%D 1979 +%K spiral + +%A Chris Torek +%T Re: dbm.a and ndbm.a archives +%B USENET newsgroup comp.unix +%D 1987 +%K torek + +%A Rich Wales +%T Discusson of "dbm" data base system +%B USENET newsgroup unix.wizards +%D Jan. 1984 +%K rich + + + + + + diff --git a/ext/dbm/sdbm/dba.c b/ext/dbm/sdbm/dba.c new file mode 100644 index 0000000000..4f227e5245 --- /dev/null +++ b/ext/dbm/sdbm/dba.c @@ -0,0 +1,84 @@ +/* + * dba dbm analysis/recovery + */ + +#include <stdio.h> +#include <sys/file.h> +#include "sdbm.h" + +char *progname; +extern void oops(); + +int +main(argc, argv) +char **argv; +{ + int n; + char *p; + char *name; + int pagf; + + progname = argv[0]; + + if (p = argv[1]) { + name = (char *) malloc((n = strlen(p)) + 5); + strcpy(name, p); + strcpy(name + n, ".pag"); + + if ((pagf = open(name, O_RDONLY)) < 0) + oops("cannot open %s.", name); + + sdump(pagf); + } + else + oops("usage: %s dbname", progname); + + return 0; +} + +sdump(pagf) +int pagf; +{ + register b; + register n = 0; + register t = 0; + register o = 0; + register e; + char pag[PBLKSIZ]; + + while ((b = read(pagf, pag, PBLKSIZ)) > 0) { + printf("#%d: ", n); + if (!okpage(pag)) + printf("bad\n"); + else { + printf("ok. "); + if (!(e = pagestat(pag))) + o++; + else + t += e; + } + n++; + } + + if (b == 0) + printf("%d pages (%d holes): %d entries\n", n, o, t); + else + oops("read failed: block %d", n); +} + +pagestat(pag) +char *pag; +{ + register n; + register free; + register short *ino = (short *) pag; + + if (!(n = ino[0])) + printf("no entries.\n"); + else { + free = ino[n] - (n + 1) * sizeof(short); + printf("%3d entries %2d%% used free %d.\n", + n / 2, ((PBLKSIZ - free) * 100) / PBLKSIZ, free); + } + return n / 2; +} diff --git a/ext/dbm/sdbm/dbd.c b/ext/dbm/sdbm/dbd.c new file mode 100644 index 0000000000..697a547597 --- /dev/null +++ b/ext/dbm/sdbm/dbd.c @@ -0,0 +1,110 @@ +/* + * dbd - dump a dbm data file + */ + +#include <stdio.h> +#include <sys/file.h> +#include "sdbm.h" + +char *progname; +extern void oops(); + + +#define empty(page) (((short *) page)[0] == 0) + +int +main(argc, argv) +char **argv; +{ + int n; + char *p; + char *name; + int pagf; + + progname = argv[0]; + + if (p = argv[1]) { + name = (char *) malloc((n = strlen(p)) + 5); + strcpy(name, p); + strcpy(name + n, ".pag"); + + if ((pagf = open(name, O_RDONLY)) < 0) + oops("cannot open %s.", name); + + sdump(pagf); + } + else + oops("usage: %s dbname", progname); + return 0; +} + +sdump(pagf) +int pagf; +{ + register r; + register n = 0; + register o = 0; + char pag[PBLKSIZ]; + + while ((r = read(pagf, pag, PBLKSIZ)) > 0) { + if (!okpage(pag)) + fprintf(stderr, "%d: bad page.\n", n); + else if (empty(pag)) + o++; + else + dispage(pag); + n++; + } + + if (r == 0) + fprintf(stderr, "%d pages (%d holes).\n", n, o); + else + oops("read failed: block %d", n); +} + + +#ifdef OLD +dispage(pag) +char *pag; +{ + register i, n; + register off; + register short *ino = (short *) pag; + + off = PBLKSIZ; + for (i = 1; i < ino[0]; i += 2) { + printf("\t[%d]: ", ino[i]); + for (n = ino[i]; n < off; n++) + putchar(pag[n]); + putchar(' '); + off = ino[i]; + printf("[%d]: ", ino[i + 1]); + for (n = ino[i + 1]; n < off; n++) + putchar(pag[n]); + off = ino[i + 1]; + putchar('\n'); + } +} +#else +dispage(pag) +char *pag; +{ + register i, n; + register off; + register short *ino = (short *) pag; + + off = PBLKSIZ; + for (i = 1; i < ino[0]; i += 2) { + for (n = ino[i]; n < off; n++) + if (pag[n] != 0) + putchar(pag[n]); + putchar('\t'); + off = ino[i]; + for (n = ino[i + 1]; n < off; n++) + if (pag[n] != 0) + putchar(pag[n]); + putchar('\n'); + off = ino[i + 1]; + } +} +#endif diff --git a/ext/dbm/sdbm/dbe.1 b/ext/dbm/sdbm/dbe.1 new file mode 100644 index 0000000000..3b32272684 --- /dev/null +++ b/ext/dbm/sdbm/dbe.1 @@ -0,0 +1,46 @@ +.TH dbe 1 "ndbm(3) EDITOR" +.SH NAME +dbe \- Edit a ndbm(3) database +.SH USAGE +dbe <database> [-m r|w|rw] [-crtvx] -a|-d|-f|-F|-s [<key> [<content>]] +.SH DESCRIPTION +\fIdbme\fP operates on ndbm(3) databases. +It can be used to create them, look at them or change them. +When specifying the value of a key or the content of its associated entry, +\\nnn, \\0, \\n, \\t, \\f and \\r are interpreted as usual. +When displaying key/content pairs, non-printable characters are displayed +using the \\nnn notation. +.SH OPTIONS +.IP -a +List all entries in the database. +.IP -c +Create the database if it does not exist. +.IP -d +Delete the entry associated with the specified key. +.IP -f +Fetch and display the entry associated with the specified key. +.IP -F +Fetch and display all the entries whose key match the specified +regular-expression +.IP "-m r|w|rw" +Open the database in read-only, write-only or read-write mode +.IP -r +Replace the entry associated with the specified key if it already exists. +See option -s. +.IP -s +Store an entry under a specific key. +An error occurs if the key already exists and the option -r was not specified. +.IP -t +Re-initialize the database before executing the command. +.IP -v +Verbose mode. +Confirm stores and deletions. +.IP -x +If option -x is used with option -c, then if the database already exists, +an error occurs. +This can be used to implement a simple exclusive access locking mechanism. +.SH SEE ALSO +ndbm(3) +.SH AUTHOR +janick@bnr.ca + diff --git a/ext/dbm/sdbm/dbe.c b/ext/dbm/sdbm/dbe.c new file mode 100644 index 0000000000..2a306f276e --- /dev/null +++ b/ext/dbm/sdbm/dbe.c @@ -0,0 +1,435 @@ +#include <stdio.h> +#ifndef VMS +#include <sys/file.h> +#include <ndbm.h> +#else +#include "file.h" +#include "ndbm.h" +#endif +#include <ctype.h> + +/***************************************************************************\ +** ** +** Function name: getopt() ** +** Author: Henry Spencer, UofT ** +** Coding date: 84/04/28 ** +** ** +** Description: ** +** ** +** Parses argv[] for arguments. ** +** Works with Whitesmith's C compiler. ** +** ** +** Inputs - The number of arguments ** +** - The base address of the array of arguments ** +** - A string listing the valid options (':' indicates an ** +** argument to the preceding option is required, a ';' ** +** indicates an argument to the preceding option is optional) ** +** ** +** Outputs - Returns the next option character, ** +** '?' for non '-' arguments ** +** or ':' when there is no more arguments. ** +** ** +** Side Effects + The argument to an option is pointed to by 'optarg' ** +** ** +***************************************************************************** +** ** +** REVISION HISTORY: ** +** ** +** DATE NAME DESCRIPTION ** +** YY/MM/DD ------------------ ------------------------------------ ** +** 88/10/20 Janick Bergeron Returns '?' on unamed arguments ** +** returns '!' on unknown options ** +** and 'EOF' only when exhausted. ** +** 88/11/18 Janick Bergeron Return ':' when no more arguments ** +** 89/08/11 Janick Bergeron Optional optarg when ';' in optstring ** +** ** +\***************************************************************************/ + +char *optarg; /* Global argument pointer. */ + +#ifdef VMS +#define index strchr +#endif + +char +getopt(argc, argv, optstring) +int argc; +char **argv; +char *optstring; +{ + register int c; + register char *place; + extern char *index(); + static int optind = 0; + static char *scan = NULL; + + optarg = NULL; + + if (scan == NULL || *scan == '\0') { + + if (optind == 0) + optind++; + if (optind >= argc) + return ':'; + + optarg = place = argv[optind++]; + if (place[0] != '-' || place[1] == '\0') + return '?'; + if (place[1] == '-' && place[2] == '\0') + return '?'; + scan = place + 1; + } + + c = *scan++; + place = index(optstring, c); + if (place == NULL || c == ':' || c == ';') { + + (void) fprintf(stderr, "%s: unknown option %c\n", argv[0], c); + scan = NULL; + return '!'; + } + if (*++place == ':') { + + if (*scan != '\0') { + + optarg = scan; + scan = NULL; + + } + else { + + if (optind >= argc) { + + (void) fprintf(stderr, "%s: %c requires an argument\n", + argv[0], c); + return '!'; + } + optarg = argv[optind]; + optind++; + } + } + else if (*place == ';') { + + if (*scan != '\0') { + + optarg = scan; + scan = NULL; + + } + else { + + if (optind >= argc || *argv[optind] == '-') + optarg = NULL; + else { + optarg = argv[optind]; + optind++; + } + } + } + return c; +} + + +void +print_datum(db) +datum db; +{ + int i; + + putchar('"'); + for (i = 0; i < db.dsize; i++) { + if (isprint(db.dptr[i])) + putchar(db.dptr[i]); + else { + putchar('\\'); + putchar('0' + ((db.dptr[i] >> 6) & 0x07)); + putchar('0' + ((db.dptr[i] >> 3) & 0x07)); + putchar('0' + (db.dptr[i] & 0x07)); + } + } + putchar('"'); +} + + +datum +read_datum(s) +char *s; +{ + datum db; + char *p; + int i; + + db.dsize = 0; + db.dptr = (char *) malloc(strlen(s) * sizeof(char)); + for (p = db.dptr; *s != '\0'; p++, db.dsize++, s++) { + if (*s == '\\') { + if (*++s == 'n') + *p = '\n'; + else if (*s == 'r') + *p = '\r'; + else if (*s == 'f') + *p = '\f'; + else if (*s == 't') + *p = '\t'; + else if (isdigit(*s) && isdigit(*(s + 1)) && isdigit(*(s + 2))) { + i = (*s++ - '0') << 6; + i |= (*s++ - '0') << 3; + i |= *s - '0'; + *p = i; + } + else if (*s == '0') + *p = '\0'; + else + *p = *s; + } + else + *p = *s; + } + + return db; +} + + +char * +key2s(db) +datum db; +{ + char *buf; + char *p1, *p2; + + buf = (char *) malloc((db.dsize + 1) * sizeof(char)); + for (p1 = buf, p2 = db.dptr; *p2 != '\0'; *p1++ = *p2++); + *p1 = '\0'; + return buf; +} + + +main(argc, argv) +int argc; +char **argv; +{ + typedef enum { + YOW, FETCH, STORE, DELETE, SCAN, REGEXP + } commands; + char opt; + int flags; + int giveusage = 0; + int verbose = 0; + commands what = YOW; + char *comarg[3]; + int st_flag = DBM_INSERT; + int argn; + DBM *db; + datum key; + datum content; + + flags = O_RDWR; + argn = 0; + + while ((opt = getopt(argc, argv, "acdfFm:rstvx")) != ':') { + switch (opt) { + case 'a': + what = SCAN; + break; + case 'c': + flags |= O_CREAT; + break; + case 'd': + what = DELETE; + break; + case 'f': + what = FETCH; + break; + case 'F': + what = REGEXP; + break; + case 'm': + flags &= ~(000007); + if (strcmp(optarg, "r") == 0) + flags |= O_RDONLY; + else if (strcmp(optarg, "w") == 0) + flags |= O_WRONLY; + else if (strcmp(optarg, "rw") == 0) + flags |= O_RDWR; + else { + fprintf(stderr, "Invalid mode: \"%s\"\n", optarg); + giveusage = 1; + } + break; + case 'r': + st_flag = DBM_REPLACE; + break; + case 's': + what = STORE; + break; + case 't': + flags |= O_TRUNC; + break; + case 'v': + verbose = 1; + break; + case 'x': + flags |= O_EXCL; + break; + case '!': + giveusage = 1; + break; + case '?': + if (argn < 3) + comarg[argn++] = optarg; + else { + fprintf(stderr, "Too many arguments.\n"); + giveusage = 1; + } + break; + } + } + + if (giveusage | what == YOW | argn < 1) { + fprintf(stderr, "Usage: %s databse [-m r|w|rw] [-crtx] -a|-d|-f|-F|-s [key [content]]\n", argv[0]); + exit(-1); + } + + if ((db = dbm_open(comarg[0], flags, 0777)) == NULL) { + fprintf(stderr, "Error opening database \"%s\"\n", comarg[0]); + exit(-1); + } + + if (argn > 1) + key = read_datum(comarg[1]); + if (argn > 2) + content = read_datum(comarg[2]); + + switch (what) { + + case SCAN: + key = dbm_firstkey(db); + if (dbm_error(db)) { + fprintf(stderr, "Error when fetching first key\n"); + goto db_exit; + } + while (key.dptr != NULL) { + content = dbm_fetch(db, key); + if (dbm_error(db)) { + fprintf(stderr, "Error when fetching "); + print_datum(key); + printf("\n"); + goto db_exit; + } + print_datum(key); + printf(": "); + print_datum(content); + printf("\n"); + if (dbm_error(db)) { + fprintf(stderr, "Error when fetching next key\n"); + goto db_exit; + } + key = dbm_nextkey(db); + } + break; + + case REGEXP: + if (argn < 2) { + fprintf(stderr, "Missing regular expression.\n"); + goto db_exit; + } + if (re_comp(comarg[1])) { + fprintf(stderr, "Invalid regular expression\n"); + goto db_exit; + } + key = dbm_firstkey(db); + if (dbm_error(db)) { + fprintf(stderr, "Error when fetching first key\n"); + goto db_exit; + } + while (key.dptr != NULL) { + if (re_exec(key2s(key))) { + content = dbm_fetch(db, key); + if (dbm_error(db)) { + fprintf(stderr, "Error when fetching "); + print_datum(key); + printf("\n"); + goto db_exit; + } + print_datum(key); + printf(": "); + print_datum(content); + printf("\n"); + if (dbm_error(db)) { + fprintf(stderr, "Error when fetching next key\n"); + goto db_exit; + } + } + key = dbm_nextkey(db); + } + break; + + case FETCH: + if (argn < 2) { + fprintf(stderr, "Missing fetch key.\n"); + goto db_exit; + } + content = dbm_fetch(db, key); + if (dbm_error(db)) { + fprintf(stderr, "Error when fetching "); + print_datum(key); + printf("\n"); + goto db_exit; + } + if (content.dptr == NULL) { + fprintf(stderr, "Cannot find "); + print_datum(key); + printf("\n"); + goto db_exit; + } + print_datum(key); + printf(": "); + print_datum(content); + printf("\n"); + break; + + case DELETE: + if (argn < 2) { + fprintf(stderr, "Missing delete key.\n"); + goto db_exit; + } + if (dbm_delete(db, key) || dbm_error(db)) { + fprintf(stderr, "Error when deleting "); + print_datum(key); + printf("\n"); + goto db_exit; + } + if (verbose) { + print_datum(key); + printf(": DELETED\n"); + } + break; + + case STORE: + if (argn < 3) { + fprintf(stderr, "Missing key and/or content.\n"); + goto db_exit; + } + if (dbm_store(db, key, content, st_flag) || dbm_error(db)) { + fprintf(stderr, "Error when storing "); + print_datum(key); + printf("\n"); + goto db_exit; + } + if (verbose) { + print_datum(key); + printf(": "); + print_datum(content); + printf(" STORED\n"); + } + break; + } + +db_exit: + dbm_clearerr(db); + dbm_close(db); + if (dbm_error(db)) { + fprintf(stderr, "Error closing database \"%s\"\n", comarg[0]); + exit(-1); + } +} diff --git a/ext/dbm/sdbm/dbm.c b/ext/dbm/sdbm/dbm.c new file mode 100644 index 0000000000..1388230e2d --- /dev/null +++ b/ext/dbm/sdbm/dbm.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 1985 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char sccsid[] = "@(#)dbm.c 5.4 (Berkeley) 5/24/89"; +#endif /* not lint */ + +#include "dbm.h" + +#define NODB ((DBM *)0) + +static DBM *cur_db = NODB; + +static char no_db[] = "dbm: no open database\n"; + +dbminit(file) + char *file; +{ + if (cur_db != NODB) + dbm_close(cur_db); + + cur_db = dbm_open(file, 2, 0); + if (cur_db == NODB) { + cur_db = dbm_open(file, 0, 0); + if (cur_db == NODB) + return (-1); + } + return (0); +} + +long +forder(key) +datum key; +{ + if (cur_db == NODB) { + printf(no_db); + return (0L); + } + return (dbm_forder(cur_db, key)); +} + +datum +fetch(key) +datum key; +{ + datum item; + + if (cur_db == NODB) { + printf(no_db); + item.dptr = 0; + return (item); + } + return (dbm_fetch(cur_db, key)); +} + +delete(key) +datum key; +{ + if (cur_db == NODB) { + printf(no_db); + return (-1); + } + if (dbm_rdonly(cur_db)) + return (-1); + return (dbm_delete(cur_db, key)); +} + +store(key, dat) +datum key, dat; +{ + if (cur_db == NODB) { + printf(no_db); + return (-1); + } + if (dbm_rdonly(cur_db)) + return (-1); + + return (dbm_store(cur_db, key, dat, DBM_REPLACE)); +} + +datum +firstkey() +{ + datum item; + + if (cur_db == NODB) { + printf(no_db); + item.dptr = 0; + return (item); + } + return (dbm_firstkey(cur_db)); +} + +datum +nextkey(key) +datum key; +{ + datum item; + + if (cur_db == NODB) { + printf(no_db); + item.dptr = 0; + return (item); + } + return (dbm_nextkey(cur_db, key)); +} diff --git a/ext/dbm/sdbm/dbm.h b/ext/dbm/sdbm/dbm.h new file mode 100644 index 0000000000..dce48fed07 --- /dev/null +++ b/ext/dbm/sdbm/dbm.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 1983 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#)dbm.h 5.2 (Berkeley) 5/24/89 + */ + +#ifndef NULL +/* + * this is lunacy, we no longer use it (and never should have + * unconditionally defined it), but, this whole file is for + * backwards compatability - someone may rely on this. + */ +#define NULL ((char *) 0) +#endif + +#include <ndbm.h> + +datum fetch(); +datum firstkey(); +datum nextkey(); diff --git a/ext/dbm/sdbm/dbu.c b/ext/dbm/sdbm/dbu.c new file mode 100644 index 0000000000..106262872e --- /dev/null +++ b/ext/dbm/sdbm/dbu.c @@ -0,0 +1,250 @@ +#include <stdio.h> +#include <sys/file.h> +#ifdef SDBM +#include "sdbm.h" +#else +#include <ndbm.h> +#endif +#include <string.h> + +#ifdef BSD42 +#define strchr index +#endif + +extern int getopt(); +extern char *strchr(); +extern void oops(); + +char *progname; + +static int rflag; +static char *usage = "%s [-R] cat | look |... dbmname"; + +#define DERROR 0 +#define DLOOK 1 +#define DINSERT 2 +#define DDELETE 3 +#define DCAT 4 +#define DBUILD 5 +#define DPRESS 6 +#define DCREAT 7 + +#define LINEMAX 8192 + +typedef struct { + char *sname; + int scode; + int flags; +} cmd; + +static cmd cmds[] = { + + "fetch", DLOOK, O_RDONLY, + "get", DLOOK, O_RDONLY, + "look", DLOOK, O_RDONLY, + "add", DINSERT, O_RDWR, + "insert", DINSERT, O_RDWR, + "store", DINSERT, O_RDWR, + "delete", DDELETE, O_RDWR, + "remove", DDELETE, O_RDWR, + "dump", DCAT, O_RDONLY, + "list", DCAT, O_RDONLY, + "cat", DCAT, O_RDONLY, + "creat", DCREAT, O_RDWR | O_CREAT | O_TRUNC, + "new", DCREAT, O_RDWR | O_CREAT | O_TRUNC, + "build", DBUILD, O_RDWR | O_CREAT, + "squash", DPRESS, O_RDWR, + "compact", DPRESS, O_RDWR, + "compress", DPRESS, O_RDWR +}; + +#define CTABSIZ (sizeof (cmds)/sizeof (cmd)) + +static cmd *parse(); +static void badk(), doit(), prdatum(); + +int +main(argc, argv) +int argc; +char *argv[]; +{ + int c; + register cmd *act; + extern int optind; + extern char *optarg; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "R")) != EOF) + switch (c) { + case 'R': /* raw processing */ + rflag++; + break; + + default: + oops("usage: %s", usage); + break; + } + + if ((argc -= optind) < 2) + oops("usage: %s", usage); + + if ((act = parse(argv[optind])) == NULL) + badk(argv[optind]); + optind++; + doit(act, argv[optind]); + return 0; +} + +static void +doit(act, file) +register cmd *act; +char *file; +{ + datum key; + datum val; + register DBM *db; + register char *op; + register int n; + char *line; +#ifdef TIME + long start; + extern long time(); +#endif + + if ((db = dbm_open(file, act->flags, 0644)) == NULL) + oops("cannot open: %s", file); + + if ((line = (char *) malloc(LINEMAX)) == NULL) + oops("%s: cannot get memory", "line alloc"); + + switch (act->scode) { + + case DLOOK: + while (fgets(line, LINEMAX, stdin) != NULL) { + n = strlen(line) - 1; + line[n] = 0; + key.dptr = line; + key.dsize = n; + val = dbm_fetch(db, key); + if (val.dptr != NULL) { + prdatum(stdout, val); + putchar('\n'); + continue; + } + prdatum(stderr, key); + fprintf(stderr, ": not found.\n"); + } + break; + case DINSERT: + break; + case DDELETE: + while (fgets(line, LINEMAX, stdin) != NULL) { + n = strlen(line) - 1; + line[n] = 0; + key.dptr = line; + key.dsize = n; + if (dbm_delete(db, key) == -1) { + prdatum(stderr, key); + fprintf(stderr, ": not found.\n"); + } + } + break; + case DCAT: + for (key = dbm_firstkey(db); key.dptr != 0; + key = dbm_nextkey(db)) { + prdatum(stdout, key); + putchar('\t'); + prdatum(stdout, dbm_fetch(db, key)); + putchar('\n'); + } + break; + case DBUILD: +#ifdef TIME + start = time(0); +#endif + while (fgets(line, LINEMAX, stdin) != NULL) { + n = strlen(line) - 1; + line[n] = 0; + key.dptr = line; + if ((op = strchr(line, '\t')) != 0) { + key.dsize = op - line; + *op++ = 0; + val.dptr = op; + val.dsize = line + n - op; + } + else + oops("bad input; %s", line); + + if (dbm_store(db, key, val, DBM_REPLACE) < 0) { + prdatum(stderr, key); + fprintf(stderr, ": "); + oops("store: %s", "failed"); + } + } +#ifdef TIME + printf("done: %d seconds.\n", time(0) - start); +#endif + break; + case DPRESS: + break; + case DCREAT: + break; + } + + dbm_close(db); +} + +static void +badk(word) +char *word; +{ + register int i; + + if (progname) + fprintf(stderr, "%s: ", progname); + fprintf(stderr, "bad keywd %s. use one of\n", word); + for (i = 0; i < (int)CTABSIZ; i++) + fprintf(stderr, "%-8s%c", cmds[i].sname, + ((i + 1) % 6 == 0) ? '\n' : ' '); + fprintf(stderr, "\n"); + exit(1); + /*NOTREACHED*/ +} + +static cmd * +parse(str) +register char *str; +{ + register int i = CTABSIZ; + register cmd *p; + + for (p = cmds; i--; p++) + if (strcmp(p->sname, str) == 0) + return p; + return NULL; +} + +static void +prdatum(stream, d) +FILE *stream; +datum d; +{ + register int c; + register char *p = d.dptr; + register int n = d.dsize; + + while (n--) { + c = *p++ & 0377; + if (c & 0200) { + fprintf(stream, "M-"); + c &= 0177; + } + if (c == 0177 || c < ' ') + fprintf(stream, "^%c", (c == 0177) ? '?' : c + '@'); + else + putc(c, stream); + } +} + + diff --git a/ext/dbm/sdbm/grind b/ext/dbm/sdbm/grind new file mode 100755 index 0000000000..23728b7d49 --- /dev/null +++ b/ext/dbm/sdbm/grind @@ -0,0 +1,9 @@ +#!/bin/sh +rm -f /tmp/*.dir /tmp/*.pag +awk -e '{ + printf "%s\t", $0 + for (i = 0; i < 40; i++) + printf "%s.", $0 + printf "\n" +}' < /usr/dict/words | $1 build /tmp/$2 + diff --git a/ext/dbm/sdbm/hash.c b/ext/dbm/sdbm/hash.c new file mode 100644 index 0000000000..9b55a7f571 --- /dev/null +++ b/ext/dbm/sdbm/hash.c @@ -0,0 +1,47 @@ +/* + * sdbm - ndbm work-alike hashed database library + * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978). + * author: oz@nexus.yorku.ca + * status: public domain. keep it that way. + * + * hashing routine + */ + +#include "sdbm.h" +/* + * polynomial conversion ignoring overflows + * [this seems to work remarkably well, in fact better + * then the ndbm hash function. Replace at your own risk] + * use: 65599 nice. + * 65587 even better. + */ +long +sdbm_hash(str, len) +register char *str; +register int len; +{ + register unsigned long n = 0; + +#ifdef DUFF + +#define HASHC n = *str++ + 65599 * n + + if (len > 0) { + register int loop = (len + 8 - 1) >> 3; + + switch(len & (8 - 1)) { + case 0: do { + HASHC; case 7: HASHC; + case 6: HASHC; case 5: HASHC; + case 4: HASHC; case 3: HASHC; + case 2: HASHC; case 1: HASHC; + } while (--loop); + } + + } +#else + while (len--) + n = *str++ + 65599 * n; +#endif + return n; +} diff --git a/ext/dbm/sdbm/linux.patches b/ext/dbm/sdbm/linux.patches new file mode 100644 index 0000000000..cb7b1b7d8e --- /dev/null +++ b/ext/dbm/sdbm/linux.patches @@ -0,0 +1,67 @@ +*** sdbm.dist/./dbu.c Mon Feb 17 21:18:52 1992 +--- sdbm/./dbu.c Mon Feb 17 21:11:20 1992 +*************** +*** 12,18 **** + #endif + + extern int getopt(); +! extern char *strchr(); + extern void oops(); + + char *progname; +--- 12,18 ---- + #endif + + extern int getopt(); +! /* extern char *strchr(); */ + extern void oops(); + + char *progname; +*** sdbm.dist/./makefile Mon Feb 17 21:18:56 1992 +--- sdbm/./makefile Mon Feb 17 21:10:46 1992 +*************** +*** 2,8 **** + # makefile for public domain ndbm-clone: sdbm + # DUFF: use duff's device (loop unroll) in parts of the code + # +! CFLAGS = -O -DSDBM -DDUFF -DBSD42 + #LDFLAGS = -p + + OBJS = sdbm.o pair.o hash.o +--- 2,8 ---- + # makefile for public domain ndbm-clone: sdbm + # DUFF: use duff's device (loop unroll) in parts of the code + # +! CFLAGS = -O -DSDBM -DDUFF + #LDFLAGS = -p + + OBJS = sdbm.o pair.o hash.o +*** sdbm.dist/./sdbm.c Mon Feb 17 21:19:17 1992 +--- sdbm/./sdbm.c Mon Feb 17 21:12:59 1992 +*************** +*** 25,30 **** +--- 25,31 ---- + #endif + #include <errno.h> + #include <string.h> ++ #include <unistd.h> + + #ifdef __STDC__ + #include <stddef.h> +*************** +*** 43,49 **** + + extern char *malloc proto((unsigned int)); + extern void free proto((void *)); +! extern long lseek(); + + /* + * forward +--- 44,50 ---- + + extern char *malloc proto((unsigned int)); + extern void free proto((void *)); +! /* extern long lseek(); */ + + /* + * forward diff --git a/ext/dbm/sdbm/makefile b/ext/dbm/sdbm/makefile new file mode 100644 index 0000000000..5dabe40242 --- /dev/null +++ b/ext/dbm/sdbm/makefile @@ -0,0 +1,55 @@ +# +# makefile for public domain ndbm-clone: sdbm +# DUFF: use duff's device (loop unroll) in parts of the code +# +CFLAGS = -O -DSDBM -DDUFF -DBSD42 +#LDFLAGS = -p + +OBJS = sdbm.o pair.o hash.o +SRCS = sdbm.c pair.c hash.c dbu.c dba.c dbd.c util.c +HDRS = tune.h sdbm.h pair.h +MISC = README CHANGES COMPARE sdbm.3 dbe.c dbe.1 dbm.c dbm.h biblio \ + readme.ms readme.ps + +all: dbu dba dbd dbe + +dbu: dbu.o sdbm util.o + cc $(LDFLAGS) -o dbu dbu.o util.o libsdbm.a + +dba: dba.o util.o + cc $(LDFLAGS) -o dba dba.o util.o +dbd: dbd.o util.o + cc $(LDFLAGS) -o dbd dbd.o util.o +dbe: dbe.o sdbm + cc $(LDFLAGS) -o dbe dbe.o libsdbm.a + +sdbm: $(OBJS) + ar cr libsdbm.a $(OBJS) + ranlib libsdbm.a +### cp libsdbm.a /usr/lib/libsdbm.a + +dba.o: sdbm.h +dbu.o: sdbm.h +util.o:sdbm.h + +$(OBJS): sdbm.h tune.h pair.h + +# +# dbu using berkelezoid ndbm routines [if you have them] for testing +# +#x-dbu: dbu.o util.o +# cc $(CFLAGS) -o x-dbu dbu.o util.o +lint: + lint -abchx $(SRCS) + +clean: + rm -f *.o mon.out core + +purge: clean + rm -f dbu libsdbm.a dbd dba dbe x-dbu *.dir *.pag + +shar: + shar $(MISC) makefile $(SRCS) $(HDRS) >SDBM.SHAR + +readme: + nroff -ms readme.ms | col -b >README diff --git a/ext/dbm/sdbm/pair.c b/ext/dbm/sdbm/pair.c new file mode 100644 index 0000000000..a3941716d9 --- /dev/null +++ b/ext/dbm/sdbm/pair.c @@ -0,0 +1,308 @@ +/* + * sdbm - ndbm work-alike hashed database library + * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978). + * author: oz@nexus.yorku.ca + * status: public domain. + * + * page-level routines + */ + +#ifndef lint +static char rcsid[] = "$Id: pair.c,v 1.10 90/12/13 13:00:35 oz Exp $"; +#endif + +#include "sdbm.h" +#include "tune.h" +#include "pair.h" + +#ifndef BSD42 +#include <memory.h> +#endif + +#define exhash(item) sdbm_hash((item).dptr, (item).dsize) + +/* + * forward + */ +static int seepair proto((char *, int, char *, int)); + +/* + * page format: + * +------------------------------+ + * ino | n | keyoff | datoff | keyoff | + * +------------+--------+--------+ + * | datoff | - - - ----> | + * +--------+---------------------+ + * | F R E E A R E A | + * +--------------+---------------+ + * | <---- - - - | data | + * +--------+-----+----+----------+ + * | key | data | key | + * +--------+----------+----------+ + * + * calculating the offsets for free area: if the number + * of entries (ino[0]) is zero, the offset to the END of + * the free area is the block size. Otherwise, it is the + * nth (ino[ino[0]]) entry's offset. + */ + +int +fitpair(pag, need) +char *pag; +int need; +{ + register int n; + register int off; + register int free; + register short *ino = (short *) pag; + + off = ((n = ino[0]) > 0) ? ino[n] : PBLKSIZ; + free = off - (n + 1) * sizeof(short); + need += 2 * sizeof(short); + + debug(("free %d need %d\n", free, need)); + + return need <= free; +} + +void +putpair(pag, key, val) +char *pag; +datum key; +datum val; +{ + register int n; + register int off; + register short *ino = (short *) pag; + + off = ((n = ino[0]) > 0) ? ino[n] : PBLKSIZ; +/* + * enter the key first + */ + off -= key.dsize; + (void) memcpy(pag + off, key.dptr, key.dsize); + ino[n + 1] = off; +/* + * now the data + */ + off -= val.dsize; + (void) memcpy(pag + off, val.dptr, val.dsize); + ino[n + 2] = off; +/* + * adjust item count + */ + ino[0] += 2; +} + +datum +getpair(pag, key) +char *pag; +datum key; +{ + register int i; + register int n; + datum val; + register short *ino = (short *) pag; + + if ((n = ino[0]) == 0) + return nullitem; + + if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0) + return nullitem; + + val.dptr = pag + ino[i + 1]; + val.dsize = ino[i] - ino[i + 1]; + return val; +} + +#ifdef SEEDUPS +int +duppair(pag, key) +char *pag; +datum key; +{ + register short *ino = (short *) pag; + return ino[0] > 0 && seepair(pag, ino[0], key.dptr, key.dsize) > 0; +} +#endif + +datum +getnkey(pag, num) +char *pag; +int num; +{ + datum key; + register int off; + register short *ino = (short *) pag; + + num = num * 2 - 1; + if (ino[0] == 0 || num > ino[0]) + return nullitem; + + off = (num > 1) ? ino[num - 1] : PBLKSIZ; + + key.dptr = pag + ino[num]; + key.dsize = off - ino[num]; + + return key; +} + +int +delpair(pag, key) +char *pag; +datum key; +{ + register int n; + register int i; + register short *ino = (short *) pag; + + if ((n = ino[0]) == 0) + return 0; + + if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0) + return 0; +/* + * found the key. if it is the last entry + * [i.e. i == n - 1] we just adjust the entry count. + * hard case: move all data down onto the deleted pair, + * shift offsets onto deleted offsets, and adjust them. + * [note: 0 < i < n] + */ + if (i < n - 1) { + register int m; + register char *dst = pag + (i == 1 ? PBLKSIZ : ino[i - 1]); + register char *src = pag + ino[i + 1]; + register int zoo = dst - src; + + debug(("free-up %d ", zoo)); +/* + * shift data/keys down + */ + m = ino[i + 1] - ino[n]; +#ifdef DUFF +#define MOVB *--dst = *--src + + if (m > 0) { + register int loop = (m + 8 - 1) >> 3; + + switch (m & (8 - 1)) { + case 0: do { + MOVB; case 7: MOVB; + case 6: MOVB; case 5: MOVB; + case 4: MOVB; case 3: MOVB; + case 2: MOVB; case 1: MOVB; + } while (--loop); + } + } +#else +#ifdef MEMMOVE + memmove(dst, src, m); +#else + while (m--) + *--dst = *--src; +#endif +#endif +/* + * adjust offset index up + */ + while (i < n - 1) { + ino[i] = ino[i + 2] + zoo; + i++; + } + } + ino[0] -= 2; + return 1; +} + +/* + * search for the key in the page. + * return offset index in the range 0 < i < n. + * return 0 if not found. + */ +static int +seepair(pag, n, key, siz) +char *pag; +register int n; +register char *key; +register int siz; +{ + register int i; + register int off = PBLKSIZ; + register short *ino = (short *) pag; + + for (i = 1; i < n; i += 2) { + if (siz == off - ino[i] && + memcmp(key, pag + ino[i], siz) == 0) + return i; + off = ino[i + 1]; + } + return 0; +} + +void +splpage(pag, new, sbit) +char *pag; +char *new; +long sbit; +{ + datum key; + datum val; + + register int n; + register int off = PBLKSIZ; + char cur[PBLKSIZ]; + register short *ino = (short *) cur; + + (void) memcpy(cur, pag, PBLKSIZ); + (void) memset(pag, 0, PBLKSIZ); + (void) memset(new, 0, PBLKSIZ); + + n = ino[0]; + for (ino++; n > 0; ino += 2) { + key.dptr = cur + ino[0]; + key.dsize = off - ino[0]; + val.dptr = cur + ino[1]; + val.dsize = ino[0] - ino[1]; +/* + * select the page pointer (by looking at sbit) and insert + */ + (void) putpair((exhash(key) & sbit) ? new : pag, key, val); + + off = ino[1]; + n -= 2; + } + + debug(("%d split %d/%d\n", ((short *) cur)[0] / 2, + ((short *) new)[0] / 2, + ((short *) pag)[0] / 2)); +} + +/* + * check page sanity: + * number of entries should be something + * reasonable, and all offsets in the index should be in order. + * this could be made more rigorous. + */ +int +chkpage(pag) +char *pag; +{ + register int n; + register int off; + register short *ino = (short *) pag; + + if ((n = ino[0]) < 0 || n > PBLKSIZ / sizeof(short)) + return 0; + + if (n > 0) { + off = PBLKSIZ; + for (ino++; n > 0; ino += 2) { + if (ino[0] > off || ino[1] > off || + ino[1] > ino[0]) + return 0; + off = ino[1]; + n -= 2; + } + } + return 1; +} diff --git a/ext/dbm/sdbm/pair.h b/ext/dbm/sdbm/pair.h new file mode 100644 index 0000000000..bd66d02fd2 --- /dev/null +++ b/ext/dbm/sdbm/pair.h @@ -0,0 +1,10 @@ +extern int fitpair proto((char *, int)); +extern void putpair proto((char *, datum, datum)); +extern datum getpair proto((char *, datum)); +extern int delpair proto((char *, datum)); +extern int chkpage proto((char *)); +extern datum getnkey proto((char *, int)); +extern void splpage proto((char *, char *, long)); +#ifdef SEEDUPS +extern int duppair proto((char *, datum)); +#endif diff --git a/ext/dbm/sdbm/readme.ms b/ext/dbm/sdbm/readme.ms new file mode 100644 index 0000000000..01ca17ccdf --- /dev/null +++ b/ext/dbm/sdbm/readme.ms @@ -0,0 +1,353 @@ +.\" tbl | readme.ms | [tn]roff -ms | ... +.\" note the "C" (courier) and "CB" fonts: you will probably have to +.\" change these. +.\" $Id: readme.ms,v 1.1 90/12/13 13:09:15 oz Exp Locker: oz $ + +.de P1 +.br +.nr dT 4 +.nf +.ft C +.sp .5 +.nr t \\n(dT*\\w'x'u +.ta 1u*\\ntu 2u*\\ntu 3u*\\ntu 4u*\\ntu 5u*\\ntu 6u*\\ntu 7u*\\ntu 8u*\\ntu 9u*\\ntu 10u*\\ntu 11u*\\ntu 12u*\\ntu 13u*\\ntu 14u*\\ntu +.. +.de P2 +.br +.ft 1 +.br +.sp .5 +.br +.fi +.. +.\" CW uses the typewriter/courier font. +.de CW +\fC\\$1\\fP\\$2 +.. + +.\" Footnote numbering [by Henry Spencer] +.\" <text>\*f for a footnote number.. +.\" .FS +.\" \*F <footnote text> +.\" .FE +.\" +.ds f \\u\\s-2\\n+f\\s+2\\d +.nr f 0 1 +.ds F \\n+F. +.nr F 0 1 + +.ND +.LP +.TL +\fIsdbm\fP \(em Substitute DBM +.br +or +.br +Berkeley \fIndbm\fP for Every UN*X\** Made Simple +.AU +Ozan (oz) Yigit +.AI +The Guild of PD Software Toolmakers +Toronto - Canada +.sp +oz@nexus.yorku.ca +.LP +.FS +UN*X is not a trademark of any (dis)organization. +.FE +.sp 2 +\fIImplementation is the sincerest form of flattery. \(em L. Peter Deutsch\fP +.SH +A The Clone of the \fIndbm\fP library +.PP +The sources accompanying this notice \(em \fIsdbm\fP \(em constitute +the first public release (Dec. 1990) of a complete clone of +the Berkeley UN*X \fIndbm\fP library. The \fIsdbm\fP library is meant to +clone the proven functionality of \fIndbm\fP as closely as possible, +including a few improvements. It is practical, easy to understand, and +compatible. +The \fIsdbm\fP library is not derived from any licensed, proprietary or +copyrighted software. +.PP +The \fIsdbm\fP implementation is based on a 1978 algorithm +[Lar78] by P.-A. (Paul) Larson known as ``Dynamic Hashing''. +In the course of searching for a substitute for \fIndbm\fP, I +prototyped three different external-hashing algorithms [Lar78, Fag79, Lit80] +and ultimately chose Larson's algorithm as a basis of the \fIsdbm\fP +implementation. The Bell Labs +\fIdbm\fP (and therefore \fIndbm\fP) is based on an algorithm invented by +Ken Thompson, [Tho90, Tor87] and predates Larson's work. +.PP +The \fIsdbm\fR programming interface is totally compatible +with \fIndbm\fP and includes a slight improvement in database initialization. +It is also expected to be binary-compatible under most UN*X versions that +support the \fIndbm\fP library. +.PP +The \fIsdbm\fP implementation shares the shortcomings of the \fIndbm\fP +library, as a side effect of various simplifications to the original Larson +algorithm. It does produce \fIholes\fP in the page file as it writes +pages past the end of file. (Larson's paper include a clever solution to +this problem that is a result of using the hash value directly as a block +address.) On the other hand, extensive tests seem to indicate that \fIsdbm\fP +creates fewer holes in general, and the resulting pagefiles are +smaller. The \fIsdbm\fP implementation is also faster than \fIndbm\fP +in database creation. +Unlike the \fIndbm\fP, the \fIsdbm\fP +.CW store +operation will not ``wander away'' trying to split its +data pages to insert a datum that \fIcannot\fP (due to elaborate worst-case +situations) be inserted. (It will fail after a pre-defined number of attempts.) +.SH +Important Compatibility Warning +.PP +The \fIsdbm\fP and \fIndbm\fP +libraries \fIcannot\fP share databases: one cannot read the (dir/pag) +database created by the other. This is due to the differences +between the \fIndbm\fP and \fIsdbm\fP algorithms\**, +.FS +Torek's discussion [Tor87] +indicates that \fIdbm/ndbm\fP implementations use the hash +value to traverse the radix trie differently than \fIsdbm\fP +and as a result, the page indexes are generated in \fIdifferent\fP order. +For more information, send e-mail to the author. +.FE +and the hash functions +used. +It is easy to convert between the \fIdbm/ndbm\fP databases and \fIsdbm\fP +by ignoring the index completely: see +.CW dbd , +.CW dbu +etc. +.R +.LP +.SH +Notice of Intellectual Property +.LP +\fIThe entire\fP sdbm \fIlibrary package, as authored by me,\fP Ozan S. Yigit, +\fIis hereby placed in the public domain.\fP As such, the author is not +responsible for the consequences of use of this software, no matter how +awful, even if they arise from defects in it. There is no expressed or +implied warranty for the \fIsdbm\fP library. +.PP +Since the \fIsdbm\fP +library package is in the public domain, this \fIoriginal\fP +release or any additional public-domain releases of the modified original +cannot possibly (by definition) be withheld from you. Also by definition, +You (singular) have all the rights to this code (including the right to +sell without permission, the right to hoard\** +.FS +You cannot really hoard something that is available to the public at +large, but try if it makes you feel any better. +.FE +and the right to do other icky things as +you see fit) but those rights are also granted to everyone else. +.PP +Please note that all previous distributions of this software contained +a copyright (which is now dropped) to protect its +origins and its current public domain status against any possible claims +and/or challenges. +.SH +Acknowledgments +.PP +Many people have been very helpful and supportive. A partial list would +necessarily include Rayan Zacherissen (who contributed the man page, +and also hacked a MMAP version of \fIsdbm\fP), +Arnold Robbins, Chris Lewis, +Bill Davidsen, Henry Spencer, Geoff Collyer, Rich Salz (who got me started +in the first place), Johannes Ruschein +(who did the minix port) and David Tilbrook. I thank you all. +.SH +Distribution Manifest and Notes +.LP +This distribution of \fIsdbm\fP includes (at least) the following: +.P1 + CHANGES change log + README this file. + biblio a small bibliography on external hashing + dba.c a crude (n/s)dbm page file analyzer + dbd.c a crude (n/s)dbm page file dumper (for conversion) + dbe.1 man page for dbe.c + dbe.c Janick's database editor + dbm.c a dbm library emulation wrapper for ndbm/sdbm + dbm.h header file for the above + dbu.c a crude db management utility + hash.c hashing function + makefile guess. + pair.c page-level routines (posted earlier) + pair.h header file for the above + readme.ms troff source for the README file + sdbm.3 man page + sdbm.c the real thing + sdbm.h header file for the above + tune.h place for tuning & portability thingies + util.c miscellaneous +.P2 +.PP +.CW dbu +is a simple database manipulation program\** that tries to look +.FS +The +.CW dbd , +.CW dba , +.CW dbu +utilities are quick hacks and are not fit for production use. They were +developed late one night, just to test out \fIsdbm\fP, and convert some +databases. +.FE +like Bell Labs' +.CW cbt +utility. It is currently incomplete in functionality. +I use +.CW dbu +to test out the routines: it takes (from stdin) tab separated +key/value pairs for commands like +.CW build +or +.CW insert +or takes keys for +commands like +.CW delete +or +.CW look . +.P1 + dbu <build|creat|look|insert|cat|delete> dbmfile +.P2 +.PP +.CW dba +is a crude analyzer of \fIdbm/sdbm/ndbm\fP +page files. It scans the entire +page file, reporting page level statistics, and totals at the end. +.PP +.CW dbd +is a crude dump program for \fIdbm/ndbm/sdbm\fP +databases. It ignores the +bitmap, and dumps the data pages in sequence. It can be used to create +input for the +.CW dbu +utility. +Note that +.CW dbd +will skip any NULLs in the key and data +fields, thus is unsuitable to convert some peculiar databases that +insist in including the terminating null. +.PP +I have also included a copy of the +.CW dbe +(\fIndbm\fP DataBase Editor) by Janick Bergeron [janick@bnr.ca] for +your pleasure. You may find it more useful than the little +.CW dbu +utility. +.PP +.CW dbm.[ch] +is a \fIdbm\fP library emulation on top of \fIndbm\fP +(and hence suitable for \fIsdbm\fP). Written by Robert Elz. +.PP +The \fIsdbm\fP +library has been around in beta test for quite a long time, and from whatever +little feedback I received (maybe no news is good news), I believe it has been +functioning without any significant problems. I would, of course, appreciate +all fixes and/or improvements. Portability enhancements would especially be +useful. +.SH +Implementation Issues +.PP +Hash functions: +The algorithm behind \fIsdbm\fP implementation needs a good bit-scrambling +hash function to be effective. I ran into a set of constants for a simple +hash function that seem to help \fIsdbm\fP perform better than \fIndbm\fP +for various inputs: +.P1 + /* + * polynomial conversion ignoring overflows + * 65599 nice. 65587 even better. + */ + long + dbm_hash(char *str, int len) { + register unsigned long n = 0; + + while (len--) + n = n * 65599 + *str++; + return n; + } +.P2 +.PP +There may be better hash functions for the purposes of dynamic hashing. +Try your favorite, and check the pagefile. If it contains too many pages +with too many holes, (in relation to this one for example) or if +\fIsdbm\fP +simply stops working (fails after +.CW SPLTMAX +attempts to split) when you feed your +NEWS +.CW history +file to it, you probably do not have a good hashing function. +If you do better (for different types of input), I would like to know +about the function you use. +.PP +Block sizes: It seems (from various tests on a few machines) that a page +file block size +.CW PBLKSIZ +of 1024 is by far the best for performance, but +this also happens to limit the size of a key/value pair. Depending on your +needs, you may wish to increase the page size, and also adjust +.CW PAIRMAX +(the maximum size of a key/value pair allowed: should always be at least +three words smaller than +.CW PBLKSIZ .) +accordingly. The system-wide version of the library +should probably be +configured with 1024 (distribution default), as this appears to be sufficient +for most common uses of \fIsdbm\fP. +.SH +Portability +.PP +This package has been tested in many different UN*Xes even including minix, +and appears to be reasonably portable. This does not mean it will port +easily to non-UN*X systems. +.SH +Notes and Miscellaneous +.PP +The \fIsdbm\fP is not a very complicated package, at least not after you +familiarize yourself with the literature on external hashing. There are +other interesting algorithms in existence that ensure (approximately) +single-read access to a data value associated with any key. These are +directory-less schemes such as \fIlinear hashing\fP [Lit80] (+ Larson +variations), \fIspiral storage\fP [Mar79] or directory schemes such as +\fIextensible hashing\fP [Fag79] by Fagin et al. I do hope these sources +provide a reasonable playground for experimentation with other algorithms. +See the June 1988 issue of ACM Computing Surveys [Enb88] for an +excellent overview of the field. +.PG +.SH +References +.LP +.IP [Lar78] 4m +P.-A. Larson, +``Dynamic Hashing'', \fIBIT\fP, vol. 18, pp. 184-201, 1978. +.IP [Tho90] 4m +Ken Thompson, \fIprivate communication\fP, Nov. 1990 +.IP [Lit80] 4m +W. Litwin, +`` Linear Hashing: A new tool for file and table addressing'', +\fIProceedings of the 6th Conference on Very Large Dabatases (Montreal)\fP, +pp. 212-223, Very Large Database Foundation, Saratoga, Calif., 1980. +.IP [Fag79] 4m +R. Fagin, J. Nievergelt, N. Pippinger, and H. R. Strong, +``Extendible Hashing - A Fast Access Method for Dynamic Files'', +\fIACM Trans. Database Syst.\fP, vol. 4, no.3, pp. 315-344, Sept. 1979. +.IP [Wal84] 4m +Rich Wales, +``Discussion of "dbm" data base system'', \fIUSENET newsgroup unix.wizards\fP, +Jan. 1984. +.IP [Tor87] 4m +Chris Torek, +``Re: dbm.a and ndbm.a archives'', \fIUSENET newsgroup comp.unix\fP, +1987. +.IP [Mar79] 4m +G. N. Martin, +``Spiral Storage: Incrementally Augmentable Hash Addressed Storage'', +\fITechnical Report #27\fP, University of Varwick, Coventry, U.K., 1979. +.IP [Enb88] 4m +R. J. Enbody and H. C. Du, +``Dynamic Hashing Schemes'',\fIACM Computing Surveys\fP, +vol. 20, no. 2, pp. 85-113, June 1988. diff --git a/ext/dbm/sdbm/readme.ps b/ext/dbm/sdbm/readme.ps new file mode 100644 index 0000000000..2b0c675595 --- /dev/null +++ b/ext/dbm/sdbm/readme.ps @@ -0,0 +1,2225 @@ +%!PS-Adobe-1.0 +%%Creator: yetti:oz (Ozan Yigit) +%%Title: stdin (ditroff) +%%CreationDate: Thu Dec 13 15:56:08 1990 +%%EndComments +% lib/psdit.pro -- prolog for psdit (ditroff) files +% Copyright (c) 1984, 1985 Adobe Systems Incorporated. All Rights Reserved. +% last edit: shore Sat Nov 23 20:28:03 1985 +% RCSID: $Header: psdit.pro,v 2.1 85/11/24 12:19:43 shore Rel $ + +/$DITroff 140 dict def $DITroff begin +/fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def +/xi {0 72 11 mul translate 72 resolution div dup neg scale 0 0 moveto + /fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def F + /pagesave save def}def +/PB{save /psv exch def currentpoint translate + resolution 72 div dup neg scale 0 0 moveto}def +/PE{psv restore}def +/arctoobig 90 def /arctoosmall .05 def +/m1 matrix def /m2 matrix def /m3 matrix def /oldmat matrix def +/tan{dup sin exch cos div}def +/point{resolution 72 div mul}def +/dround {transform round exch round exch itransform}def +/xT{/devname exch def}def +/xr{/mh exch def /my exch def /resolution exch def}def +/xp{}def +/xs{docsave restore end}def +/xt{}def +/xf{/fontname exch def /slotno exch def fontnames slotno get fontname eq not + {fonts slotno fontname findfont put fontnames slotno fontname put}if}def +/xH{/fontheight exch def F}def +/xS{/fontslant exch def F}def +/s{/fontsize exch def /fontheight fontsize def F}def +/f{/fontnum exch def F}def +/F{fontheight 0 le {/fontheight fontsize def}if + fonts fontnum get fontsize point 0 0 fontheight point neg 0 0 m1 astore + fontslant 0 ne{1 0 fontslant tan 1 0 0 m2 astore m3 concatmatrix}if + makefont setfont .04 fontsize point mul 0 dround pop setlinewidth}def +/X{exch currentpoint exch pop moveto show}def +/N{3 1 roll moveto show}def +/Y{exch currentpoint pop exch moveto show}def +/S{show}def +/ditpush{}def/ditpop{}def +/AX{3 -1 roll currentpoint exch pop moveto 0 exch ashow}def +/AN{4 2 roll moveto 0 exch ashow}def +/AY{3 -1 roll currentpoint pop exch moveto 0 exch ashow}def +/AS{0 exch ashow}def +/MX{currentpoint exch pop moveto}def +/MY{currentpoint pop exch moveto}def +/MXY{moveto}def +/cb{pop}def % action on unknown char -- nothing for now +/n{}def/w{}def +/p{pop showpage pagesave restore /pagesave save def}def +/abspoint{currentpoint exch pop add exch currentpoint pop add exch}def +/distance{dup mul exch dup mul add sqrt}def +/dstroke{currentpoint stroke moveto}def +/Dl{2 copy gsave rlineto stroke grestore rmoveto}def +/arcellipse{/diamv exch def /diamh exch def oldmat currentmatrix pop + currentpoint translate 1 diamv diamh div scale /rad diamh 2 div def + currentpoint exch rad add exch rad -180 180 arc oldmat setmatrix}def +/Dc{dup arcellipse dstroke}def +/De{arcellipse dstroke}def +/Da{/endv exch def /endh exch def /centerv exch def /centerh exch def + /cradius centerv centerv mul centerh centerh mul add sqrt def + /eradius endv endv mul endh endh mul add sqrt def + /endang endv endh atan def + /startang centerv neg centerh neg atan def + /sweep startang endang sub dup 0 lt{360 add}if def + sweep arctoobig gt + {/midang startang sweep 2 div sub def /midrad cradius eradius add 2 div def + /midh midang cos midrad mul def /midv midang sin midrad mul def + midh neg midv neg endh endv centerh centerv midh midv Da + currentpoint moveto Da} + {sweep arctoosmall ge + {/controldelt 1 sweep 2 div cos sub 3 sweep 2 div sin mul div 4 mul def + centerv neg controldelt mul centerh controldelt mul + endv neg controldelt mul centerh add endh add + endh controldelt mul centerv add endv add + centerh endh add centerv endv add rcurveto dstroke} + {centerh endh add centerv endv add rlineto dstroke}ifelse}ifelse}def + +/Barray 200 array def % 200 values in a wiggle +/D~{mark}def +/D~~{counttomark Barray exch 0 exch getinterval astore /Bcontrol exch def pop + /Blen Bcontrol length def Blen 4 ge Blen 2 mod 0 eq and + {Bcontrol 0 get Bcontrol 1 get abspoint /Ycont exch def /Xcont exch def + Bcontrol 0 2 copy get 2 mul put Bcontrol 1 2 copy get 2 mul put + Bcontrol Blen 2 sub 2 copy get 2 mul put + Bcontrol Blen 1 sub 2 copy get 2 mul put + /Ybi /Xbi currentpoint 3 1 roll def def 0 2 Blen 4 sub + {/i exch def + Bcontrol i get 3 div Bcontrol i 1 add get 3 div + Bcontrol i get 3 mul Bcontrol i 2 add get add 6 div + Bcontrol i 1 add get 3 mul Bcontrol i 3 add get add 6 div + /Xbi Xcont Bcontrol i 2 add get 2 div add def + /Ybi Ycont Bcontrol i 3 add get 2 div add def + /Xcont Xcont Bcontrol i 2 add get add def + /Ycont Ycont Bcontrol i 3 add get add def + Xbi currentpoint pop sub Ybi currentpoint exch pop sub rcurveto + }for dstroke}if}def +end +/ditstart{$DITroff begin + /nfonts 60 def % NFONTS makedev/ditroff dependent! + /fonts[nfonts{0}repeat]def + /fontnames[nfonts{()}repeat]def +/docsave save def +}def + +% character outcalls +/oc {/pswid exch def /cc exch def /name exch def + /ditwid pswid fontsize mul resolution mul 72000 div def + /ditsiz fontsize resolution mul 72 div def + ocprocs name known{ocprocs name get exec}{name cb} + ifelse}def +/fractm [.65 0 0 .6 0 0] def +/fraction + {/fden exch def /fnum exch def gsave /cf currentfont def + cf fractm makefont setfont 0 .3 dm 2 copy neg rmoveto + fnum show rmoveto currentfont cf setfont(\244)show setfont fden show + grestore ditwid 0 rmoveto} def +/oce {grestore ditwid 0 rmoveto}def +/dm {ditsiz mul}def +/ocprocs 50 dict def ocprocs begin +(14){(1)(4)fraction}def +(12){(1)(2)fraction}def +(34){(3)(4)fraction}def +(13){(1)(3)fraction}def +(23){(2)(3)fraction}def +(18){(1)(8)fraction}def +(38){(3)(8)fraction}def +(58){(5)(8)fraction}def +(78){(7)(8)fraction}def +(sr){gsave 0 .06 dm rmoveto(\326)show oce}def +(is){gsave 0 .15 dm rmoveto(\362)show oce}def +(->){gsave 0 .02 dm rmoveto(\256)show oce}def +(<-){gsave 0 .02 dm rmoveto(\254)show oce}def +(==){gsave 0 .05 dm rmoveto(\272)show oce}def +end + +% an attempt at a PostScript FONT to implement ditroff special chars +% this will enable us to +% cache the little buggers +% generate faster, more compact PS out of psdit +% confuse everyone (including myself)! +50 dict dup begin +/FontType 3 def +/FontName /DIThacks def +/FontMatrix [.001 0 0 .001 0 0] def +/FontBBox [-260 -260 900 900] def% a lie but ... +/Encoding 256 array def +0 1 255{Encoding exch /.notdef put}for +Encoding + dup 8#040/space put %space + dup 8#110/rc put %right ceil + dup 8#111/lt put %left top curl + dup 8#112/bv put %bold vert + dup 8#113/lk put %left mid curl + dup 8#114/lb put %left bot curl + dup 8#115/rt put %right top curl + dup 8#116/rk put %right mid curl + dup 8#117/rb put %right bot curl + dup 8#120/rf put %right floor + dup 8#121/lf put %left floor + dup 8#122/lc put %left ceil + dup 8#140/sq put %square + dup 8#141/bx put %box + dup 8#142/ci put %circle + dup 8#143/br put %box rule + dup 8#144/rn put %root extender + dup 8#145/vr put %vertical rule + dup 8#146/ob put %outline bullet + dup 8#147/bu put %bullet + dup 8#150/ru put %rule + dup 8#151/ul put %underline + pop +/DITfd 100 dict def +/BuildChar{0 begin + /cc exch def /fd exch def + /charname fd /Encoding get cc get def + /charwid fd /Metrics get charname get def + /charproc fd /CharProcs get charname get def + charwid 0 fd /FontBBox get aload pop setcachedevice + 2 setlinejoin 40 setlinewidth + newpath 0 0 moveto gsave charproc grestore + end}def +/BuildChar load 0 DITfd put +%/UniqueID 5 def +/CharProcs 50 dict def +CharProcs begin +/space{}def +/.notdef{}def +/ru{500 0 rls}def +/rn{0 840 moveto 500 0 rls}def +/vr{0 800 moveto 0 -770 rls}def +/bv{0 800 moveto 0 -1000 rls}def +/br{0 750 moveto 0 -1000 rls}def +/ul{0 -140 moveto 500 0 rls}def +/ob{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath stroke}def +/bu{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath fill}def +/sq{80 0 rmoveto currentpoint dround newpath moveto + 640 0 rlineto 0 640 rlineto -640 0 rlineto closepath stroke}def +/bx{80 0 rmoveto currentpoint dround newpath moveto + 640 0 rlineto 0 640 rlineto -640 0 rlineto closepath fill}def +/ci{500 360 rmoveto currentpoint newpath 333 0 360 arc + 50 setlinewidth stroke}def + +/lt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 add exch s4 a4p stroke}def +/lb{0 800 moveto 0 -550 rlineto currx -200 2cx s4 add exch s4 a4p stroke}def +/rt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 sub exch s4 a4p stroke}def +/rb{0 800 moveto 0 -500 rlineto currx -200 2cx s4 sub exch s4 a4p stroke}def +/lk{0 800 moveto 0 300 -300 300 s4 arcto pop pop 1000 sub + 0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def +/rk{0 800 moveto 0 300 s2 300 s4 arcto pop pop 1000 sub + 0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def +/lf{0 800 moveto 0 -1000 rlineto s4 0 rls}def +/rf{0 800 moveto 0 -1000 rlineto s4 neg 0 rls}def +/lc{0 -200 moveto 0 1000 rlineto s4 0 rls}def +/rc{0 -200 moveto 0 1000 rlineto s4 neg 0 rls}def +end + +/Metrics 50 dict def Metrics begin +/.notdef 0 def +/space 500 def +/ru 500 def +/br 0 def +/lt 416 def +/lb 416 def +/rt 416 def +/rb 416 def +/lk 416 def +/rk 416 def +/rc 416 def +/lc 416 def +/rf 416 def +/lf 416 def +/bv 416 def +/ob 350 def +/bu 350 def +/ci 750 def +/bx 750 def +/sq 750 def +/rn 500 def +/ul 500 def +/vr 0 def +end + +DITfd begin +/s2 500 def /s4 250 def /s3 333 def +/a4p{arcto pop pop pop pop}def +/2cx{2 copy exch}def +/rls{rlineto stroke}def +/currx{currentpoint pop}def +/dround{transform round exch round exch itransform} def +end +end +/DIThacks exch definefont pop +ditstart +(psc)xT +576 1 1 xr +1(Times-Roman)xf 1 f +2(Times-Italic)xf 2 f +3(Times-Bold)xf 3 f +4(Times-BoldItalic)xf 4 f +5(Helvetica)xf 5 f +6(Helvetica-Bold)xf 6 f +7(Courier)xf 7 f +8(Courier-Bold)xf 8 f +9(Symbol)xf 9 f +10(DIThacks)xf 10 f +10 s +1 f +xi +%%EndProlog + +%%Page: 1 1 +10 s 0 xH 0 xS 1 f +8 s +2 f +12 s +1778 672(sdbm)N +3 f +2004(\320)X +2124(Substitute)X +2563(DBM)X +2237 768(or)N +1331 864(Berkeley)N +2 f +1719(ndbm)X +3 f +1956(for)X +2103(Every)X +2373(UN*X)X +1 f +10 s +2628 832(1)N +3 f +12 s +2692 864(Made)N +2951(Simple)X +2 f +10 s +2041 1056(Ozan)N +2230(\(oz\))X +2375(Yigit)X +1 f +1658 1200(The)N +1803(Guild)X +2005(of)X +2092(PD)X +2214(Software)X +2524(Toolmakers)X +2000 1296(Toronto)N +2278(-)X +2325(Canada)X +1965 1488(oz@nexus.yorku.ca)N +2 f +555 1804(Implementation)N +1078(is)X +1151(the)X +1269(sincerest)X +1574(form)X +1745(of)X +1827(\257attery.)X +2094(\320)X +2185(L.)X +2269(Peter)X +2463(Deutsch)X +3 f +555 1996(A)N +633(The)X +786(Clone)X +1006(of)X +1093(the)X +2 f +1220(ndbm)X +3 f +1418(library)X +1 f +755 2120(The)N +903(sources)X +1167(accompanying)X +1658(this)X +1796(notice)X +2015(\320)X +2 f +2118(sdbm)X +1 f +2309(\320)X +2411(constitute)X +2744(the)X +2864(\256rst)X +3010(public)X +3232(release)X +3478(\(Dec.)X +3677(1990\))X +3886(of)X +3975(a)X +555 2216(complete)N +874(clone)X +1073(of)X +1165(the)X +1288(Berkeley)X +1603(UN*X)X +2 f +1842(ndbm)X +1 f +2045(library.)X +2304(The)X +2 f +2454(sdbm)X +1 f +2648(library)X +2887(is)X +2965(meant)X +3186(to)X +3273(clone)X +3472(the)X +3594(proven)X +3841(func-)X +555 2312(tionality)N +846(of)X +2 f +938(ndbm)X +1 f +1141(as)X +1233(closely)X +1485(as)X +1576(possible,)X +1882(including)X +2208(a)X +2268(few)X +2413(improvements.)X +2915(It)X +2988(is)X +3065(practical,)X +3386(easy)X +3553(to)X +3639(understand,)X +555 2408(and)N +691(compatible.)X +1107(The)X +2 f +1252(sdbm)X +1 f +1441(library)X +1675(is)X +1748(not)X +1870(derived)X +2131(from)X +2307(any)X +2443(licensed,)X +2746(proprietary)X +3123(or)X +3210(copyrighted)X +3613(software.)X +755 2532(The)N +2 f +910(sdbm)X +1 f +1109(implementation)X +1641(is)X +1723(based)X +1935(on)X +2044(a)X +2109(1978)X +2298(algorithm)X +2638([Lar78])X +2913(by)X +3022(P.-A.)X +3220(\(Paul\))X +3445(Larson)X +3697(known)X +3944(as)X +555 2628(``Dynamic)N +934(Hashing''.)X +1326(In)X +1424(the)X +1553(course)X +1794(of)X +1892(searching)X +2231(for)X +2355(a)X +2421(substitute)X +2757(for)X +2 f +2881(ndbm)X +1 f +3059(,)X +3109(I)X +3166(prototyped)X +3543(three)X +3734(different)X +555 2724(external-hashing)N +1119(algorithms)X +1490([Lar78,)X +1758(Fag79,)X +2007(Lit80])X +2236(and)X +2381(ultimately)X +2734(chose)X +2946(Larson's)X +3256(algorithm)X +3596(as)X +3692(a)X +3756(basis)X +3944(of)X +555 2820(the)N +2 f +680(sdbm)X +1 f +875(implementation.)X +1423(The)X +1574(Bell)X +1733(Labs)X +2 f +1915(dbm)X +1 f +2079(\(and)X +2248(therefore)X +2 f +2565(ndbm)X +1 f +2743(\))X +2796(is)X +2875(based)X +3084(on)X +3190(an)X +3292(algorithm)X +3629(invented)X +3931(by)X +555 2916(Ken)N +709(Thompson,)X +1091([Tho90,)X +1367(Tor87])X +1610(and)X +1746(predates)X +2034(Larson's)X +2335(work.)X +755 3040(The)N +2 f +903(sdbm)X +1 f +1095(programming)X +1553(interface)X +1857(is)X +1932(totally)X +2158(compatible)X +2536(with)X +2 f +2700(ndbm)X +1 f +2900(and)X +3038(includes)X +3327(a)X +3385(slight)X +3584(improvement)X +555 3136(in)N +641(database)X +942(initialization.)X +1410(It)X +1483(is)X +1560(also)X +1713(expected)X +2023(to)X +2109(be)X +2208(binary-compatible)X +2819(under)X +3025(most)X +3203(UN*X)X +3440(versions)X +3730(that)X +3873(sup-)X +555 3232(port)N +704(the)X +2 f +822(ndbm)X +1 f +1020(library.)X +755 3356(The)N +2 f +909(sdbm)X +1 f +1107(implementation)X +1638(shares)X +1868(the)X +1995(shortcomings)X +2455(of)X +2551(the)X +2 f +2678(ndbm)X +1 f +2885(library,)X +3148(as)X +3244(a)X +3309(side)X +3467(effect)X +3680(of)X +3775(various)X +555 3452(simpli\256cations)N +1046(to)X +1129(the)X +1248(original)X +1518(Larson)X +1762(algorithm.)X +2114(It)X +2183(does)X +2350(produce)X +2 f +2629(holes)X +1 f +2818(in)X +2900(the)X +3018(page)X +3190(\256le)X +3312(as)X +3399(it)X +3463(writes)X +3679(pages)X +3882(past)X +555 3548(the)N +680(end)X +823(of)X +917(\256le.)X +1066(\(Larson's)X +1400(paper)X +1605(include)X +1867(a)X +1929(clever)X +2152(solution)X +2435(to)X +2523(this)X +2664(problem)X +2957(that)X +3103(is)X +3182(a)X +3244(result)X +3448(of)X +3541(using)X +3740(the)X +3864(hash)X +555 3644(value)N +758(directly)X +1032(as)X +1128(a)X +1193(block)X +1400(address.\))X +1717(On)X +1844(the)X +1971(other)X +2165(hand,)X +2370(extensive)X +2702(tests)X +2873(seem)X +3067(to)X +3158(indicate)X +3441(that)X +2 f +3590(sdbm)X +1 f +3787(creates)X +555 3740(fewer)N +762(holes)X +954(in)X +1039(general,)X +1318(and)X +1456(the)X +1576(resulting)X +1878(page\256les)X +2185(are)X +2306(smaller.)X +2584(The)X +2 f +2731(sdbm)X +1 f +2922(implementation)X +3446(is)X +3521(also)X +3672(faster)X +3873(than)X +2 f +555 3836(ndbm)N +1 f +757(in)X +843(database)X +1144(creation.)X +1467(Unlike)X +1709(the)X +2 f +1831(ndbm)X +1 f +2009(,)X +2053(the)X +2 f +2175(sdbm)X +7 f +2396(store)X +1 f +2660(operation)X +2987(will)X +3134(not)X +3259(``wander)X +3573(away'')X +3820(trying)X +555 3932(to)N +642(split)X +804(its)X +904(data)X +1063(pages)X +1271(to)X +1358(insert)X +1561(a)X +1622(datum)X +1847(that)X +2 f +1992(cannot)X +1 f +2235(\(due)X +2403(to)X +2490(elaborate)X +2810(worst-case)X +3179(situations\))X +3537(be)X +3637(inserted.)X +3935(\(It)X +555 4028(will)N +699(fail)X +826(after)X +994(a)X +1050(pre-de\256ned)X +1436(number)X +1701(of)X +1788(attempts.\))X +3 f +555 4220(Important)N +931(Compatibility)X +1426(Warning)X +1 f +755 4344(The)N +2 f +904(sdbm)X +1 f +1097(and)X +2 f +1237(ndbm)X +1 f +1439(libraries)X +2 f +1726(cannot)X +1 f +1968(share)X +2162(databases:)X +2515(one)X +2654(cannot)X +2891(read)X +3053(the)X +3174(\(dir/pag\))X +3478(database)X +3778(created)X +555 4440(by)N +657(the)X +777(other.)X +984(This)X +1148(is)X +1222(due)X +1359(to)X +1442(the)X +1561(differences)X +1940(between)X +2229(the)X +2 f +2348(ndbm)X +1 f +2547(and)X +2 f +2684(sdbm)X +1 f +2874(algorithms)X +8 s +3216 4415(2)N +10 s +4440(,)Y +3289(and)X +3426(the)X +3545(hash)X +3713(functions)X +555 4536(used.)N +769(It)X +845(is)X +925(easy)X +1094(to)X +1182(convert)X +1449(between)X +1743(the)X +2 f +1867(dbm/ndbm)X +1 f +2231(databases)X +2565(and)X +2 f +2707(sdbm)X +1 f +2902(by)X +3008(ignoring)X +3305(the)X +3429(index)X +3633(completely:)X +555 4632(see)N +7 f +706(dbd)X +1 f +(,)S +7 f +918(dbu)X +1 f +1082(etc.)X +3 f +555 4852(Notice)N +794(of)X +881(Intellectual)X +1288(Property)X +2 f +555 4976(The)N +696(entire)X +1 f +904(sdbm)X +2 f +1118(library)X +1361(package,)X +1670(as)X +1762(authored)X +2072(by)X +2169(me,)X +1 f +2304(Ozan)X +2495(S.)X +2580(Yigit,)X +2 f +2785(is)X +2858(hereby)X +3097(placed)X +3331(in)X +3413(the)X +3531(public)X +3751(domain.)X +1 f +555 5072(As)N +670(such,)X +863(the)X +987(author)X +1218(is)X +1297(not)X +1425(responsible)X +1816(for)X +1936(the)X +2060(consequences)X +2528(of)X +2621(use)X +2754(of)X +2847(this)X +2988(software,)X +3310(no)X +3415(matter)X +3645(how)X +3808(awful,)X +555 5168(even)N +727(if)X +796(they)X +954(arise)X +1126(from)X +1302(defects)X +1550(in)X +1632(it.)X +1716(There)X +1924(is)X +1997(no)X +2097(expressed)X +2434(or)X +2521(implied)X +2785(warranty)X +3091(for)X +3205(the)X +2 f +3323(sdbm)X +1 f +3512(library.)X +8 s +10 f +555 5316(hhhhhhhhhhhhhhhhhh)N +6 s +1 f +635 5391(1)N +8 s +691 5410(UN*X)N +877(is)X +936(not)X +1034(a)X +1078(trademark)X +1352(of)X +1421(any)X +1529(\(dis\)organization.)X +6 s +635 5485(2)N +8 s +691 5504(Torek's)N +908(discussion)X +1194([Tor87])X +1411(indicates)X +1657(that)X +2 f +1772(dbm/ndbm)X +1 f +2061(implementations)X +2506(use)X +2609(the)X +2705(hash)X +2840(value)X +2996(to)X +3064(traverse)X +3283(the)X +3379(radix)X +3528(trie)X +3631(dif-)X +555 5584(ferently)N +772(than)X +2 f +901(sdbm)X +1 f +1055(and)X +1166(as)X +1238(a)X +1285(result,)X +1462(the)X +1559(page)X +1698(indexes)X +1912(are)X +2008(generated)X +2274(in)X +2 f +2343(different)X +1 f +2579(order.)X +2764(For)X +2872(more)X +3021(information,)X +3357(send)X +3492(e-mail)X +3673(to)X +555 5664(the)N +649(author.)X + +2 p +%%Page: 2 2 +8 s 0 xH 0 xS 1 f +10 s +2216 384(-)N +2263(2)X +2323(-)X +755 672(Since)N +971(the)X +2 f +1107(sdbm)X +1 f +1314(library)X +1566(package)X +1868(is)X +1959(in)X +2058(the)X +2193(public)X +2430(domain,)X +2727(this)X +2 f +2879(original)X +1 f +3173(release)X +3434(or)X +3538(any)X +3691(additional)X +555 768(public-domain)N +1045(releases)X +1323(of)X +1413(the)X +1534(modi\256ed)X +1841(original)X +2112(cannot)X +2348(possibly)X +2636(\(by)X +2765(de\256nition\))X +3120(be)X +3218(withheld)X +3520(from)X +3698(you.)X +3860(Also)X +555 864(by)N +659(de\256nition,)X +1009(You)X +1170(\(singular\))X +1505(have)X +1680(all)X +1783(the)X +1904(rights)X +2109(to)X +2194(this)X +2332(code)X +2507(\(including)X +2859(the)X +2980(right)X +3154(to)X +3239(sell)X +3373(without)X +3640(permission,)X +555 960(the)N +679(right)X +856(to)X +944(hoard)X +8 s +1127 935(3)N +10 s +1185 960(and)N +1327(the)X +1451(right)X +1628(to)X +1716(do)X +1821(other)X +2011(icky)X +2174(things)X +2394(as)X +2486(you)X +2631(see)X +2759(\256t\))X +2877(but)X +3004(those)X +3198(rights)X +3405(are)X +3529(also)X +3683(granted)X +3949(to)X +555 1056(everyone)N +870(else.)X +755 1180(Please)N +997(note)X +1172(that)X +1329(all)X +1446(previous)X +1759(distributions)X +2195(of)X +2298(this)X +2449(software)X +2762(contained)X +3110(a)X +3182(copyright)X +3525(\(which)X +3784(is)X +3873(now)X +555 1276(dropped\))N +868(to)X +953(protect)X +1199(its)X +1297(origins)X +1542(and)X +1681(its)X +1779(current)X +2030(public)X +2253(domain)X +2516(status)X +2721(against)X +2970(any)X +3108(possible)X +3392(claims)X +3623(and/or)X +3850(chal-)X +555 1372(lenges.)N +3 f +555 1564(Acknowledgments)N +1 f +755 1688(Many)N +966(people)X +1204(have)X +1380(been)X +1556(very)X +1723(helpful)X +1974(and)X +2114(supportive.)X +2515(A)X +2596(partial)X +2824(list)X +2944(would)X +3167(necessarily)X +3547(include)X +3806(Rayan)X +555 1784(Zacherissen)N +963(\(who)X +1152(contributed)X +1541(the)X +1663(man)X +1824(page,)X +2019(and)X +2158(also)X +2310(hacked)X +2561(a)X +2620(MMAP)X +2887(version)X +3146(of)X +2 f +3236(sdbm)X +1 f +3405(\),)X +3475(Arnold)X +3725(Robbins,)X +555 1880(Chris)N +763(Lewis,)X +1013(Bill)X +1166(Davidsen,)X +1523(Henry)X +1758(Spencer,)X +2071(Geoff)X +2293(Collyer,)X +2587(Rich)X +2772(Salz)X +2944(\(who)X +3143(got)X +3279(me)X +3411(started)X +3659(in)X +3755(the)X +3887(\256rst)X +555 1976(place\),)N +792(Johannes)X +1106(Ruschein)X +1424(\(who)X +1609(did)X +1731(the)X +1849(minix)X +2055(port\))X +2231(and)X +2367(David)X +2583(Tilbrook.)X +2903(I)X +2950(thank)X +3148(you)X +3288(all.)X +3 f +555 2168(Distribution)N +992(Manifest)X +1315(and)X +1463(Notes)X +1 f +555 2292(This)N +717(distribution)X +1105(of)X +2 f +1192(sdbm)X +1 f +1381(includes)X +1668(\(at)X +1773(least\))X +1967(the)X +2085(following:)X +7 f +747 2436(CHANGES)N +1323(change)X +1659(log)X +747 2532(README)N +1323(this)X +1563(file.)X +747 2628(biblio)N +1323(a)X +1419(small)X +1707(bibliography)X +2331(on)X +2475(external)X +2907(hashing)X +747 2724(dba.c)N +1323(a)X +1419(crude)X +1707(\(n/s\)dbm)X +2139(page)X +2379(file)X +2619(analyzer)X +747 2820(dbd.c)N +1323(a)X +1419(crude)X +1707(\(n/s\)dbm)X +2139(page)X +2379(file)X +2619(dumper)X +2955(\(for)X +3195(conversion\))X +747 2916(dbe.1)N +1323(man)X +1515(page)X +1755(for)X +1947(dbe.c)X +747 3012(dbe.c)N +1323(Janick's)X +1755(database)X +2187(editor)X +747 3108(dbm.c)N +1323(a)X +1419(dbm)X +1611(library)X +1995(emulation)X +2475(wrapper)X +2859(for)X +3051(ndbm/sdbm)X +747 3204(dbm.h)N +1323(header)X +1659(file)X +1899(for)X +2091(the)X +2283(above)X +747 3300(dbu.c)N +1323(a)X +1419(crude)X +1707(db)X +1851(management)X +2379(utility)X +747 3396(hash.c)N +1323(hashing)X +1707(function)X +747 3492(makefile)N +1323(guess.)X +747 3588(pair.c)N +1323(page-level)X +1851(routines)X +2283(\(posted)X +2667(earlier\))X +747 3684(pair.h)N +1323(header)X +1659(file)X +1899(for)X +2091(the)X +2283(above)X +747 3780(readme.ms)N +1323(troff)X +1611(source)X +1947(for)X +2139(the)X +2331(README)X +2667(file)X +747 3876(sdbm.3)N +1323(man)X +1515(page)X +747 3972(sdbm.c)N +1323(the)X +1515(real)X +1755(thing)X +747 4068(sdbm.h)N +1323(header)X +1659(file)X +1899(for)X +2091(the)X +2283(above)X +747 4164(tune.h)N +1323(place)X +1611(for)X +1803(tuning)X +2139(&)X +2235(portability)X +2811(thingies)X +747 4260(util.c)N +1323(miscellaneous)X +755 4432(dbu)N +1 f +924(is)X +1002(a)X +1063(simple)X +1301(database)X +1603(manipulation)X +2050(program)X +8 s +2322 4407(4)N +10 s +2379 4432(that)N +2524(tries)X +2687(to)X +2774(look)X +2941(like)X +3086(Bell)X +3244(Labs')X +7 f +3480(cbt)X +1 f +3649(utility.)X +3884(It)X +3958(is)X +555 4528(currently)N +867(incomplete)X +1245(in)X +1329(functionality.)X +1800(I)X +1849(use)X +7 f +2006(dbu)X +1 f +2172(to)X +2255(test)X +2387(out)X +2510(the)X +2629(routines:)X +2930(it)X +2995(takes)X +3181(\(from)X +3385(stdin\))X +3588(tab)X +3707(separated)X +555 4624(key/value)N +898(pairs)X +1085(for)X +1210(commands)X +1587(like)X +7 f +1765(build)X +1 f +2035(or)X +7 f +2160(insert)X +1 f +2478(or)X +2575(takes)X +2770(keys)X +2947(for)X +3071(commands)X +3448(like)X +7 f +3626(delete)X +1 f +3944(or)X +7 f +555 4720(look)N +1 f +(.)S +7 f +747 4864(dbu)N +939(<build|creat|look|insert|cat|delete>)X +2715(dbmfile)X +755 5036(dba)N +1 f +927(is)X +1008(a)X +1072(crude)X +1279(analyzer)X +1580(of)X +2 f +1675(dbm/sdbm/ndbm)X +1 f +2232(page)X +2412(\256les.)X +2593(It)X +2670(scans)X +2872(the)X +2998(entire)X +3209(page)X +3389(\256le,)X +3538(reporting)X +3859(page)X +555 5132(level)N +731(statistics,)X +1046(and)X +1182(totals)X +1375(at)X +1453(the)X +1571(end.)X +7 f +755 5256(dbd)N +1 f +925(is)X +1004(a)X +1066(crude)X +1271(dump)X +1479(program)X +1777(for)X +2 f +1897(dbm/ndbm/sdbm)X +1 f +2452(databases.)X +2806(It)X +2881(ignores)X +3143(the)X +3267(bitmap,)X +3534(and)X +3675(dumps)X +3913(the)X +555 5352(data)N +717(pages)X +928(in)X +1018(sequence.)X +1361(It)X +1437(can)X +1576(be)X +1679(used)X +1853(to)X +1942(create)X +2162(input)X +2353(for)X +2474(the)X +7 f +2627(dbu)X +1 f +2798(utility.)X +3055(Note)X +3238(that)X +7 f +3413(dbd)X +1 f +3584(will)X +3735(skip)X +3895(any)X +8 s +10 f +555 5432(hhhhhhhhhhhhhhhhhh)N +6 s +1 f +635 5507(3)N +8 s +691 5526(You)N +817(cannot)X +1003(really)X +1164(hoard)X +1325(something)X +1608(that)X +1720(is)X +1779(available)X +2025(to)X +2091(the)X +2185(public)X +2361(at)X +2423(large,)X +2582(but)X +2680(try)X +2767(if)X +2822(it)X +2874(makes)X +3053(you)X +3165(feel)X +3276(any)X +3384(better.)X +6 s +635 5601(4)N +8 s +691 5620(The)N +7 f +829(dbd)X +1 f +943(,)X +7 f +998(dba)X +1 f +1112(,)X +7 f +1167(dbu)X +1 f +1298(utilities)X +1508(are)X +1602(quick)X +1761(hacks)X +1923(and)X +2032(are)X +2126(not)X +2225(\256t)X +2295(for)X +2385(production)X +2678(use.)X +2795(They)X +2942(were)X +3081(developed)X +3359(late)X +3467(one)X +3575(night,)X +555 5700(just)N +664(to)X +730(test)X +835(out)X +2 f +933(sdbm)X +1 f +1068(,)X +1100(and)X +1208(convert)X +1415(some)X +1566(databases.)X + +3 p +%%Page: 3 3 +8 s 0 xH 0 xS 1 f +10 s +2216 384(-)N +2263(3)X +2323(-)X +555 672(NULLs)N +821(in)X +903(the)X +1021(key)X +1157(and)X +1293(data)X +1447(\256elds,)X +1660(thus)X +1813(is)X +1886(unsuitable)X +2235(to)X +2317(convert)X +2578(some)X +2767(peculiar)X +3046(databases)X +3374(that)X +3514(insist)X +3702(in)X +3784(includ-)X +555 768(ing)N +677(the)X +795(terminating)X +1184(null.)X +755 892(I)N +841(have)X +1052(also)X +1240(included)X +1575(a)X +1670(copy)X +1885(of)X +2011(the)X +7 f +2195(dbe)X +1 f +2397(\()X +2 f +2424(ndbm)X +1 f +2660(DataBase)X +3026(Editor\))X +3311(by)X +3449(Janick)X +3712(Bergeron)X +555 988([janick@bnr.ca])N +1098(for)X +1212(your)X +1379(pleasure.)X +1687(You)X +1845(may)X +2003(\256nd)X +2147(it)X +2211(more)X +2396(useful)X +2612(than)X +2770(the)X +2888(little)X +7 f +3082(dbu)X +1 f +3246(utility.)X +7 f +755 1112(dbm.[ch])N +1 f +1169(is)X +1252(a)X +2 f +1318(dbm)X +1 f +1486(library)X +1730(emulation)X +2079(on)X +2188(top)X +2319(of)X +2 f +2415(ndbm)X +1 f +2622(\(and)X +2794(hence)X +3011(suitable)X +3289(for)X +2 f +3412(sdbm)X +1 f +3581(\).)X +3657(Written)X +3931(by)X +555 1208(Robert)N +793(Elz.)X +755 1332(The)N +2 f +901(sdbm)X +1 f +1090(library)X +1324(has)X +1451(been)X +1623(around)X +1866(in)X +1948(beta)X +2102(test)X +2233(for)X +2347(quite)X +2527(a)X +2583(long)X +2745(time,)X +2927(and)X +3063(from)X +3239(whatever)X +3554(little)X +3720(feedback)X +555 1428(I)N +609(received)X +909(\(maybe)X +1177(no)X +1284(news)X +1476(is)X +1555(good)X +1741(news\),)X +1979(I)X +2032(believe)X +2290(it)X +2360(has)X +2493(been)X +2671(functioning)X +3066(without)X +3336(any)X +3478(signi\256cant)X +3837(prob-)X +555 1524(lems.)N +752(I)X +805(would,)X +1051(of)X +1144(course,)X +1400(appreciate)X +1757(all)X +1863(\256xes)X +2040(and/or)X +2271(improvements.)X +2774(Portability)X +3136(enhancements)X +3616(would)X +3841(espe-)X +555 1620(cially)N +753(be)X +849(useful.)X +3 f +555 1812(Implementation)N +1122(Issues)X +1 f +755 1936(Hash)N +944(functions:)X +1288(The)X +1437(algorithm)X +1772(behind)X +2 f +2014(sdbm)X +1 f +2207(implementation)X +2733(needs)X +2939(a)X +2998(good)X +3181(bit-scrambling)X +3671(hash)X +3841(func-)X +555 2032(tion)N +702(to)X +787(be)X +886(effective.)X +1211(I)X +1261(ran)X +1387(into)X +1534(a)X +1593(set)X +1705(of)X +1795(constants)X +2116(for)X +2233(a)X +2292(simple)X +2528(hash)X +2698(function)X +2988(that)X +3130(seem)X +3317(to)X +3401(help)X +2 f +3561(sdbm)X +1 f +3752(perform)X +555 2128(better)N +758(than)X +2 f +916(ndbm)X +1 f +1114(for)X +1228(various)X +1484(inputs:)X +7 f +747 2272(/*)N +795 2368(*)N +891(polynomial)X +1419(conversion)X +1947(ignoring)X +2379(overflows)X +795 2464(*)N +891(65599)X +1179(nice.)X +1467(65587)X +1755(even)X +1995(better.)X +795 2560(*/)N +747 2656(long)N +747 2752(dbm_hash\(char)N +1419(*str,)X +1707(int)X +1899(len\))X +2139({)X +939 2848(register)N +1371(unsigned)X +1803(long)X +2043(n)X +2139(=)X +2235(0;)X +939 3040(while)N +1227(\(len--\))X +1131 3136(n)N +1227(=)X +1323(n)X +1419(*)X +1515(65599)X +1803(+)X +1899(*str++;)X +939 3232(return)N +1275(n;)X +747 3328(})N +1 f +755 3500(There)N +975(may)X +1145(be)X +1253(better)X +1467(hash)X +1645(functions)X +1974(for)X +2099(the)X +2228(purposes)X +2544(of)X +2642(dynamic)X +2949(hashing.)X +3269(Try)X +3416(your)X +3594(favorite,)X +3895(and)X +555 3596(check)N +766(the)X +887(page\256le.)X +1184(If)X +1261(it)X +1328(contains)X +1618(too)X +1743(many)X +1944(pages)X +2150(with)X +2315(too)X +2440(many)X +2641(holes,)X +2853(\(in)X +2965(relation)X +3233(to)X +3318(this)X +3456(one)X +3595(for)X +3712(example\))X +555 3692(or)N +656(if)X +2 f +739(sdbm)X +1 f +942(simply)X +1193(stops)X +1391(working)X +1692(\(fails)X +1891(after)X +7 f +2101(SPLTMAX)X +1 f +2471(attempts)X +2776(to)X +2872(split\))X +3070(when)X +3278(you)X +3432(feed)X +3604(your)X +3784(NEWS)X +7 f +555 3788(history)N +1 f +912(\256le)X +1035(to)X +1118(it,)X +1203(you)X +1344(probably)X +1650(do)X +1751(not)X +1874(have)X +2047(a)X +2104(good)X +2285(hashing)X +2555(function.)X +2883(If)X +2958(you)X +3099(do)X +3200(better)X +3404(\(for)X +3545(different)X +3842(types)X +555 3884(of)N +642(input\),)X +873(I)X +920(would)X +1140(like)X +1280(to)X +1362(know)X +1560(about)X +1758(the)X +1876(function)X +2163(you)X +2303(use.)X +755 4008(Block)N +967(sizes:)X +1166(It)X +1236(seems)X +1453(\(from)X +1657(various)X +1914(tests)X +2077(on)X +2178(a)X +2235(few)X +2377(machines\))X +2727(that)X +2867(a)X +2923(page)X +3095(\256le)X +3217(block)X +3415(size)X +7 f +3588(PBLKSIZ)X +1 f +3944(of)X +555 4104(1024)N +738(is)X +814(by)X +917(far)X +1030(the)X +1150(best)X +1301(for)X +1417(performance,)X +1866(but)X +1990(this)X +2127(also)X +2278(happens)X +2563(to)X +2647(limit)X +2819(the)X +2939(size)X +3086(of)X +3175(a)X +3233(key/value)X +3567(pair.)X +3734(Depend-)X +555 4200(ing)N +681(on)X +785(your)X +956(needs,)X +1183(you)X +1327(may)X +1489(wish)X +1663(to)X +1748(increase)X +2035(the)X +2156(page)X +2331(size,)X +2499(and)X +2638(also)X +2790(adjust)X +7 f +3032(PAIRMAX)X +1 f +3391(\(the)X +3539(maximum)X +3886(size)X +555 4296(of)N +648(a)X +710(key/value)X +1048(pair)X +1199(allowed:)X +1501(should)X +1740(always)X +1989(be)X +2090(at)X +2173(least)X +2345(three)X +2531(words)X +2752(smaller)X +3013(than)X +7 f +3204(PBLKSIZ)X +1 f +(.\))S +3612(accordingly.)X +555 4392(The)N +706(system-wide)X +1137(version)X +1399(of)X +1492(the)X +1616(library)X +1856(should)X +2095(probably)X +2406(be)X +2508(con\256gured)X +2877(with)X +3044(1024)X +3229(\(distribution)X +3649(default\),)X +3944(as)X +555 4488(this)N +690(appears)X +956(to)X +1038(be)X +1134(suf\256cient)X +1452(for)X +1566(most)X +1741(common)X +2041(uses)X +2199(of)X +2 f +2286(sdbm)X +1 f +2455(.)X +3 f +555 4680(Portability)N +1 f +755 4804(This)N +917(package)X +1201(has)X +1328(been)X +1500(tested)X +1707(in)X +1789(many)X +1987(different)X +2284(UN*Xes)X +2585(even)X +2757(including)X +3079(minix,)X +3305(and)X +3441(appears)X +3707(to)X +3789(be)X +3885(rea-)X +555 4900(sonably)N +824(portable.)X +1127(This)X +1289(does)X +1456(not)X +1578(mean)X +1772(it)X +1836(will)X +1980(port)X +2129(easily)X +2336(to)X +2418(non-UN*X)X +2799(systems.)X +3 f +555 5092(Notes)N +767(and)X +915(Miscellaneous)X +1 f +755 5216(The)N +2 f +913(sdbm)X +1 f +1115(is)X +1201(not)X +1336(a)X +1405(very)X +1581(complicated)X +2006(package,)X +2323(at)X +2414(least)X +2594(not)X +2729(after)X +2910(you)X +3063(familiarize)X +3444(yourself)X +3739(with)X +3913(the)X +555 5312(literature)N +879(on)X +993(external)X +1286(hashing.)X +1589(There)X +1811(are)X +1944(other)X +2143(interesting)X +2514(algorithms)X +2889(in)X +2984(existence)X +3316(that)X +3469(ensure)X +3712(\(approxi-)X +555 5408(mately\))N +825(single-read)X +1207(access)X +1438(to)X +1525(a)X +1586(data)X +1745(value)X +1944(associated)X +2299(with)X +2466(any)X +2607(key.)X +2768(These)X +2984(are)X +3107(directory-less)X +3568(schemes)X +3864(such)X +555 5504(as)N +2 f +644(linear)X +857(hashing)X +1 f +1132([Lit80])X +1381(\(+)X +1475(Larson)X +1720(variations\),)X +2 f +2105(spiral)X +2313(storage)X +1 f +2575([Mar79])X +2865(or)X +2954(directory)X +3265(schemes)X +3558(such)X +3726(as)X +2 f +3814(exten-)X +555 5600(sible)N +731(hashing)X +1 f +1009([Fag79])X +1288(by)X +1393(Fagin)X +1600(et)X +1683(al.)X +1786(I)X +1838(do)X +1943(hope)X +2124(these)X +2314(sources)X +2579(provide)X +2848(a)X +2908(reasonable)X +3276(playground)X +3665(for)X +3783(experi-)X +555 5696(mentation)N +907(with)X +1081(other)X +1277(algorithms.)X +1690(See)X +1837(the)X +1966(June)X +2144(1988)X +2335(issue)X +2526(of)X +2624(ACM)X +2837(Computing)X +3227(Surveys)X +3516([Enb88])X +3810(for)X +3935(an)X +555 5792(excellent)N +865(overview)X +1184(of)X +1271(the)X +1389(\256eld.)X + +4 p +%%Page: 4 4 +10 s 0 xH 0 xS 1 f +2216 384(-)N +2263(4)X +2323(-)X +3 f +555 672(References)N +1 f +555 824([Lar78])N +875(P.-A.)X +1064(Larson,)X +1327(``Dynamic)X +1695(Hashing'',)X +2 f +2056(BIT)X +1 f +(,)S +2216(vol.)X +2378(18,)X +2518(pp.)X +2638(184-201,)X +2945(1978.)X +555 948([Tho90])N +875(Ken)X +1029(Thompson,)X +2 f +1411(private)X +1658(communication)X +1 f +2152(,)X +2192(Nov.)X +2370(1990)X +555 1072([Lit80])N +875(W.)X +992(Litwin,)X +1246(``)X +1321(Linear)X +1552(Hashing:)X +1862(A)X +1941(new)X +2096(tool)X +2261(for)X +2396(\256le)X +2539(and)X +2675(table)X +2851(addressing'',)X +2 f +3288(Proceedings)X +3709(of)X +3791(the)X +3909(6th)X +875 1168(Conference)N +1269(on)X +1373(Very)X +1548(Large)X +1782(Dabatases)X +2163(\(Montreal\))X +1 f +2515(,)X +2558(pp.)X +2701(212-223,)X +3031(Very)X +3215(Large)X +3426(Database)X +3744(Founda-)X +875 1264(tion,)N +1039(Saratoga,)X +1360(Calif.,)X +1580(1980.)X +555 1388([Fag79])N +875(R.)X +969(Fagin,)X +1192(J.)X +1284(Nievergelt,)X +1684(N.)X +1803(Pippinger,)X +2175(and)X +2332(H.)X +2451(R.)X +2544(Strong,)X +2797(``Extendible)X +3218(Hashing)X +3505(-)X +3552(A)X +3630(Fast)X +3783(Access)X +875 1484(Method)N +1144(for)X +1258(Dynamic)X +1572(Files'',)X +2 f +1821(ACM)X +2010(Trans.)X +2236(Database)X +2563(Syst.)X +1 f +2712(,)X +2752(vol.)X +2894(4,)X +2994(no.3,)X +3174(pp.)X +3294(315-344,)X +3601(Sept.)X +3783(1979.)X +555 1608([Wal84])N +875(Rich)X +1055(Wales,)X +1305(``Discussion)X +1739(of)X +1835("dbm")X +2072(data)X +2235(base)X +2406(system'',)X +2 f +2730(USENET)X +3051(newsgroup)X +3430(unix.wizards)X +1 f +3836(,)X +3884(Jan.)X +875 1704(1984.)N +555 1828([Tor87])N +875(Chris)X +1068(Torek,)X +1300(``Re:)X +1505(dbm.a)X +1743(and)X +1899(ndbm.a)X +2177(archives'',)X +2 f +2539(USENET)X +2852(newsgroup)X +3223(comp.unix)X +1 f +3555(,)X +3595(1987.)X +555 1952([Mar79])N +875(G.)X +974(N.)X +1073(Martin,)X +1332(``Spiral)X +1598(Storage:)X +1885(Incrementally)X +2371(Augmentable)X +2843(Hash)X +3048(Addressed)X +3427(Storage'',)X +2 f +3766(Techni-)X +875 2048(cal)N +993(Report)X +1231(#27)X +1 f +(,)S +1391(University)X +1749(of)X +1836(Varwick,)X +2153(Coventry,)X +2491(U.K.,)X +2687(1979.)X +555 2172([Enb88])N +875(R.)X +977(J.)X +1057(Enbody)X +1335(and)X +1480(H.)X +1586(C.)X +1687(Du,)X +1833(``Dynamic)X +2209(Hashing)X +2524(Schemes'',)X +2 f +2883(ACM)X +3080(Computing)X +3463(Surveys)X +1 f +3713(,)X +3761(vol.)X +3911(20,)X +875 2268(no.)N +995(2,)X +1075(pp.)X +1195(85-113,)X +1462(June)X +1629(1988.)X + +4 p +%%Trailer +xt + +xs diff --git a/ext/dbm/sdbm/sdbm.3 b/ext/dbm/sdbm/sdbm.3 new file mode 100644 index 0000000000..f0f2d07c84 --- /dev/null +++ b/ext/dbm/sdbm/sdbm.3 @@ -0,0 +1,290 @@ +.\" $Id: sdbm.3,v 1.2 90/12/13 13:00:57 oz Exp $ +.TH SDBM 3 "1 March 1990" +.SH NAME +sdbm, dbm_open, dbm_prep, dbm_close, dbm_fetch, dbm_store, dbm_delete, dbm_firstkey, dbm_nextkey, dbm_hash, dbm_rdonly, dbm_error, dbm_clearerr, dbm_dirfno, dbm_pagfno \- data base subroutines +.SH SYNOPSIS +.nf +.ft B +#include <sdbm.h> +.sp +typedef struct { + char *dptr; + int dsize; +} datum; +.sp +datum nullitem = { NULL, 0 }; +.sp +\s-1DBM\s0 *dbm_open(char *file, int flags, int mode) +.sp +\s-1DBM\s0 *dbm_prep(char *dirname, char *pagname, int flags, int mode) +.sp +void dbm_close(\s-1DBM\s0 *db) +.sp +datum dbm_fetch(\s-1DBM\s0 *db, key) +.sp +int dbm_store(\s-1DBM\s0 *db, datum key, datum val, int flags) +.sp +int dbm_delete(\s-1DBM\s0 *db, datum key) +.sp +datum dbm_firstkey(\s-1DBM\s0 *db) +.sp +datum dbm_nextkey(\s-1DBM\s0 *db) +.sp +long dbm_hash(char *string, int len) +.sp +int dbm_rdonly(\s-1DBM\s0 *db) +int dbm_error(\s-1DBM\s0 *db) +dbm_clearerr(\s-1DBM\s0 *db) +int dbm_dirfno(\s-1DBM\s0 *db) +int dbm_pagfno(\s-1DBM\s0 *db) +.ft R +.fi +.SH DESCRIPTION +.IX "database library" sdbm "" "\fLsdbm\fR" +.IX dbm_open "" "\fLdbm_open\fR \(em open \fLsdbm\fR database" +.IX dbm_prep "" "\fLdbm_prep\fR \(em prepare \fLsdbm\fR database" +.IX dbm_close "" "\fLdbm_close\fR \(em close \fLsdbm\fR routine" +.IX dbm_fetch "" "\fLdbm_fetch\fR \(em fetch \fLsdbm\fR database data" +.IX dbm_store "" "\fLdbm_store\fR \(em add data to \fLsdbm\fR database" +.IX dbm_delete "" "\fLdbm_delete\fR \(em remove data from \fLsdbm\fR database" +.IX dbm_firstkey "" "\fLdbm_firstkey\fR \(em access \fLsdbm\fR database" +.IX dbm_nextkey "" "\fLdbm_nextkey\fR \(em access \fLsdbm\fR database" +.IX dbm_hash "" "\fLdbm_hash\fR \(em string hash for \fLsdbm\fR database" +.IX dbm_rdonly "" "\fLdbm_rdonly\fR \(em return \fLsdbm\fR database read-only mode" +.IX dbm_error "" "\fLdbm_error\fR \(em return \fLsdbm\fR database error condition" +.IX dbm_clearerr "" "\fLdbm_clearerr\fR \(em clear \fLsdbm\fR database error condition" +.IX dbm_dirfno "" "\fLdbm_dirfno\fR \(em return \fLsdbm\fR database bitmap file descriptor" +.IX dbm_pagfno "" "\fLdbm_pagfno\fR \(em return \fLsdbm\fR database data file descriptor" +.IX "database functions \(em \fLsdbm\fR" dbm_open "" \fLdbm_open\fP +.IX "database functions \(em \fLsdbm\fR" dbm_prep "" \fLdbm_prep\fP +.IX "database functions \(em \fLsdbm\fR" dbm_close "" \fLdbm_close\fP +.IX "database functions \(em \fLsdbm\fR" dbm_fetch "" \fLdbm_fetch\fP +.IX "database functions \(em \fLsdbm\fR" dbm_store "" \fLdbm_store\fP +.IX "database functions \(em \fLsdbm\fR" dbm_delete "" \fLdbm_delete\fP +.IX "database functions \(em \fLsdbm\fR" dbm_firstkey "" \fLdbm_firstkey\fP +.IX "database functions \(em \fLsdbm\fR" dbm_nextkey "" \fLdbm_nextkey\fP +.IX "database functions \(em \fLsdbm\fR" dbm_rdonly "" \fLdbm_rdonly\fP +.IX "database functions \(em \fLsdbm\fR" dbm_error "" \fLdbm_error\fP +.IX "database functions \(em \fLsdbm\fR" dbm_clearerr "" \fLdbm_clearerr\fP +.IX "database functions \(em \fLsdbm\fR" dbm_dirfno "" \fLdbm_dirfno\fP +.IX "database functions \(em \fLsdbm\fR" dbm_pagfno "" \fLdbm_pagfno\fP +.LP +This package allows an application to maintain a mapping of <key,value> pairs +in disk files. This is not to be considered a real database system, but is +still useful in many simple applications built around fast retrieval of a data +value from a key. This implementation uses an external hashing scheme, +called Dynamic Hashing, as described by Per-Aake Larson in BIT 18 (1978) pp. +184-201. Retrieval of any item usually requires a single disk access. +The application interface is compatible with the +.IR ndbm (3) +library. +.LP +An +.B sdbm +database is kept in two files usually given the extensions +.B \.dir +and +.BR \.pag . +The +.B \.dir +file contains a bitmap representing a forest of binary hash trees, the leaves +of which indicate data pages in the +.B \.pag +file. +.LP +The application interface uses the +.B datum +structure to describe both +.I keys +and +.IR value s. +A +.B datum +specifies a byte sequence of +.I dsize +size pointed to by +.IR dptr . +If you use +.SM ASCII +strings as +.IR key s +or +.IR value s, +then you must decide whether or not to include the terminating +.SM NUL +byte which sometimes defines strings. Including it will require larger +database files, but it will be possible to get sensible output from a +.IR strings (1) +command applied to the data file. +.LP +In order to allow a process using this package to manipulate multiple +databases, the applications interface always requires a +.IR handle , +a +.BR "DBM *" , +to identify the database to be manipulated. Such a handle can be obtained +from the only routines that do not require it, namely +.BR dbm_open (\|) +or +.BR dbm_prep (\|). +Either of these will open or create the two necessary files. The +difference is that the latter allows explicitly naming the bitmap and data +files whereas +.BR dbm_open (\|) +will take a base file name and call +.BR dbm_prep (\|) +with the default extensions. +The +.I flags +and +.I mode +parameters are the same as for +.BR open (2). +.LP +To free the resources occupied while a database handle is active, call +.BR dbm_close (\|). +.LP +Given a handle, one can retrieve data associated with a key by using the +.BR dbm_fetch (\|) +routine, and associate data with a key by using the +.BR dbm_store (\|) +routine. +.LP +The values of the +.I flags +parameter for +.BR dbm_store (\|) +can be either +.BR \s-1DBM_INSERT\s0 , +which will not change an existing entry with the same key, or +.BR \s-1DBM_REPLACE\s0 , +which will replace an existing entry with the same key. +Keys are unique within the database. +.LP +To delete a key and its associated value use the +.BR dbm_delete (\|) +routine. +.LP +To retrieve every key in the database, use a loop like: +.sp +.nf +.ft B +for (key = dbm_firstkey(db); key.dptr != NULL; key = dbm_nextkey(db)) + ; +.ft R +.fi +.LP +The order of retrieval is unspecified. +.LP +If you determine that the performance of the database is inadequate or +you notice clustering or other effects that may be due to the hashing +algorithm used by this package, you can override it by supplying your +own +.BR dbm_hash (\|) +routine. Doing so will make the database unintelligable to any other +applications that do not use your specialized hash function. +.sp +.LP +The following macros are defined in the header file: +.IP +.BR dbm_rdonly (\|) +returns true if the database has been opened read\-only. +.IP +.BR dbm_error (\|) +returns true if an I/O error has occurred. +.IP +.BR dbm_clearerr (\|) +allows you to clear the error flag if you think you know what the error +was and insist on ignoring it. +.IP +.BR dbm_dirfno (\|) +returns the file descriptor associated with the bitmap file. +.IP +.BR dbm_pagfno (\|) +returns the file descriptor associated with the data file. +.SH SEE ALSO +.IR open (2). +.SH DIAGNOSTICS +Functions that return a +.B "DBM *" +handle will use +.SM NULL +to indicate an error. +Functions that return an +.B int +will use \-1 to indicate an error. The normal return value in that case is 0. +Functions that return a +.B datum +will return +.B nullitem +to indicate an error. +.LP +As a special case of +.BR dbm_store (\|), +if it is called with the +.B \s-1DBM_INSERT\s0 +flag and the key already exists in the database, the return value will be 1. +.LP +In general, if a function parameter is invalid, +.B errno +will be set to +.BR \s-1EINVAL\s0 . +If a write operation is requested on a read-only database, +.B errno +will be set to +.BR \s-1ENOPERM\s0 . +If a memory allocation (using +.IR malloc (3)) +failed, +.B errno +will be set to +.BR \s-1ENOMEM\s0 . +For I/O operation failures +.B errno +will contain the value set by the relevant failed system call, either +.IR read (2), +.IR write (2), +or +.IR lseek (2). +.SH AUTHOR +.IP "Ozan S. Yigit" (oz@nexus.yorku.ca) +.SH BUGS +The sum of key and value data sizes must not exceed +.B \s-1PAIRMAX\s0 +(1008 bytes). +.LP +The sum of the key and value data sizes where several keys hash to the +same value must fit within one bitmap page. +.LP +The +.B \.pag +file will contain holes, so its apparent size is larger than its contents. +When copied through the filesystem the holes will be filled. +.LP +The contents of +.B datum +values returned are in volatile storage. If you want to retain the values +pointed to, you must copy them immediately before another call to this package. +.LP +The only safe way for multiple processes to (read and) update a database at +the same time, is to implement a private locking scheme outside this package +and open and close the database between lock acquisitions. It is safe for +multiple processes to concurrently access a database read-only. +.SH APPLICATIONS PORTABILITY +For complete source code compatibility with the Berkeley Unix +.IR ndbm (3) +library, the +.B sdbm.h +header file should be installed in +.BR /usr/include/ndbm.h . +.LP +The +.B nullitem +data item, and the +.BR dbm_prep (\|), +.BR dbm_hash (\|), +.BR dbm_rdonly (\|), +.BR dbm_dirfno (\|), +and +.BR dbm_pagfno (\|) +functions are unique to this package. diff --git a/ext/dbm/sdbm/sdbm.c b/ext/dbm/sdbm/sdbm.c new file mode 100644 index 0000000000..d4ecdceb07 --- /dev/null +++ b/ext/dbm/sdbm/sdbm.c @@ -0,0 +1,524 @@ +/* + * sdbm - ndbm work-alike hashed database library + * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978). + * author: oz@nexus.yorku.ca + * status: public domain. + * + * core routines + */ + +#ifndef lint +static char rcsid[] = "$Id: sdbm.c,v 1.16 90/12/13 13:01:31 oz Exp $"; +#endif + +#include "sdbm.h" +#include "tune.h" +#include "pair.h" + +#include <sys/types.h> +#include <sys/stat.h> +#ifdef BSD42 +#include <sys/file.h> +#else +#include <fcntl.h> +#include <memory.h> +#endif +#include <errno.h> +#include <string.h> + +#ifdef __STDC__ +#include <stddef.h> +#endif + +#ifndef NULL +#define NULL 0 +#endif + +/* + * externals + */ +#ifndef sun +extern int errno; +#endif + +extern char *malloc proto((unsigned int)); +extern void free proto((void *)); +extern long lseek(); + +/* + * forward + */ +static int getdbit proto((DBM *, long)); +static int setdbit proto((DBM *, long)); +static int getpage proto((DBM *, long)); +static datum getnext proto((DBM *)); +static int makroom proto((DBM *, long, int)); + +/* + * useful macros + */ +#define bad(x) ((x).dptr == NULL || (x).dsize < 0) +#define exhash(item) sdbm_hash((item).dptr, (item).dsize) +#define ioerr(db) ((db)->flags |= DBM_IOERR) + +#define OFF_PAG(off) (long) (off) * PBLKSIZ +#define OFF_DIR(off) (long) (off) * DBLKSIZ + +static long masks[] = { + 000000000000, 000000000001, 000000000003, 000000000007, + 000000000017, 000000000037, 000000000077, 000000000177, + 000000000377, 000000000777, 000000001777, 000000003777, + 000000007777, 000000017777, 000000037777, 000000077777, + 000000177777, 000000377777, 000000777777, 000001777777, + 000003777777, 000007777777, 000017777777, 000037777777, + 000077777777, 000177777777, 000377777777, 000777777777, + 001777777777, 003777777777, 007777777777, 017777777777 +}; + +datum nullitem = {NULL, 0}; + +DBM * +sdbm_open(file, flags, mode) +register char *file; +register int flags; +register int mode; +{ + register DBM *db; + register char *dirname; + register char *pagname; + register int n; + + if (file == NULL || !*file) + return errno = EINVAL, (DBM *) NULL; +/* + * need space for two seperate filenames + */ + n = strlen(file) * 2 + strlen(DIRFEXT) + strlen(PAGFEXT) + 2; + + if ((dirname = malloc((unsigned) n)) == NULL) + return errno = ENOMEM, (DBM *) NULL; +/* + * build the file names + */ + dirname = strcat(strcpy(dirname, file), DIRFEXT); + pagname = strcpy(dirname + strlen(dirname) + 1, file); + pagname = strcat(pagname, PAGFEXT); + + db = sdbm_prep(dirname, pagname, flags, mode); + free((char *) dirname); + return db; +} + +DBM * +sdbm_prep(dirname, pagname, flags, mode) +char *dirname; +char *pagname; +int flags; +int mode; +{ + register DBM *db; + struct stat dstat; + + if ((db = (DBM *) malloc(sizeof(DBM))) == NULL) + return errno = ENOMEM, (DBM *) NULL; + + db->flags = 0; + db->hmask = 0; + db->blkptr = 0; + db->keyptr = 0; +/* + * adjust user flags so that WRONLY becomes RDWR, + * as required by this package. Also set our internal + * flag for RDONLY if needed. + */ + if (flags & O_WRONLY) + flags = (flags & ~O_WRONLY) | O_RDWR; + + else if ((flags & 03) == O_RDONLY) + db->flags = DBM_RDONLY; +/* + * open the files in sequence, and stat the dirfile. + * If we fail anywhere, undo everything, return NULL. + */ + if ((db->pagf = open(pagname, flags, mode)) > -1) { + if ((db->dirf = open(dirname, flags, mode)) > -1) { +/* + * need the dirfile size to establish max bit number. + */ + if (fstat(db->dirf, &dstat) == 0) { +/* + * zero size: either a fresh database, or one with a single, + * unsplit data page: dirpage is all zeros. + */ + db->dirbno = (!dstat.st_size) ? 0 : -1; + db->pagbno = -1; + db->maxbno = dstat.st_size * BYTESIZ; + + (void) memset(db->pagbuf, 0, PBLKSIZ); + (void) memset(db->dirbuf, 0, DBLKSIZ); + /* + * success + */ + return db; + } + (void) close(db->dirf); + } + (void) close(db->pagf); + } + free((char *) db); + return (DBM *) NULL; +} + +void +sdbm_close(db) +register DBM *db; +{ + if (db == NULL) + errno = EINVAL; + else { + (void) close(db->dirf); + (void) close(db->pagf); + free((char *) db); + } +} + +datum +sdbm_fetch(db, key) +register DBM *db; +datum key; +{ + if (db == NULL || bad(key)) + return errno = EINVAL, nullitem; + + if (getpage(db, exhash(key))) + return getpair(db->pagbuf, key); + + return ioerr(db), nullitem; +} + +int +sdbm_delete(db, key) +register DBM *db; +datum key; +{ + if (db == NULL || bad(key)) + return errno = EINVAL, -1; + if (sdbm_rdonly(db)) + return errno = EPERM, -1; + + if (getpage(db, exhash(key))) { + if (!delpair(db->pagbuf, key)) + return -1; +/* + * update the page file + */ + if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0 + || write(db->pagf, db->pagbuf, PBLKSIZ) < 0) + return ioerr(db), -1; + + return 0; + } + + return ioerr(db), -1; +} + +int +sdbm_store(db, key, val, flags) +register DBM *db; +datum key; +datum val; +int flags; +{ + int need; + register long hash; + + if (db == NULL || bad(key)) + return errno = EINVAL, -1; + if (sdbm_rdonly(db)) + return errno = EPERM, -1; + + need = key.dsize + val.dsize; +/* + * is the pair too big (or too small) for this database ?? + */ + if (need < 0 || need > PAIRMAX) + return errno = EINVAL, -1; + + if (getpage(db, (hash = exhash(key)))) { +/* + * if we need to replace, delete the key/data pair + * first. If it is not there, ignore. + */ + if (flags == DBM_REPLACE) + (void) delpair(db->pagbuf, key); +#ifdef SEEDUPS + else if (duppair(db->pagbuf, key)) + return 1; +#endif +/* + * if we do not have enough room, we have to split. + */ + if (!fitpair(db->pagbuf, need)) + if (!makroom(db, hash, need)) + return ioerr(db), -1; +/* + * we have enough room or split is successful. insert the key, + * and update the page file. + */ + (void) putpair(db->pagbuf, key, val); + + if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0 + || write(db->pagf, db->pagbuf, PBLKSIZ) < 0) + return ioerr(db), -1; + /* + * success + */ + return 0; + } + + return ioerr(db), -1; +} + +/* + * makroom - make room by splitting the overfull page + * this routine will attempt to make room for SPLTMAX times before + * giving up. + */ +static int +makroom(db, hash, need) +register DBM *db; +long hash; +int need; +{ + long newp; + char twin[PBLKSIZ]; + char *pag = db->pagbuf; + char *new = twin; + register int smax = SPLTMAX; + + do { +/* + * split the current page + */ + (void) splpage(pag, new, db->hmask + 1); +/* + * address of the new page + */ + newp = (hash & db->hmask) | (db->hmask + 1); + +/* + * write delay, read avoidence/cache shuffle: + * select the page for incoming pair: if key is to go to the new page, + * write out the previous one, and copy the new one over, thus making + * it the current page. If not, simply write the new page, and we are + * still looking at the page of interest. current page is not updated + * here, as sdbm_store will do so, after it inserts the incoming pair. + */ + if (hash & (db->hmask + 1)) { + if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0 + || write(db->pagf, db->pagbuf, PBLKSIZ) < 0) + return 0; + db->pagbno = newp; + (void) memcpy(pag, new, PBLKSIZ); + } + else if (lseek(db->pagf, OFF_PAG(newp), SEEK_SET) < 0 + || write(db->pagf, new, PBLKSIZ) < 0) + return 0; + + if (!setdbit(db, db->curbit)) + return 0; +/* + * see if we have enough room now + */ + if (fitpair(pag, need)) + return 1; +/* + * try again... update curbit and hmask as getpage would have + * done. because of our update of the current page, we do not + * need to read in anything. BUT we have to write the current + * [deferred] page out, as the window of failure is too great. + */ + db->curbit = 2 * db->curbit + + ((hash & (db->hmask + 1)) ? 2 : 1); + db->hmask |= db->hmask + 1; + + if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0 + || write(db->pagf, db->pagbuf, PBLKSIZ) < 0) + return 0; + + } while (--smax); +/* + * if we are here, this is real bad news. After SPLTMAX splits, + * we still cannot fit the key. say goodnight. + */ +#ifdef BADMESS + (void) write(2, "sdbm: cannot insert after SPLTMAX attempts.\n", 44); +#endif + return 0; + +} + +/* + * the following two routines will break if + * deletions aren't taken into account. (ndbm bug) + */ +datum +sdbm_firstkey(db) +register DBM *db; +{ + if (db == NULL) + return errno = EINVAL, nullitem; +/* + * start at page 0 + */ + if (lseek(db->pagf, OFF_PAG(0), SEEK_SET) < 0 + || read(db->pagf, db->pagbuf, PBLKSIZ) < 0) + return ioerr(db), nullitem; + db->pagbno = 0; + db->blkptr = 0; + db->keyptr = 0; + + return getnext(db); +} + +datum +sdbm_nextkey(db) +register DBM *db; +{ + if (db == NULL) + return errno = EINVAL, nullitem; + return getnext(db); +} + +/* + * all important binary trie traversal + */ +static int +getpage(db, hash) +register DBM *db; +register long hash; +{ + register int hbit; + register long dbit; + register long pagb; + + dbit = 0; + hbit = 0; + while (dbit < db->maxbno && getdbit(db, dbit)) + dbit = 2 * dbit + ((hash & (1 << hbit++)) ? 2 : 1); + + debug(("dbit: %d...", dbit)); + + db->curbit = dbit; + db->hmask = masks[hbit]; + + pagb = hash & db->hmask; +/* + * see if the block we need is already in memory. + * note: this lookaside cache has about 10% hit rate. + */ + if (pagb != db->pagbno) { +/* + * note: here, we assume a "hole" is read as 0s. + * if not, must zero pagbuf first. + */ + if (lseek(db->pagf, OFF_PAG(pagb), SEEK_SET) < 0 + || read(db->pagf, db->pagbuf, PBLKSIZ) < 0) + return 0; + if (!chkpage(db->pagbuf)) + return 0; + db->pagbno = pagb; + + debug(("pag read: %d\n", pagb)); + } + return 1; +} + +static int +getdbit(db, dbit) +register DBM *db; +register long dbit; +{ + register long c; + register long dirb; + + c = dbit / BYTESIZ; + dirb = c / DBLKSIZ; + + if (dirb != db->dirbno) { + if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0 + || read(db->dirf, db->dirbuf, DBLKSIZ) < 0) + return 0; + db->dirbno = dirb; + + debug(("dir read: %d\n", dirb)); + } + + return db->dirbuf[c % DBLKSIZ] & (1 << dbit % BYTESIZ); +} + +static int +setdbit(db, dbit) +register DBM *db; +register long dbit; +{ + register long c; + register long dirb; + + c = dbit / BYTESIZ; + dirb = c / DBLKSIZ; + + if (dirb != db->dirbno) { + if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0 + || read(db->dirf, db->dirbuf, DBLKSIZ) < 0) + return 0; + db->dirbno = dirb; + + debug(("dir read: %d\n", dirb)); + } + + db->dirbuf[c % DBLKSIZ] |= (1 << dbit % BYTESIZ); + + if (dbit >= db->maxbno) + db->maxbno += DBLKSIZ * BYTESIZ; + + if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0 + || write(db->dirf, db->dirbuf, DBLKSIZ) < 0) + return 0; + + return 1; +} + +/* + * getnext - get the next key in the page, and if done with + * the page, try the next page in sequence + */ +static datum +getnext(db) +register DBM *db; +{ + datum key; + + for (;;) { + db->keyptr++; + key = getnkey(db->pagbuf, db->keyptr); + if (key.dptr != NULL) + return key; +/* + * we either run out, or there is nothing on this page.. + * try the next one... If we lost our position on the + * file, we will have to seek. + */ + db->keyptr = 0; + if (db->pagbno != db->blkptr++) + if (lseek(db->pagf, OFF_PAG(db->blkptr), SEEK_SET) < 0) + break; + db->pagbno = db->blkptr; + if (read(db->pagf, db->pagbuf, PBLKSIZ) <= 0) + break; + if (!chkpage(db->pagbuf)) + break; + } + + return ioerr(db), nullitem; +} diff --git a/ext/dbm/sdbm/sdbm.h b/ext/dbm/sdbm/sdbm.h new file mode 100644 index 0000000000..e2fc762aab --- /dev/null +++ b/ext/dbm/sdbm/sdbm.h @@ -0,0 +1,91 @@ +/* + * sdbm - ndbm work-alike hashed database library + * based on Per-Ake Larson's Dynamic Hashing algorithms. BIT 18 (1978). + * author: oz@nexus.yorku.ca + * status: public domain. + */ +#define DBLKSIZ 4096 +#define PBLKSIZ 1024 +#define PAIRMAX 1008 /* arbitrary on PBLKSIZ-N */ +#define SPLTMAX 10 /* maximum allowed splits */ + /* for a single insertion */ +#define DIRFEXT ".dir" +#define PAGFEXT ".pag" + +typedef struct { + int dirf; /* directory file descriptor */ + int pagf; /* page file descriptor */ + int flags; /* status/error flags, see below */ + long maxbno; /* size of dirfile in bits */ + long curbit; /* current bit number */ + long hmask; /* current hash mask */ + long blkptr; /* current block for nextkey */ + int keyptr; /* current key for nextkey */ + long blkno; /* current page to read/write */ + long pagbno; /* current page in pagbuf */ + char pagbuf[PBLKSIZ]; /* page file block buffer */ + long dirbno; /* current block in dirbuf */ + char dirbuf[DBLKSIZ]; /* directory file block buffer */ +} DBM; + +#define DBM_RDONLY 0x1 /* data base open read-only */ +#define DBM_IOERR 0x2 /* data base I/O error */ + +/* + * utility macros + */ +#define sdbm_rdonly(db) ((db)->flags & DBM_RDONLY) +#define sdbm_error(db) ((db)->flags & DBM_IOERR) + +#define sdbm_clearerr(db) ((db)->flags &= ~DBM_IOERR) /* ouch */ + +#define sdbm_dirfno(db) ((db)->dirf) +#define sdbm_pagfno(db) ((db)->pagf) + +typedef struct { + char *dptr; + int dsize; +} datum; + +extern datum nullitem; + +#ifdef __STDC__ +#define proto(p) p +#else +#define proto(p) () +#endif + +/* + * flags to sdbm_store + */ +#define DBM_INSERT 0 +#define DBM_REPLACE 1 + +/* + * ndbm interface + */ +extern DBM *sdbm_open proto((char *, int, int)); +extern void sdbm_close proto((DBM *)); +extern datum sdbm_fetch proto((DBM *, datum)); +extern int sdbm_delete proto((DBM *, datum)); +extern int sdbm_store proto((DBM *, datum, datum, int)); +extern datum sdbm_firstkey proto((DBM *)); +extern datum sdbm_nextkey proto((DBM *)); + +/* + * other + */ +extern DBM *sdbm_prep proto((char *, char *, int, int)); +extern long sdbm_hash proto((char *, int)); + +#ifndef SDBM_ONLY +#define dbm_open sdbm_open; +#define dbm_close sdbm_close; +#define dbm_fetch sdbm_fetch; +#define dbm_store sdbm_store; +#define dbm_delete sdbm_delete; +#define dbm_firstkey sdbm_firstkey; +#define dbm_nextkey sdbm_nextkey; +#define dbm_error sdbm_error; +#define dbm_clearerr sdbm_clearerr; +#endif diff --git a/ext/dbm/sdbm/tune.h b/ext/dbm/sdbm/tune.h new file mode 100644 index 0000000000..9d8a35b90b --- /dev/null +++ b/ext/dbm/sdbm/tune.h @@ -0,0 +1,34 @@ +/* + * sdbm - ndbm work-alike hashed database library + * tuning and portability constructs [not nearly enough] + * author: oz@nexus.yorku.ca + */ + +#define BYTESIZ 8 + +#ifdef SVID +#include <unistd.h> +#endif + +#ifdef BSD42 +#define SEEK_SET L_SET +#define memset(s,c,n) bzero(s, n) /* only when c is zero */ +#define memcpy(s1,s2,n) bcopy(s2, s1, n) +#define memcmp(s1,s2,n) bcmp(s1,s2,n) +#endif + +/* + * important tuning parms (hah) + */ + +#define SEEDUPS /* always detect duplicates */ +#define BADMESS /* generate a message for worst case: + cannot make room after SPLTMAX splits */ +/* + * misc + */ +#ifdef DEBUG +#define debug(x) printf x +#else +#define debug(x) +#endif diff --git a/ext/dbm/sdbm/util.c b/ext/dbm/sdbm/util.c new file mode 100644 index 0000000000..4b03d89f09 --- /dev/null +++ b/ext/dbm/sdbm/util.c @@ -0,0 +1,50 @@ +#include <stdio.h> +#ifdef SDBM +#include "sdbm.h" +#else +#include "ndbm.h" +#endif + +void +oops(s1, s2) +register char *s1; +register char *s2; +{ + extern int errno, sys_nerr; + extern char *sys_errlist[]; + extern char *progname; + + if (progname) + fprintf(stderr, "%s: ", progname); + fprintf(stderr, s1, s2); + if (errno > 0 && errno < sys_nerr) + fprintf(stderr, " (%s)", sys_errlist[errno]); + fprintf(stderr, "\n"); + exit(1); +} + +int +okpage(pag) +char *pag; +{ + register unsigned n; + register off; + register short *ino = (short *) pag; + + if ((n = ino[0]) > PBLKSIZ / sizeof(short)) + return 0; + + if (!n) + return 1; + + off = PBLKSIZ; + for (ino++; n; ino += 2) { + if (ino[0] > off || ino[1] > off || + ino[1] > ino[0]) + return 0; + off = ino[1]; + n -= 2; + } + + return 1; +} |