summaryrefslogtreecommitdiff
path: root/ext/dbm
diff options
context:
space:
mode:
Diffstat (limited to 'ext/dbm')
-rw-r--r--ext/dbm/GDBM_File.c310
-rw-r--r--ext/dbm/GDBM_File.xs76
-rw-r--r--ext/dbm/GDBM_File.xs.bak122
-rw-r--r--ext/dbm/Makefile14
-rw-r--r--ext/dbm/NDBM_File.c267
-rw-r--r--ext/dbm/NDBM_File.xs58
-rw-r--r--ext/dbm/ODBM_File.c246
-rw-r--r--ext/dbm/ODBM_File.xs86
-rw-r--r--ext/dbm/SDBM_File.c266
-rw-r--r--ext/dbm/SDBM_File.xs57
-rw-r--r--ext/dbm/sdbm/.pure0
-rwxr-xr-xext/dbm/sdbm/.r5884
-rw-r--r--ext/dbm/sdbm/CHANGES18
-rw-r--r--ext/dbm/sdbm/COMPARE88
-rw-r--r--ext/dbm/sdbm/README396
-rw-r--r--ext/dbm/sdbm/README.too3
-rw-r--r--ext/dbm/sdbm/biblio64
-rw-r--r--ext/dbm/sdbm/dba.c84
-rw-r--r--ext/dbm/sdbm/dbd.c110
-rw-r--r--ext/dbm/sdbm/dbe.146
-rw-r--r--ext/dbm/sdbm/dbe.c435
-rw-r--r--ext/dbm/sdbm/dbm.c120
-rw-r--r--ext/dbm/sdbm/dbm.h33
-rw-r--r--ext/dbm/sdbm/dbu.c250
-rwxr-xr-xext/dbm/sdbm/grind9
-rw-r--r--ext/dbm/sdbm/hash.c47
-rw-r--r--ext/dbm/sdbm/linux.patches67
-rw-r--r--ext/dbm/sdbm/makefile55
-rw-r--r--ext/dbm/sdbm/pair.c308
-rw-r--r--ext/dbm/sdbm/pair.h10
-rw-r--r--ext/dbm/sdbm/readme.ms353
-rw-r--r--ext/dbm/sdbm/readme.ps2225
-rw-r--r--ext/dbm/sdbm/sdbm.3290
-rw-r--r--ext/dbm/sdbm/sdbm.c524
-rw-r--r--ext/dbm/sdbm/sdbm.h91
-rw-r--r--ext/dbm/sdbm/tune.h34
-rw-r--r--ext/dbm/sdbm/util.c50
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;
+}