[comp.sys.att] BSD stuff --> libndir and libdbm

jbm@uncle.UUCP (John B. Milton) (06/11/88)

I am looking for two collections of routines which are both, I believe, from
BSD. The first one is the directory reading routines that a lot of programs
use (cshar, vtree, etc.). This is usually a library called ndir. The other
one is a set of routines to do data base manager indexed files. This is
usually a library called dbm. I know there are little ones in news and rn,
but I want the whole thing.

Are there any other fun BSD libs I'm missing? Any other good c library stuff?

Both machines I use run SYSV. One is a UNIXpc (7300), the other is a Sperry
5000/90 (Arete' 1200).

If you have either of these, please send them to me and I will post to
unix-pc.sources

John
-- 
John Bly Milton IV, jbm@uncle.UUCP, {ihnp4|osu-cis}!n8emr!uncle!jbm
home: (614) 294-4823, work: (614) 459-7641; talk to me about fractals

lenny@icus.UUCP (Lenny Tropiano) (06/13/88)

In article <290@uncle.UUCP>, jbm@uncle.UUCP (John B. Milton) writes:
> I am looking for two collections of routines which are both, I believe, from
> BSD. The first one is the directory reading routines that a lot of programs
> use (cshar, vtree, etc.). This is usually a library called ndir. The other
> one is a set of routines to do data base manager indexed files. This is
> usually a library called dbm. I know there are little ones in news and rn,
> but I want the whole thing.
> 

I have the dirent routines that work fine with cshar...  As for dbm there
isn't really a FULL-IMPLEMENTATION available for the UNIX pc.  I've seen
dbz that works good with news... (so I've been told)

--- cut here --- --- cut here --- --- cut here --- --- cut here ---
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  INSTALL NOTES closedir.c directory.3c dirent.4 dirent.h
#   getdents.2 getdents.c Makefile opendir.c readdir.c rewinddir.c
#   seekdir.c sys._dir.h sys.dirent.h telldir.c testdir.c
# Wrapped by lenny@icus on Thu Feb 11 22:37:39 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f INSTALL -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"INSTALL\"
else
echo shar: Extracting \"INSTALL\" \(5490 characters\)
sed "s/^X//" >INSTALL <<'END_OF_INSTALL'
X
X
X			INSTALLATION INSTRUCTIONS
X
X
XThe following instructions are for systems resembling Ninth Edition UNIX, with
Xhints about dealing with variations you may encounter for your specific system.
XInstallation should be done only by someone who is comfortable with modifying
Xthe standard C library and header files.
X
XIf your system already includes directory access routines, you should replace
Xthem with this package.  We're trying to get this standardized; see the
Xdiscussion in the NOTES file.
X
XI have tried to make the source code as generic as possible, but if your system
Xpredates Seventh Edition UNIX you will have problems.
X
XDISCLAIMER:  Although I believe the code and procedures described here to be
Xcorrect, I make no warranty of any kind, and you are advised to perform your
Xown careful testing before making any substantial change like this to your
Xprogramming environment.
X
X
X0)  For antique systems that do not support C's "void" data type, edit the file
X    sys.dirent.h to add the following:
X
X	typedef int		void;	/* good enough for govt work */
X
X    If for some reason your <sys/types.h> doesn't define them, add the
X    following to sys.dirent.h:
X
X	typedef unsigned short	ino_t;	/* (assuming original UFS) */
X	typedef long		off_t;	/* long is forced by lseek() */
X
X    None of this should be necessary for any modern UNIX system.
X
X1)  Copy the file dirent.h to /usr/include/dirent.h and copy the file
X    sys.dirent.h to /usr/include/sys/dirent.h.  (The file sys._dir.h is also
X    provided for the BRL UNIX System V emulation for 4.nBSD.  That environment
X    uses different directory names for everything.)
X
X2)  Copy the file directory.3c to /usr/man/man3/directory.3 and copy the file
X    dirent.4 to /usr/man/man5/dirent.5; edit the new file
X    /usr/man/man3/directory.3 to change the "SEE ALSO" reference from dirent(4)
X    to dirent(5) and to change the 3C on the first line to 3; edit the new file
X    /usr/man/man5/dirent.5 to change the 4 on the first line to 5; then print
X    the manual pages via the command
X
X	man directory dirent
X
X    to see what the new routines are like.  (If you have a "catman" style of
X    on-line manual, adapt these instructions accordingly.  Manual entries are
X    kept in directories with other names on some systems such as UNIX System V.
X    On systems that already had a directory library documented in some other
X    manual entry, remove the superseded manual entry; if the description of the
X    native filesystem directory format found by "man dir" refers to a directory
X    library, modify it to simply refer to the entry for "dirent".)
X
X3)  Copy the files closedir.c, opendir.c, readdir.c, rewinddir.c, seekdir.c,
X    and telldir.c to the "gen" or "port/gen" subdirectory of your C library
X    source directory.  If you do not have a getdents() system call, copy the
X    file getdents.c to the "sys" or "port/sys" subdirectory and copy the file
X    getdents.2 to /usr/man/man2/getdents.2 (actually you may prefer to put this
X    file in section 3 and adjust the references in the other manual entries
X    accordingly; also adjust the references to dirent(4) to be to dirent(5) if
X    that's where the entry is).  Edit the C library Makefile(s) to include the
X    new object modules in the C library.  (See the comments at the beginning of
X    getdents.c for symbols that must be defined to configure getdents.c.)  Then
X    remake and reinstall the C library.  Alternatively, you can just compile
X    the new sources and insert their objects near the front of the C library
X    /lib/libc.a using the "ar" utility (seekdir.o should precede readdir.o,
X    which in turn should precede getdents.o).  On some systems you then need to
X    use the "ranlib" utility to update the archive symbol table.
X
X4)  After the C library has been updated, delete /usr/include/ndir.h or any
X    other header used with a previous directory library to prevent inadvertent
X    use of the superseded directory access interface.  Also delete any
X    corresponding library such as /usr/lib/libndir.a.
X
X5)  To verify installation, try compiling, linking, and running the program
X    testdir.c.  This program searches the current directory "." for each file
X    named as a program argument and prints `"FOO" found.' or `"FOO" not found.'
X    where FOO is of course replaced by the name being sought in the directory.
X    Try something like
X
X	cd /usr/bin			# a multi-block directory
X	WHEREVER/testdir FOO lint BAR f77 XYZZY
X
X    which should produce the output
X
X	"FOO" not found.
X	"lint" found.
X	"BAR" not found.
X	"f77" found.
X	"XYZZY" not found.
X
X    A more thorough test would be
X
X	cd /usr/bin			# a multi-block directory
X	WHEREVER/testdir `ls -a` | grep 'not found'
X
X    This program does not test the seekdir() and telldir() functions.
X
X6)  Notify your programmers that all directory access must be made through the
X    new interface, and that documentation is available via
X
X	man directory dirent
X
X    Make the NOTES file available to those programmers who might want to
X    understand what this is all about.
X
X7)  Change all system sources that were accessing directories to use the new
X    routines.  Nearly all such sources contain the line
X
X	#include <sys/dir.h>
X    or
X	#include <ndir.h>
X
X    so they should be easy to find.  (If you earlier removed some other header
X    file, that is, if this package superseded an earlier version of the
X    directory access library, look for its name too.  See the conversion
X    instructions in the NOTES file.)
END_OF_INSTALL
if test 5490 -ne `wc -c <INSTALL`; then
    echo shar: \"INSTALL\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f NOTES -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"NOTES\"
else
echo shar: Extracting \"NOTES\" \(5314 characters\)
sed "s/^X//" >NOTES <<'END_OF_NOTES'
X
X
XNOTES FOR NEARLY-POSIX-COMPATIBLE C LIBRARY DIRECTORY-ACCESS ROUTINES
X
X
XOlder UNIX C libraries lacked support for reading directories, so historically
Xprograms had knowledge of UNIX directory structure hard-coded into them.  When
XBerkeley changed the format of directories for 4.2BSD, it became necessary to
Xchange programs to work with the new structure.  Fortunately, Berkeley designed
Xa small set of directory access routines to encapsulate knowledge of the new
Xdirectory format so that user programs could deal with directory entries as an
Xabstract data type.  (Unfortunately, they didn't get it quite right.)  The
Xinterface to these routines was nearly independent of the particular
Ximplementation of directories on any given UNIX system; this has become a
Xparticularly important requirement with the advent of heterogeneous network
Xfilesystems such as NFS.
X
XIt has consequently become possible to write portable applications that search
Xdirectories by restricting all directory access to use these new interface
Xroutines.  The sources supplied here are a total rewrite of Berkeley's code,
Xincorporating ideas from a variety of sources and conforming as closely to
Xpublished standards as possible, and are in the PUBLIC DOMAIN to encourage
Xtheir widespread adoption.  They support four methods of access to system
Xdirectories: the original UNIX filesystem via read(), the 4.2BSD filesystem via
Xread(), NFS and native filesystems via getdirentries(), and SVR3 getdents().
XThe other three types are accomplished by appropriate emulation of the SVR3
Xgetdents() system call, which attains portability at the cost of slightly more
Xdata movement than absolutely necessary for some systems.  These routines
Xshould be added to the standard C library on all UNIX systems, and all existing
Xand future applications should be changed to use this interface.  Once this is
Xdone, there should be no portability problems due to differences in underlying
Xdirectory structures among UNIX systems.  (When porting your applications to
Xother UNIX systems, you can always carry this package around with you.)
X
XAn additional benefit of these routines is that they buffer directory input,
Xwhich provides improved access speed over raw read()s of one entry at a time.
X
XOne annoying compatibility problem has arisen along the way, namely that the
Xoriginal Berkeley interface used the same name, struct direct, for the new data
Xstructure as had been used for the original UNIX filesystem directory record
Xstructure.  This name was changed by the IEEE 1003.1 (POSIX) Working Group to
X"struct dirent" and was picked up for SVR3 under the new name; it is also the
Xname used in this portable package.  I believe it is necessary to bite the
Xbullet and adopt the new non-conflicting name.  Code using a 4.2BSD-compatible
Xpackage needs to be slightly revised to work with this new package, as follows:
X	Change
X		#include <ndir.h>	/* Ninth Edition UNIX */
X	or
X		#include <sys/dir.h>	/* 4.2BSD */
X	or
X		#include <dir.h>	/* BRL System V emulation */
X	to
X		#include <sys/types.h>	/* if not already #included */
X		#include <dirent.h>
X
X	Change
X		struct direct
X	to
X		struct dirent
X
X	Change
X		(anything)->d_namlen
X	to
X		strlen( (anything)->d_name )
X
XThere is a minor compatibility problem in that the closedir() function was
Xoriginally defined to have type void, but IEEE 1003.1 changed this to type int,
Xwhich is what this implementation supports (even though I disagree with the
Xchange).  However, the difference does not affect most applications.
X
XAnother minor problem is that IEEE 1003.1 defined the d_name member of a struct
Xdirent to be an array of maximum length; this does not permit use of compact
Xvariable-length entries directly from a directory block buffer.  This part of
Xthe specification is incompatible with efficient use of the getdents() system
Xcall, and I have therefore chosen to follow the SVID specification instead of
XIEEE 1003.1 (which I hope is changed for the final-use standard).  This
Xdeviation should have little or no impact on sensibly-coded applications, since
Xthe relevant d_name length is that given by strlen(), not the declared array
Xsize.
X
XError handling is not completely satisfactory, due to the variety of possible
Xfailure modes in a general setting.  For example, the rewinddir() function
Xmight fail, but there is no good way to indicate this.  I have tried to
Xfollow the specifications in IEEE 1003.1 and the SVID as closely as possible,
Xbut there are minor deviations in this regard.  Applications should not rely
Xtoo heavily on exact failure mode semantics.
X
XPlease do not change the new standard interface in any way, as that would
Xdefeat the major purpose of this package!  (It's okay to alter the internal
Ximplementation if you really have to, although I tried to make this unnecessary
Xfor the vast majority of UNIX variants.)
X
XInstallation instructions can be found in the file named INSTALL.
X
XThis implementation is provided by:
X
X	Douglas A. Gwyn
X	U.S. Army Ballistic Research Laboratory
X	SLCBR-VL-V
X	Aberdeen Proving Ground, MD 21005-5066
X
X	(301)278-6647
X
X	Gwyn@BRL.MIL or seismo!brl!gwyn
X
XThis is UNSUPPORTED, use-at-your-own-risk, free software in the public domain.
XHowever, I would appreciate hearing of any actual bugs you find in this
Ximplementation and/or any improvements you come up with.
END_OF_NOTES
if test 5314 -ne `wc -c <NOTES`; then
    echo shar: \"NOTES\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f closedir.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"closedir.c\"
else
echo shar: Extracting \"closedir.c\" \(568 characters\)
sed "s/^X//" >closedir.c <<'END_OF_closedir.c'
X/*
X	closedir -- close a directory stream
X
X	last edit:	25-Apr-1987	D A Gwyn
X*/
X
X#include	<sys/errno.h>
X#include	<sys/types.h>
X#include	<dirent.h>
X
Xtypedef char	*pointer;		/* (void *) if you have it */
X
Xextern void	free();
Xextern int	close();
X
Xextern int	errno;
X
X#ifndef NULL
X#define	NULL	0
X#endif
X
Xint
Xclosedir( dirp )
X	register DIR	*dirp;		/* stream from opendir() */
X	{
X	if ( dirp == NULL || dirp->dd_buf == NULL )
X		{
X		errno = EFAULT;
X		return -1;		/* invalid pointer */
X		}
X
X	free( (pointer)dirp->dd_buf );
X	free( (pointer)dirp );
X	return close( dirp->dd_fd );
X	}
END_OF_closedir.c
if test 568 -ne `wc -c <closedir.c`; then
    echo shar: \"closedir.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f directory.3c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"directory.3c\"
else
echo shar: Extracting \"directory.3c\" \(4136 characters\)
sed "s/^X//" >directory.3c <<'END_OF_directory.3c'
X.TH DIRECTORY 3C "Standard Extension"
X.SH NAME
Xopendir, readdir, telldir, seekdir, rewinddir, closedir \- directory operations
X.SH SYNOPSIS
X.B "#include <sys/types.h>"
X.br
X.B "#include <dirent.h>"
X.P
X.B "DIR \(**opendir (dirname)"
X.br
X.B "char \(**dirname;"
X.P
X.B "struct dirent \(**readdir (dirp)"
X.br
X.B "DIR \(**dirp;"
X.P
X.B "off_t telldir (dirp)"
X.br
X.B "DIR \(**dirp;"
X.P
X.B "void seekdir (dirp, loc)"
X.br
X.B "DIR \(**dirp;"
X.br
X.B "off_t loc;"
X.P
X.B "void rewinddir (dirp)"
X.br
X.B "DIR \(**dirp;"
X.P
X.B "int closedir (dirp)"
X.br
X.B "DIR \(**dirp;"
X.SH DESCRIPTION
X.I Opendir
Xestablishes a connection between
Xthe directory named by
X.I dirname
Xand a unique object of type
X.SM DIR
Xknown as a
X.I "directory stream"
Xthat it creates.
X.I Opendir
Xreturns a pointer to be used to identify the
Xdirectory stream
Xin subsequent operations.
XA
X.SM NULL
Xpointer is returned if
X.I dirname
Xcannot be accessed or is not a directory,
Xor if
X.I opendir
Xis unable to create the
X.SM DIR
Xobject
X(perhaps due to insufficient memory).
X.P
X.I Readdir
Xreturns a pointer to an internal structure
Xcontaining information about the next active directory entry.
XNo inactive entries are reported.
XThe internal structure may be overwritten by
Xanother operation on the same
Xdirectory stream;
Xthe amount of storage needed to hold a copy
Xof the internal structure is given by the value of a macro,
X.IR DIRENTSIZ(strlen(direntp\->d_name)) ,
Xnot by
X.I "sizeof(struct\ dirent)"
Xas one might expect.
XA
X.SM NULL
Xpointer is returned
Xupon reaching the end of the directory,
Xupon detecting an invalid location in the directory,
Xor upon occurrence of an error while reading the directory.
X.P
X.I Telldir
Xreturns the current position associated with the named
Xdirectory stream
Xfor later use as an argument to
X.IR seekdir .
X.P
X.I Seekdir
Xsets the position of the next
X.I readdir
Xoperation on the named
Xdirectory stream.
XThe new position reverts to the one associated with the
Xdirectory stream
Xwhen the
X.I telldir
Xoperation from which
X.I loc
Xwas obtained was performed.
X.P
X.I Rewinddir
Xresets the position of the named
Xdirectory stream
Xto the beginning of the directory.
XAll buffered data for the directory stream is discarded,
Xthereby guaranteeing that the actual
Xfile system directory will be referred to for the next
X.I readdir
Xon the
Xdirectory stream.
X.P
X.I Closedir
Xcloses the named
Xdirectory stream;
Xinternal resources used for the
Xdirectory stream are liberated,
Xand subsequent use of the associated
X.SM DIR
Xobject is no longer valid.
X.I Closedir
Xreturns a value of zero if no error occurs,
X\-1 otherwise.
X.P
XThere are several possible errors that can occur
Xas a result of these operations;
Xthe external integer variable
X.I errno
Xis set to indicate the specific error.
X.RI ( Readdir 's
Xdetection of the normal end of a directory
Xis not considered to be an error.)
X.SH EXAMPLE
XSample code which searches the current working directory for entry
X.IR name :
X.P
X.ft B
X	dirp = opendir( "." );
X.br
X	while ( (dp = readdir( dirp )) != NULL )
X.br
X		if ( strcmp( dp\->d_name, name ) == 0 )
X.br
X			{
X.br
X			(void) closedir( dirp );
X.br
X			return FOUND;
X.br
X			}
X.br
X	(void) closedir( dirp );
X.br
X	return NOT_FOUND;
X.ft P
X.SH "SEE ALSO"
Xgetdents(2), dirent(4).
X.SH WARNINGS
XEntries for "." and ".."
Xmay not be reported for some file system types.
X.P
XThe value returned by
X.I telldir
Xneed not have any simple interpretation
Xand should only be used as an argument to
X.IR seekdir .
XSimilarly,
Xthe
X.I loc
Xargument to
X.I seekdir
Xmust be obtained from a previous
X.I telldir
Xoperation on the same
Xdirectory stream.
X.P
X.I Telldir
Xand
X.I seekdir
Xare unreliable when used in conjunction with
Xfile systems that perform directory compaction or expansion
Xor when the directory stream has been closed and reopened.
XIt is best to avoid using
X.I telldir
Xand
X.I seekdir
Xaltogether.
X.P
XThe exact set of
X.I errno
Xvalues and meanings may vary among implementations.
X.P
XBecause directory entries can dynamically
Xappear and disappear,
Xand because directory contents are buffered
Xby these routines,
Xan application may need to continually rescan
Xa directory to maintain an accurate picture
Xof its active entries.
END_OF_directory.3c
if test 4136 -ne `wc -c <directory.3c`; then
    echo shar: \"directory.3c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f dirent.4 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"dirent.4\"
else
echo shar: Extracting \"dirent.4\" \(1593 characters\)
sed "s/^X//" >dirent.4 <<'END_OF_dirent.4'
X.TH DIRENT 4 "Standard Extension"
X.SH NAME
Xdirent \- file system independent directory entry
X.SH SYNOPSIS
X.B "#include <sys/types.h>"
X.br
X.B "#include <sys/dirent.h>"
X.SH DESCRIPTION
XDifferent file system types
Xmay have different directory entries.
XThe
X.I dirent
Xstructure defines a
Xfile system independent directory entry,
Xwhich contains information common to
Xdirectory entries in different file system types.
XA set of these structures is returned by the
X.IR getdents (2)
Xsystem call.
X.P
XThe
X.I dirent
Xstructure is defined below.
X.br
Xstruct	dirent	{
X.br
X			long			d_ino;
X.br
X			off_t			d_off;
X.br
X			unsigned short		d_reclen;
X.br
X			char			d_name[1];
X.br
X		};
X.P
XThe field
X.I d_ino
Xis a number which is unique
Xfor each file in the file system.
XThe field
X.I d_off\^
Xrepresents an offset of that directory entry
Xin the actual file system directory.
XThe field
X.I d_name
Xis the beginning of the character array
Xgiving the name of the directory entry.
XThis name is null terminated
Xand may have at most
X.SM NAME_MAX
Xcharacters in addition to the null terminator.
XThis results in file system independent directory entries
Xbeing variable-length entities.
XThe value of
X.I d_reclen
Xis the record length of this entry.
XThis length is defined to be the number of bytes
Xbetween the beginning of the current entry and the next one,
Xadjusted so that the next entry
Xwill start on a long boundary.
X.SH FILES
X/usr/include/sys/dirent.h
X.SH "SEE ALSO"
Xgetdents(2).
X.SH WARNING
XThe field
X.I d_off\^
Xdoes not have a simple interpretation
Xfor some file system types
Xand should not be used directly by applications.
END_OF_dirent.4
if test 1593 -ne `wc -c <dirent.4`; then
    echo shar: \"dirent.4\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f dirent.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"dirent.h\"
else
echo shar: Extracting \"dirent.h\" \(730 characters\)
sed "s/^X//" >dirent.h <<'END_OF_dirent.h'
X/*
X	<dirent.h> -- definitions for SVR3 directory access routines
X
X	last edit:	25-Apr-1987	D A Gwyn
X
X	Prerequisite:	<sys/types.h>
X*/
X
X#include	<sys/dirent.h>
X
X#define	DIRBUF		8192		/* buffer size for fs-indep. dirs */
X	/* must in general be larger than the filesystem buffer size */
X
Xtypedef struct
X	{
X	int	dd_fd;			/* file descriptor */
X	int	dd_loc;			/* offset in block */
X	int	dd_size;		/* amount of valid data */
X	char	*dd_buf;		/* -> directory block */
X	}	DIR;			/* stream data from opendir() */
X
Xextern DIR		*opendir();
Xextern struct dirent	*readdir();
Xextern off_t		telldir();
Xextern void		seekdir();
Xextern void		rewinddir();
Xextern int		closedir();
X
X#ifndef NULL
X#define	NULL	0			/* DAG -- added for convenience */
X#endif
END_OF_dirent.h
if test 730 -ne `wc -c <dirent.h`; then
    echo shar: \"dirent.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f getdents.2 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"getdents.2\"
else
echo shar: Extracting \"getdents.2\" \(1922 characters\)
sed "s/^X//" >getdents.2 <<'END_OF_getdents.2'
X.TH GETDENTS 2 "Standard Extension"
X.SH NAME
Xgetdents \- get directory entries in a file system independent format
X.SH SYNOPSIS
X.B "#include <sys/types.h>"
X.br
X.B "#include <sys/dirent.h>"
X.P
X.B "int getdents (fildes, buf, nbyte)"
X.br
X.B "int fildes;"
X.br
X.B "char \(**buf;"
X.br
X.B "unsigned nbyte;"
X.SH DESCRIPTION
X.I Fildes
Xis a file descriptor obtained from an
X.IR open (2)
Xor
X.IR dup (2)
Xsystem call.
X.P
X.I Getdents
Xattempts to read
X.I nbyte
Xbytes from the directory associated with
X.I fildes
Xand to format them as
Xfile system independent entries
Xin the buffer pointed to by
X.IR buf .
XSince the file system independent directory entries
Xare of variable length,
Xin most cases the actual number of bytes returned
Xwill be less than
X.IR nbyte .
X.P
XThe file system independent directory entry is specified by the
X.I dirent
Xstructure.
XFor a description of this see
X.IR dirent (4).
X.P
XOn devices capable of seeking,
X.I getdents
Xstarts at a position in the file given by
Xthe file pointer associated with
X.IR fildes .
XUpon return from
X.IR getdents ,
Xthe file pointer has been incremented
Xto point to the next directory entry.
X.P
XThis system call was developed in order to implement the
X.I readdir
Xroutine
X[for a description see
X.IR directory (3C)]
Xand should not be used for other purposes.
X.SH "SEE ALSO"
Xdirectory(3C), dirent(4).
X.SH DIAGNOSTICS
XUpon successful completion
Xa non-negative integer is returned
Xindicating the number of bytes of
X.I buf\^
Xactually filled.
X(This need not be the number actually used
Xin the actual directory file.)\|\|
XA value of zero
Xindicates the end of the directory has been reached.
XIf
X.I getdents
Xfails for any other reason,
Xa value of \-1 is returned and
Xthe external integer variable
X.I errno
Xis set to indicate the error.
X.SH WARNINGS
XEntries for "." and ".."
Xmay not be reported for some file system types.
X.P
XThe exact set of
X.I errno
Xvalues and meanings may vary among implementations.
END_OF_getdents.2
if test 1922 -ne `wc -c <getdents.2`; then
    echo shar: \"getdents.2\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f getdents.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"getdents.c\"
else
echo shar: Extracting \"getdents.c\" \(6436 characters\)
sed "s/^X//" >getdents.c <<'END_OF_getdents.c'
X/*
X	getdents -- get directory entries in a file system independent format
X			(SVR3 system call emulation)
X
X	last edit:	25-Apr-1987	D A Gwyn
X
X	This single source file supports several different methods of
X	getting directory entries from the operating system.  Define
X	whichever one of the following describes your system:
X
X	UFS	original UNIX filesystem (14-character name limit)
X	BFS	4.2BSD (also 4.3BSD) native filesystem (long names)
X	NFS	getdirentries() system call
X
X	Also define any of the following that are pertinent:
X
X	BRL	BRL UNIX System V emulation environment on 4.nBSD
X	UNK	have _getdents() system call, but kernel may not support it
X
X	If your C library has a getdents() system call interface, but you
X	can't count on all kernels on which your application binaries may
X	run to support it, change the system call interface name to
X	_getdents() and define "UNK" to enable the system-call validity
X	test in this "wrapper" around _getdents().
X
X	If your system has a getdents() system call that is guaranteed 
X	to always work, you shouldn't be using this source file at all.
X*/
X
X#define UFS
X
X
X#include	<sys/errno.h>
X#include	<sys/types.h>
X#ifdef BRL
X#include	<sys/_dir.h>		/* BSD flavor, not System V */
X#else
X#include	<sys/dir.h>
X#undef	MAXNAMLEN			/* avoid conflict with SVR3 */
X	/* Good thing we don't need to use the DIRSIZ() macro! */
X#ifdef d_ino				/* 4.3BSD/NFS using d_fileno */
X#undef	d_ino				/* (not absolutely necessary) */
X#else
X#define	d_fileno	d_ino		/* (struct direct) member */
X#endif
X#endif
X#include	<sys/dirent.h>
X#include	<sys/stat.h>
X#ifdef UNK
X#ifndef UFS
X#include "***** ERROR ***** UNK applies only to UFS"
X/* One could do something similar for getdirentries(), but I didn't bother. */
X#endif
X#include	<signal.h>
X#endif
X
X#if defined(UFS) + defined(BFS) + defined(NFS) != 1	/* sanity check */
X#include "***** ERROR ***** exactly one of UFS, BFS, or NFS must be defined"
X#endif
X
X#ifdef UFS
X#define	RecLen( dp )	(sizeof(struct direct))	/* fixed-length entries */
X#else	/* BFS || NFS */
X#define	RecLen( dp )	((dp)->d_reclen)	/* variable-length entries */
X#endif
X
X#ifdef NFS
X#ifdef BRL
X#define	getdirentries	_getdirentries	/* package hides this system call */
X#endif
Xextern int	getdirentries();
Xstatic long	dummy;			/* getdirentries() needs basep */
X#define	GetBlock( fd, buf, n )	getdirentries( fd, buf, (unsigned)n, &dummy )
X#else	/* UFS || BFS */
X#ifdef BRL
X#define read	_read			/* avoid emulation overhead */
X#endif
Xextern int	read();
X#define	GetBlock( fd, buf, n )	read( fd, buf, (unsigned)n )
X#endif
X
X#ifdef UNK
Xextern int	_getdents();		/* actual system call */
X#endif
X
Xextern char	*strncpy();
Xextern int	fstat(), strlen();
Xextern off_t	lseek();
X
Xextern int	errno;
X
X#ifndef DIRBLKSIZ
X#define	DIRBLKSIZ	4096		/* directory file read buffer size */
X#endif
X
X#ifndef NULL
X#define	NULL	0
X#endif
X
X#ifndef SEEK_CUR
X#define	SEEK_CUR	1
X#endif
X
X#ifndef S_ISDIR				/* macro to test for directory file */
X#define	S_ISDIR( mode )		(((mode) & S_IFMT) == S_IFDIR)
X#endif
X
X#ifdef UNK
Xstatic enum	{ maybe, no, yes }	state = maybe;
X					/* does _getdents() work? */
X
X/*ARGSUSED*/
Xstatic void
Xsig_catch( sig )
X	int	sig;			/* must be SIGSYS */
X	{
X	state = no;			/* attempted _getdents() faulted */
X	}
X#endif
X
Xint
Xgetdents( fildes, buf, nbyte )		/* returns # bytes read;
X					   0 on EOF, -1 on error */
X	int			fildes;	/* directory file descriptor */
X	char			*buf;	/* where to put the (struct dirent)s */
X	unsigned		nbyte;	/* size of buf[] */
X	{
X	int			serrno;	/* entry errno */
X	off_t			offset;	/* initial directory file offset */
X	struct stat		statb;	/* fstat() info */
X	union	{
X		char		dblk[DIRBLKSIZ];
X					/* directory file block buffer */
X		struct direct	dummy;	/* just for alignment */
X		}	u;		/* (avoids having to malloc()) */
X	register struct direct	*dp;	/* -> u.dblk[.] */
X	register struct dirent	*bp;	/* -> buf[.] */
X
X#ifdef UNK
X	switch ( state )
X		{
X		void		(*shdlr)();	/* entry SIGSYS handler */
X		register int	retval;	/* return from _getdents() if any */
X
X	case yes:			/* _getdents() is known to work */
X		return _getdents( fildes, buf, nbyte );
X
X	case maybe:			/* first time only */
X		shdlr = signal( SIGSYS, sig_catch );
X		retval = _getdents( fildes, buf, nbyte );	/* try it */
X		(void)signal( SIGSYS, shdlr );
X
X		if ( state == maybe )	/* SIGSYS did not occur */
X			{
X			state = yes;	/* so _getdents() must have worked */
X			return retval;
X			}
X		/* else fall through into emulation */
X
X/*	case no:	/* fall through into emulation */
X		}
X#endif
X
X	if ( buf == NULL || (unsigned long)buf % sizeof(long) != 0 /* ugh */ )
X		{
X		errno = EFAULT;		/* invalid pointer */
X		return -1;
X		}
X
X	if ( fstat( fildes, &statb ) != 0 )
X		return -1;		/* errno set by fstat() */
X
X	if ( !S_ISDIR( statb.st_mode ) )
X		{
X		errno = ENOTDIR;	/* not a directory */
X		return -1;
X		}
X
X	if ( (offset = lseek( fildes, (off_t)0, SEEK_CUR )) < 0 )
X		return -1;		/* errno set by lseek() */
X
X#ifdef BFS				/* no telling what remote hosts do */
X	if ( (unsigned long)offset % DIRBLKSIZ != 0 )
X		{
X		errno = ENOENT;		/* file pointer probably misaligned */
X		return -1;
X		}
X#endif
X
X	serrno = errno;			/* save entry errno */
X
X	for ( bp = (struct dirent *)buf; bp == (struct dirent *)buf; )
X		{			/* convert next directory block */
X		int	size;
X
X		do	size = GetBlock( fildes, u.dblk, DIRBLKSIZ );
X		while ( size == -1 && errno == EINTR );
X
X		if ( size <= 0 )
X			return size;	/* EOF or error (EBADF) */
X
X		for ( dp = (struct direct *)u.dblk;
X		      (char *)dp < &u.dblk[size];
X		      dp = (struct direct *)((char *)dp + RecLen( dp ))
X		    )	{
X#ifndef UFS
X			if ( dp->d_reclen <= 0 )
X				{
X				errno = EIO;	/* corrupted directory */
X				return -1;
X				}
X#endif
X
X			if ( dp->d_fileno != 0 )
X				{	/* non-empty; copy to user buffer */
X				register int	reclen =
X					DIRENTSIZ( strlen( dp->d_name ) );
X
X				if ( (char *)bp + reclen > &buf[nbyte] )
X					{
X					errno = EINVAL;
X					return -1;	/* buf too small */
X					}
X
X				bp->d_ino = dp->d_fileno;
X				bp->d_off = offset + ((char *)dp - u.dblk);
X				bp->d_reclen = reclen;
X				(void)strncpy( bp->d_name, dp->d_name,
X					       reclen - DIRENTBASESIZ
X					     );	/* adds NUL padding */
X#ifdef UFS
X				bp -> d_name[14] = '\0';
X#endif
X
X				bp = (struct dirent *)((char *)bp + reclen);
X				}
X			}
X
X		if ( (char *)dp > &u.dblk[size] )
X			{
X			errno = EIO;	/* corrupted directory */
X			return -1;
X			}
X		}
X
X	errno = serrno;			/* restore entry errno */
X	return (char *)bp - buf;	/* return # bytes read */
X	}
END_OF_getdents.c
if test 6436 -ne `wc -c <getdents.c`; then
    echo shar: \"getdents.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(1276 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
Xtest:	testdir
X	testdir *
X
Xtestdir:	testdir.c dirent.h sys.dirent.h libdirent.a
X	cc -O testdir.c -o testdir libdirent.a
X
Xlibdirent.a:	closedir.o getdents.o opendir.o readdir.o rewinddir.o \
X		seekdir.o telldir.o
X	rm -f libdirent.a
X	ar crv libdirent.a closedir.o getdents.o opendir.o readdir.o \
X		rewinddir.o seekdir.o telldir.o
X
Xclosedir.o:	closedir.c	dirent.h	sys.dirent.h
Xgetdents.o:	getdents.c	sys.dirent.h
Xopendir.o:	opendir.c	dirent.h	sys.dirent.h
Xreaddir.o:	readdir.c	dirent.h	sys.dirent.h
Xrewinddir.o:	rewinddir.c	dirent.h	sys.dirent.h
Xseekdir.o:	seekdir.c	dirent.h	sys.dirent.h
Xtelldir.o:	telldir.c	dirent.h	sys.dirent.h
X
X
Xclean:
X	rm -f *.E[BC]K *.o testdir
X	
Xclobber:	clean
X	rm -f *.a
X
Xinstall:	libdirent.a dirent.h sys.dirent.h
X	-mv /usr/include/dirent.h /usr/include/odirent.h
X	cp dirent.h /usr/include/dirent.h
X	chmod 444 /usr/include/dirent.h
X	-chown local /usr/include/dirent.h
X	-chgrp pd /usr/include/dirent.h
X	-mv /usr/include/sys/dirent.h /usr/include/sys/odirent.h
X	cp sys.dirent.h /usr/include/sys/dirent.h
X	chmod 444 /usr/include/sys/dirent.h
X	-chown local /usr/include/sys/dirent.h
X	-chgrp pd /usr/include/sys/dirent.h
X	cp libdirent.a /usr/lib/libdirent.a
X	chmod 444 /usr/lib/libdirent.a
X	-chown local /usr/lib/libdirent.a
X	-chgrp pd /usr/lib/libdirent.a
END_OF_Makefile
if test 1276 -ne `wc -c <Makefile`; then
    echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f opendir.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"opendir.c\"
else
echo shar: Extracting \"opendir.c\" \(1468 characters\)
sed "s/^X//" >opendir.c <<'END_OF_opendir.c'
X/*
X	opendir -- open a directory stream
X
X	last edit:	25-Apr-1987	D A Gwyn
X*/
X
X#include	<sys/errno.h>
X#include	<sys/types.h>
X#include	<sys/stat.h>
X#include	<dirent.h>
X
X#ifdef BRL
X#define open	_open			/* avoid emulation overhead */
X#endif
X
Xtypedef char	*pointer;		/* (void *) if you have it */
X
Xextern void	free();
Xextern pointer	malloc();
Xextern int	open(), close(), fstat();
X
Xextern int	errno;
X
X#ifndef NULL
X#define	NULL	0
X#endif
X
X#ifndef O_RDONLY
X#define	O_RDONLY	0
X#endif
X
X#ifndef S_ISDIR				/* macro to test for directory file */
X#define	S_ISDIR( mode )		(((mode) & S_IFMT) == S_IFDIR)
X#endif
X
XDIR *
Xopendir( dirname )
X	char		*dirname;	/* name of directory */
X	{
X	register DIR	*dirp;		/* -> malloc'ed storage */
X	register int	fd;		/* file descriptor for read */
X	struct stat	sbuf;		/* result of fstat() */
X
X	if ( (fd = open( dirname, O_RDONLY )) < 0 )
X		return NULL;		/* errno set by open() */
X
X	if ( fstat( fd, &sbuf ) != 0 || !S_ISDIR( sbuf.st_mode ) )
X		{
X		(void)close( fd );
X		errno = ENOTDIR;
X		return NULL;		/* not a directory */
X		}
X
X	if ( (dirp = (DIR *)malloc( sizeof(DIR) )) == NULL
X	  || (dirp->dd_buf = (char *)malloc( (unsigned)DIRBUF )) == NULL
X	   )	{
X		register int	serrno = errno;
X					/* errno set to ENOMEM by sbrk() */
X
X		if ( dirp != NULL )
X			free( (pointer)dirp );
X
X		(void)close( fd );
X		errno = serrno;
X		return NULL;		/* not enough memory */
X		}
X
X	dirp->dd_fd = fd;
X	dirp->dd_loc = dirp->dd_size = 0;	/* refill needed */
X
X	return dirp;
X	}
END_OF_opendir.c
if test 1468 -ne `wc -c <opendir.c`; then
    echo shar: \"opendir.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f readdir.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"readdir.c\"
else
echo shar: Extracting \"readdir.c\" \(991 characters\)
sed "s/^X//" >readdir.c <<'END_OF_readdir.c'
X/*
X	readdir -- read next entry from a directory stream
X
X	last edit:	25-Apr-1987	D A Gwyn
X*/
X
X#include	<sys/errno.h>
X#include	<sys/types.h>
X#include	<dirent.h>
X
Xextern int	getdents();		/* SVR3 system call, or emulation */
X
Xextern int	errno;
X
X#ifndef NULL
X#define	NULL	0
X#endif
X
Xstruct dirent *
Xreaddir( dirp )
X	register DIR		*dirp;	/* stream from opendir() */
X	{
X	register struct dirent	*dp;	/* -> directory data */
X
X	if ( dirp == NULL || dirp->dd_buf == NULL )
X		{
X		errno = EFAULT;
X		return NULL;		/* invalid pointer */
X		}
X
X	do	{
X		if ( dirp->dd_loc >= dirp->dd_size )	/* empty or obsolete */
X			dirp->dd_loc = dirp->dd_size = 0;
X
X		if ( dirp->dd_size == 0	/* need to refill buffer */
X		  && (dirp->dd_size =
X			getdents( dirp->dd_fd, dirp->dd_buf, (unsigned)DIRBUF )
X		     ) <= 0
X		   )
X			return NULL;	/* EOF or error */
X
X		dp = (struct dirent *)&dirp->dd_buf[dirp->dd_loc];
X		dirp->dd_loc += dp->d_reclen;
X		}
X	while ( dp->d_ino == 0L );	/* don't rely on getdents() */
X
X	return dp;
X	}
END_OF_readdir.c
if test 991 -ne `wc -c <readdir.c`; then
    echo shar: \"readdir.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f rewinddir.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"rewinddir.c\"
else
echo shar: Extracting \"rewinddir.c\" \(746 characters\)
sed "s/^X//" >rewinddir.c <<'END_OF_rewinddir.c'
X/*
X	rewinddir -- rewind a directory stream
X
X	last edit:	25-Apr-1987	D A Gwyn
X
X	This is not simply a call to seekdir(), because seekdir()
X	will use the current buffer whenever possible and we need
X	rewinddir() to forget about buffered data.
X*/
X
X#include	<sys/errno.h>
X#include	<sys/types.h>
X#include	<dirent.h>
X
Xextern off_t	lseek();
X
Xextern int	errno;
X
X#ifndef NULL
X#define	NULL	0
X#endif
X
X#ifndef SEEK_SET
X#define	SEEK_SET	0
X#endif
X
Xvoid
Xrewinddir( dirp )
X	register DIR		*dirp;	/* stream from opendir() */
X	{
X	if ( dirp == NULL || dirp->dd_buf == NULL )
X		{
X		errno = EFAULT;
X		return;			/* invalid pointer */
X		}
X
X	dirp->dd_loc = dirp->dd_size = 0;	/* invalidate buffer */
X	(void)lseek( dirp->dd_fd, (off_t)0, SEEK_SET );	/* may set errno */
X	}
END_OF_rewinddir.c
if test 746 -ne `wc -c <rewinddir.c`; then
    echo shar: \"rewinddir.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f seekdir.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"seekdir.c\"
else
echo shar: Extracting \"seekdir.c\" \(2981 characters\)
sed "s/^X//" >seekdir.c <<'END_OF_seekdir.c'
X/*
X	seekdir -- reposition a directory stream
X
X	last edit:	25-Apr-1987	D A Gwyn
X
X	An unsuccessful seekdir() will in general alter the current
X	directory position; beware.
X
X	NOTE:	4.nBSD directory compaction makes seekdir() & telldir()
X		practically impossible to do right.  Avoid using them!
X*/
X
X#include	<sys/errno.h>
X#include	<sys/types.h>
X#include	<dirent.h>
X
Xextern off_t	lseek();
X
Xextern int	errno;
X
X#ifndef NULL
X#define	NULL	0
X#endif
X
X#ifndef SEEK_SET
X#define	SEEK_SET	0
X#endif
X
Xtypedef int	bool;			/* Boolean data type */
X#define	false	0
X#define	true	1
X
Xvoid
Xseekdir( dirp, loc )
X	register DIR		*dirp;	/* stream from opendir() */
X	register off_t		loc;	/* position from telldir() */
X	{
X	register bool		rewind;	/* "start over when stymied" flag */
X
X	if ( dirp == NULL || dirp->dd_buf == NULL )
X		{
X		errno = EFAULT;
X		return;			/* invalid pointer */
X		}
X
X	/* A (struct dirent)'s d_off is an invented quantity on 4.nBSD
X	   NFS-supporting systems, so it is not safe to lseek() to it. */
X
X	/* Monotonicity of d_off is heavily exploited in the following. */
X
X	/* This algorithm is tuned for modest directory sizes.  For
X	   huge directories, it might be more efficient to read blocks
X	   until the first d_off is too large, then back up one block,
X	   or even to use binary search on the directory blocks.  I
X	   doubt that the extra code for that would be worthwhile. */
X
X	if ( dirp->dd_loc >= dirp->dd_size	/* invalid index */
X	  || ((struct dirent *)&dirp->dd_buf[dirp->dd_loc])->d_off > loc
X					/* too far along in buffer */
X	   )
X		dirp->dd_loc = 0;	/* reset to beginning of buffer */
X	/* else save time by starting at current dirp->dd_loc */
X
X	for ( rewind = true; ; )
X		{
X		register struct dirent	*dp;
X
X		/* See whether the matching entry is in the current buffer. */
X
X		if ( (dirp->dd_loc < dirp->dd_size	/* valid index */
X		   || readdir( dirp ) != NULL	/* next buffer read */
X		   && (dirp->dd_loc = 0, true)	/* beginning of buffer set */
X		     )
X		  && (dp = (struct dirent *)&dirp->dd_buf[dirp->dd_loc])->d_off
X			<= loc		/* match possible in this buffer */
X		   )	{
X			for ( /* dp initialized above */ ;
X			      (char *)dp < &dirp->dd_buf[dirp->dd_size];
X			      dp = (struct dirent *)((char *)dp + dp->d_reclen)
X			    )
X				if ( dp->d_off == loc )
X					{	/* found it! */
X					dirp->dd_loc =
X						(char *)dp - dirp->dd_buf;
X					return;
X					}
X
X			rewind = false;	/* no point in backing up later */
X			dirp->dd_loc = dirp->dd_size;	/* set end of buffer */
X			}
X		else			/* whole buffer past matching entry */
X			if ( !rewind )
X				{	/* no point in searching further */
X				errno = EINVAL;
X				return;	/* no entry at specified loc */
X				}
X			else	{	/* rewind directory and start over */
X				rewind = false;	/* but only once! */
X
X				dirp->dd_loc = dirp->dd_size = 0;
X
X				if ( lseek( dirp->dd_fd, (off_t)0, SEEK_SET )
X					!= 0
X				   )
X					return;	/* errno already set (EBADF) */
X
X				if ( loc == 0 )
X					return; /* save time for rewinddir() */
X				}
X		}
X	}
END_OF_seekdir.c
if test 2981 -ne `wc -c <seekdir.c`; then
    echo shar: \"seekdir.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f sys._dir.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"sys._dir.h\"
else
echo shar: Extracting \"sys._dir.h\" \(2977 characters\)
sed "s/^X//" >sys._dir.h <<'END_OF_sys._dir.h'
X/*
X	<sys/_dir.h> -- definitions for 4.2,4.3BSD directories
X
X	last edit:	25-Apr-1987	D A Gwyn
X
X	A directory consists of some number of blocks of DIRBLKSIZ bytes each,
X	where DIRBLKSIZ is chosen such that it can be transferred to disk in a
X	single atomic operation (e.g., 512 bytes on most machines).
X
X	Each DIRBLKSIZ-byte block contains some number of directory entry
X	structures, which are of variable length.  Each directory entry has the
X	beginning of a (struct direct) at the front of it, containing its
X	filesystem-unique ident number, the length of the entry, and the length
X	of the name contained in the entry.  These are followed by the NUL-
X	terminated name padded to a (long) boundary with 0 bytes.  The maximum
X	length of a name in a directory is MAXNAMELEN.
X
X	The macro DIRSIZ(dp) gives the amount of space required to represent a
X	directory entry.  Free space in a directory is represented by entries
X	that have dp->d_reclen > DIRSIZ(dp).  All DIRBLKSIZ bytes in a
X	directory block are claimed by the directory entries; this usually
X	results in the last entry in a directory having a large dp->d_reclen.
X	When entries are deleted from a directory, the space is returned to the
X	previous entry in the same directory block by increasing its
X	dp->d_reclen.  If the first entry of a directory block is free, then
X	its dp->d_fileno is set to 0; entries other than the first in a
X	directory do not normally have 	dp->d_fileno set to 0.
X
X	prerequisite:	<sys/types.h>
X*/
X
X#if defined(accel) || defined(sun) || defined(vax)
X#define	DIRBLKSIZ	512		/* size of directory block */
X#else
X#ifdef alliant
X#define	DIRBLKSIZ	4096		/* size of directory block */
X#else
X#ifdef gould
X#define	DIRBLKSIZ	1024		/* size of directory block */
X#else
X#ifdef ns32000	/* Dynix System V */
X#define	DIRBLKSIZ	2600		/* size of directory block */
X#else	/* be conservative; multiple blocks are okay but fractions are not */
X#define	DIRBLKSIZ	4096		/* size of directory block */
X#endif
X#endif
X#endif
X#endif
X
X#define	MAXNAMELEN	255		/* maximum filename length */
X/* NOTE:  not MAXNAMLEN, which has been preempted by SVR3 <dirent.h> */
X
Xstruct direct				/* data from read()/_getdirentries() */
X	{
X	unsigned long	d_fileno;	/* unique ident of entry */
X	unsigned short	d_reclen;	/* length of this record */
X	unsigned short	d_namlen;	/* length of string in d_name */
X	char		d_name[MAXNAMELEN+1];	/* NUL-terminated filename */
X	/* typically shorter */
X	};
X
X/*
X	The DIRSIZ macro gives the minimum record length which will hold the
X	directory entry.  This requires the amount of space in a (struct
X	direct) without the d_name field, plus enough space for the name with a
X	terminating NUL character, rounded up to a (long) boundary.
X
X	(Note that Berkeley didn't properly compensate for struct padding,
X	but we nevertheless have to use the same size as the actual system.)
X*/
X
X#define	DIRSIZ( dp )	((sizeof(struct direct) - (MAXNAMELEN+1) \
X			+ sizeof(long) + (dp)->d_namlen) \
X			/ sizeof(long) * sizeof(long))
END_OF_sys._dir.h
if test 2977 -ne `wc -c <sys._dir.h`; then
    echo shar: \"sys._dir.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f sys.dirent.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"sys.dirent.h\"
else
echo shar: Extracting \"sys.dirent.h\" \(980 characters\)
sed "s/^X//" >sys.dirent.h <<'END_OF_sys.dirent.h'
X/*
X	<sys/dirent.h> -- file system independent directory entry (SVR3)
X
X	last edit:	25-Apr-1987	D A Gwyn
X
X	prerequisite:	<sys/types.h>
X*/
X
Xstruct dirent				/* data from getdents()/readdir() */
X	{
X	long		d_ino;		/* inode number of entry */
X	off_t		d_off;		/* offset of disk directory entry */
X	unsigned short	d_reclen;	/* length of this record */
X	char		d_name[1];	/* name of file */	/* non-POSIX */
X	};
X
X/* The following nonportable ugliness could have been avoided by defining
X   DIRENTSIZ and DIRENTBASESIZ to also have (struct dirent *) arguments. */
X#define	DIRENTBASESIZ		(((struct dirent *)0)->d_name \
X				- (char *)&((struct dirent *)0)->d_ino)
X#define	DIRENTSIZ( namlen )	((DIRENTBASESIZ + sizeof(long) + (namlen)) \
X				/ sizeof(long) * sizeof(long))
X
X/* DAG -- the following was moved from <dirent.h>, which was the wrong place */
X#define	MAXNAMLEN	512		/* maximum filename length */
X
X#ifndef NAME_MAX
X#define	NAME_MAX	(MAXNAMLEN - 1)	/* DAG -- added for POSIX */
X#endif
END_OF_sys.dirent.h
if test 980 -ne `wc -c <sys.dirent.h`; then
    echo shar: \"sys.dirent.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f telldir.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"telldir.c\"
else
echo shar: Extracting \"telldir.c\" \(794 characters\)
sed "s/^X//" >telldir.c <<'END_OF_telldir.c'
X/*
X	telldir -- report directory stream position
X
X	last edit:	25-Apr-1987	D A Gwyn
X
X	NOTE:	4.nBSD directory compaction makes seekdir() & telldir()
X		practically impossible to do right.  Avoid using them!
X*/
X
X#include	<sys/errno.h>
X#include	<sys/types.h>
X#include	<dirent.h>
X
Xextern off_t	lseek();
X
Xextern int	errno;
X
X#ifndef SEEK_CUR
X#define	SEEK_CUR	1
X#endif
X
Xoff_t
Xtelldir( dirp )				/* return offset of next entry */
X	DIR	*dirp;			/* stream from opendir() */
X	{
X	if ( dirp == NULL || dirp->dd_buf == NULL )
X		{
X		errno = EFAULT;
X		return -1;		/* invalid pointer */
X		}
X
X	if ( dirp->dd_loc < dirp->dd_size )	/* valid index */
X		return ((struct dirent *)&dirp->dd_buf[dirp->dd_loc])->d_off;
X	else				/* beginning of next directory block */
X		return lseek( dirp->dd_fd, (off_t)0, SEEK_CUR );
X	}
END_OF_telldir.c
if test 794 -ne `wc -c <telldir.c`; then
    echo shar: \"telldir.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f testdir.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"testdir.c\"
else
echo shar: Extracting \"testdir.c\" \(841 characters\)
sed "s/^X//" >testdir.c <<'END_OF_testdir.c'
X/*
X	testdir -- basic test for C library directory access routines
X
X	last edit:	25-Apr-1987	D A Gwyn
X*/
X
X#include	<sys/types.h>
X#include	<stdio.h>
X#include	<dirent.h>
X
Xextern void	exit();
Xextern int	strcmp();
X
Xmain( argc, argv )
X	int			argc;
X	register char		**argv;
X	{
X	register DIR		*dirp;
X	register struct dirent	*dp;
X	int			nerrs = 0;	/* total not found */
X
X	if ( (dirp = opendir( "." )) == NULL )
X		{
X		(void)fprintf( stderr, "Cannot open \".\" directory\n" );
X		exit( 1 );
X		}
X
X	while ( --argc > 0 )
X		{
X		++argv;
X
X		while ( (dp = readdir( dirp )) != NULL ){
X			if ( strcmp( dp->d_name, *argv ) == 0 )
X				{
X				(void)printf( "\"%s\" found.\n", *argv );
X				break;
X				}
X		}
X		if ( dp == NULL )
X			{
X			(void)printf( "\"%s\" not found.\n", *argv );
X			++nerrs;
X			}
X
X		rewinddir( dirp );
X		}
X
X	(void)closedir( dirp );
X	exit( nerrs );
X	}
END_OF_testdir.c
if test 841 -ne `wc -c <testdir.c`; then
    echo shar: \"testdir.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0
-- 
US MAIL  : Lenny Tropiano, ICUS Software Systems      IIIII  CCC U   U  SSS
           PO Box 1                                     I   C    U   U S
           Islip Terrace, New York  11752               I   C    U   U  SS 
PHONE    : (516) 968-8576 [H] (516) 582-5525 [W]        I   C    U   U    S
TELEX    : 154232428 [ICUS]                           IIIII  CCC  UUU  SSS 
AT&T MAIL: ...attmail!icus!lenny  
UUCP     : ...{talcott, boulder, pacbell, sbcs, mtune, bc-cis}!icus!lenny 

alex@umbc3.UMD.EDU (Alex S. Crain) (06/13/88)

In article <385@icus.UUCP> lenny@icus.UUCP (Lenny Tropiano) writes:
>I have the dirent routines that work fine with cshar...  As for dbm there
>isn't really a FULL-IMPLEMENTATION available for the UNIX pc.  I've seen
>dbz that works good with news... (so I've been told)
>
>--- cut here --- --- cut here --- --- cut here --- --- cut here ---

			[sorces ommitted]

	I logged in today for the express purpose of scoring the man pages
for the directory routines so that I could spend all night (or less, hopefully)
writing a BSD directory library.

	On a whim, I decided to read news first.

	This was the first message.

	[insert theme from the twilight zone here]

	Thanks, lenny.

-- 
					:alex.

nerwin!alex@umbc3.umd.edu
alex@umbc3.umd.edu

root@rocky.cs.wisc.edu.CS.WISC.EDU (Charlie Root) (06/14/88)

As for libndir, there was a public domain implementaion of the directory
routines posted to comp.sources.unix a long time ago.  You can ftp it from
j.cc.purdue.edu.  UUCP access through uunet.uu.net.

I havn't seen a public domain impl. of libdbm.  I think that it is avail.
from AT&T.  If you try and port it from BSD sources, there is a problem
with when a database goes past one disk page.  Turns out there is a call
to bcopy, and memcopy, (and for that manor Wollengong's implementation of
BCOPY) does not handle it correctly.  A simple substitution is easy to whip
up.

Jonathan Sadler
Computing Systems Lab (CSL)
University of Wisconsin - Madison

randy@chinet.UUCP (Randy Suess) (06/14/88)

I have been swamped with requests, so figure a posting is in order.
This posting and the following contain the mdbm source as posted 
a while ago and the mods made by Dave Ihnat (ignatz@chinet) to
make it look like a 99.9% clone of V7 dbm.  Made spacewar and news 2.11
work fine on a 3b2/310 running SysVr3.1.
Good luck.


#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 2)."
# Contents:  . ./addons ./addons/READ.ME ./addons/bcmp.c
#   ./addons/bcmp.s ./addons/bcopy.c ./addons/bcopy.s ./addons/bzero.c
#   ./addons/bzero.s ./mdbm ./mdbm/.archinfo ./mdbm/Makefile
#   ./mdbm/access.c ./mdbm/bcmp.c ./mdbm/bcopy.c ./mdbm/bzero.c
#   ./mdbm/checkblock.c ./mdbm/close.c ./mdbm/compare.c ./mdbm/dbm.h
#   ./mdbm/dbmcompat.c ./mdbm/delete.c ./mdbm/delitem.c
#   ./mdbm/dumpdbm.c ./mdbm/fetch.c ./mdbm/firsthash.c
#   ./mdbm/firstkey.c ./mdbm/hash.c ./mdbm/hashinc.c ./mdbm/mdbm.h
#   ./mdbm/mdbm_local.h ./mdbm/nextkey.c ./mdbm/open.c ./mdbm/search.c
#   ./mdbm/sync.c ./mdbm/testdbm.c
# Wrapped by randy@chinet on Wed Jun  8 13:52:15 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test ! -d ./addons ; then
    echo shar: Creating directory \"./addons\"
    mkdir ./addons
fi
if test -f ./addons/READ.ME -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./addons/READ.ME\"
else
echo shar: Extracting \"./addons/READ.ME\" \(1514 characters\)
sed "s/^X//" >./addons/READ.ME <<'END_OF_./addons/READ.ME'
XFrom ihnp4!zehntel!hplabs!hao!seismo!umcp-cs!eneevax!chris Sat Aug 18 03:31:41 1984
XRelay-Version: version B 2.10.1 exptools 1/30/84; site ihnp3.UUCP
XPosting-Version: version B 2.10.1 6/24/83; site eneevax.UUCP
XPath: ihnp3!ihnp4!zehntel!hplabs!hao!seismo!umcp-cs!eneevax!chris
XFrom: chris@eneevax.UUCP (Chris Torek)
XNewsgroups: net.sources
XSubject: bcopy, bcmp, bzero for 4.1BSD
XMessage-ID: <153@eneevax.UUCP>
XDate: Sat, 18-Aug-84 03:31:41 CDT
XArticle-I.D.: eneevax.153
XPosted: Sat Aug 18 03:31:41 1984
XDate-Received: Sun, 19-Aug-84 11:19:10 EDT
XOrganization: Univ. of Maryland, EE Dept.
XLines: 156
X
XI've received (justified) complaints for not explaining bcmp(),
Xbcopy(), and bzero() in my mdbm source posting.  This is one of those
X4.2 dependencies I warned about.  Anyway, here are implementations of
Xbcopy, bcmp, and bzero in Vax assembly and in C.  WARNING: I haven't
Xtested the Vax assembly version of bcmp (nor any of the C routines but
Xwho needs to test those?).  Also, the assembly routines won't work
Xunder VMS, which (I believe) needs r2-r11 saved; you'd have to change
Xthe entry masks.
X
XIf you're running 4.2 you should already have these in your C library,
Xso in that case, ignore this posting.  (Otherwise, why not rewrite
Xthese for your particular machine and *install* it in your C library?)
X
X--Chris Torek, U of MD CS/EE, seismo!umcp-cs!chris, chris@maryland.ARPA,
X  chris@umcp-cs.CSNet  (I don't have my regular .signature installed on
X  this machine)
X-------------------------------------------
END_OF_./addons/READ.ME
if test 1514 -ne `wc -c <./addons/READ.ME`; then
    echo shar: \"./addons/READ.ME\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./addons/bcmp.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./addons/bcmp.c\"
else
echo shar: Extracting \"./addons/bcmp.c\" \(383 characters\)
sed "s/^X//" >./addons/bcmp.c <<'END_OF_./addons/bcmp.c'
X/*
X * bcmp
X *
X * compare count bytes at s1 and s2; return 0 iff equal
X *
X * N.B.: Beware large counts (>32767) on machines with 16 bit `int's.
X * (This routine should really be rewritten for those.)
X */
Xbcmp (s1, s2, count)
Xregister char *s1, *s2;
Xregister int count;
X{
X    while (--count >= 0)
X	if (*s1++ != *s2++)
X	    return 1;		/* or ``return *--s1 - *--s2;'' */
X    return 0;
X}
END_OF_./addons/bcmp.c
if test 383 -ne `wc -c <./addons/bcmp.c`; then
    echo shar: \"./addons/bcmp.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./addons/bcmp.s -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./addons/bcmp.s\"
else
echo shar: Extracting \"./addons/bcmp.s\" \(518 characters\)
sed "s/^X//" >./addons/bcmp.s <<'END_OF_./addons/bcmp.s'
X# bcmp (s1, s2, count) char *s1, *s2; int count;
X#
X# Compare "count" bytes at "s1" with those at "s2"; return 0 iff equal
X
X	.align	2
X	.globl	_bcopy
X_bcopy:
X	.word	0
X	movl	4(ap),r1		# r1 = s1
X	movl	8(ap),r3		# r3 = s2
X	brb	2f
X1:
X	subl2	r0,12(ap)		# count-=65535 (bytes compared)
X	cmpc3	r0,(r1),(r3)		# r1, r3 magically point to next 65K
X	bneq	3f
X2:
X	movzwl	$65535,r0
X	cmpl	12(ap),r0		# <= 65535 bytes to compare?
X	jgtr	1b			# brif not, do 65535 and try again
X	cmpc3	12(ap),(r1),(r3)	# compare up to 65535 bytes
X3:
X	ret
END_OF_./addons/bcmp.s
if test 518 -ne `wc -c <./addons/bcmp.s`; then
    echo shar: \"./addons/bcmp.s\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./addons/bcopy.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./addons/bcopy.c\"
else
echo shar: Extracting \"./addons/bcopy.c\" \(356 characters\)
sed "s/^X//" >./addons/bcopy.c <<'END_OF_./addons/bcopy.c'
X/*
X * bcopy - copy count bytes from "from" to "to" - not guaranteed to work
X * if "from" and "to" overlap
X *
X * N.B.: Beware large counts (>32767) on machines with 16 bit `int's.
X * (This routine should really be rewritten for those.)
X */
Xbcopy (from, to, count)
Xregister char *from, *to;
Xregister int count;
X{
X    while (--count >= 0)
X	*to++ = *from++;
X}
END_OF_./addons/bcopy.c
if test 356 -ne `wc -c <./addons/bcopy.c`; then
    echo shar: \"./addons/bcopy.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./addons/bcopy.s -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./addons/bcopy.s\"
else
echo shar: Extracting \"./addons/bcopy.s\" \(540 characters\)
sed "s/^X//" >./addons/bcopy.s <<'END_OF_./addons/bcopy.s'
X# bcopy (from, to, count) char *from, *to; int count;
X#
X# Copy "count" bytes from "from" to "to"; not guaranteed to
X# work if "from" and "to" overlap.
X
X	.align	2
X	.globl	_bcopy
X_bcopy:
X	.word	0
X	movl	4(ap),r1		# r1 = from
X	movl	8(ap),r3		# r3 = to
X	brb	2f
X1:
X	subl2	r0,12(ap)		# count-=65535 (bytes moved this time)
X	movc3	r0,(r1),(r3)		# r1, r3 magically point to next 65K
X2:
X	movzwl	$65535,r0
X	cmpl	12(ap),r0		# <= 65535 bytes to move?
X	jgtr	1b			# brif not, move 65535 and try again
X	movc3	12(ap),(r1),(r3)	# move up to 65535 bytes
X	ret
END_OF_./addons/bcopy.s
if test 540 -ne `wc -c <./addons/bcopy.s`; then
    echo shar: \"./addons/bcopy.s\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./addons/bzero.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./addons/bzero.c\"
else
echo shar: Extracting \"./addons/bzero.c\" \(284 characters\)
sed "s/^X//" >./addons/bzero.c <<'END_OF_./addons/bzero.c'
X/*
X * bzero - zero count bytes at address addr
X *
X * N.B.: Beware large counts (>32767) on machines with 16 bit `int's.
X * (This routine should really be rewritten for those.)
X */
Xbzero (addr, count)
Xregister char *addr;
Xregister int count;
X{
X    while (--count >= 0)
X	*addr++ = 0;
X}
END_OF_./addons/bzero.c
if test 284 -ne `wc -c <./addons/bzero.c`; then
    echo shar: \"./addons/bzero.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./addons/bzero.s -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./addons/bzero.s\"
else
echo shar: Extracting \"./addons/bzero.s\" \(455 characters\)
sed "s/^X//" >./addons/bzero.s <<'END_OF_./addons/bzero.s'
X# bzero (addr, count) char *addr; int count;
X#
X# Zero "count" bytes at address "addr"
X
X	.align	2
X	.globl	_bzero
X_bzero:
X	.word	0
X	movl	4(ap),r3		# r3 = addr
X	brb	2f
X1:
X	subl2	r0,8(ap)		# count-=65535 (bytes zeroed this time)
X	movc5	$0,(sp),$0,r0,(r3)	# r3 magically points to next 65K
X2:
X	movzwl	$65535,r0
X	cmpl	8(ap),r0		# <= 65535 bytes to zero?
X	jgtr	1b			# brif not, zero 65535 and try again
X	movc5	$0,(sp),$0,8(ap),(r3)	# zero up to 65535 bytes
X	ret
END_OF_./addons/bzero.s
if test 455 -ne `wc -c <./addons/bzero.s`; then
    echo shar: \"./addons/bzero.s\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test ! -d ./mdbm ; then
    echo shar: Creating directory \"./mdbm\"
    mkdir ./mdbm
fi
if test ! -d ./mdbm/.archinfo ; then
    echo shar: Creating directory \"./mdbm/.archinfo\"
    mkdir ./mdbm/.archinfo
fi
if test -f ./mdbm/Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/Makefile\"
else
echo shar: Extracting \"./mdbm/Makefile\" \(1830 characters\)
sed "s/^X//" >./mdbm/Makefile <<'END_OF_./mdbm/Makefile'
X# $Header$
X#
X# The -R flag compiles initialized data into the text area.  Not really
X# necessary, but nice.
X# (DMI-AiC): Unfortunately, also not on BTL-derived compilers.
X# (DMI-AiC): Added dbm compatibility module
XCC = ccsh # 3b1 Only!
X#CC = cc
X
X#CFLAGS=	-O -R
XCFLAGS=	-O
X
XOBJS=	access.o checkblock.o close.o compare.o delete.o delitem.o\
X	fetch.o firsthash.o firstkey.o hash.o hashinc.o nextkey.o\
X	open.o search.o store.o sync.o dbmcompat.o
X
XSRCS=	access.c checkblock.c close.c compare.c delete.c delitem.c\
X	fetch.c firsthash.c firstkey.c hash.c hashinc.c nextkey.c\
X	open.c search.c store.c sync.c dbmcompat.c
X
XHDRS=	mdbm.h mdbm_local.h
X
X.c.o:
X	$(CC) -c $(CFLAGS) $<
X	@ld -r -x $@
X	@mv a.out $@
X
Xall: libmdbm.a testdbm dumpdbm
X
Xlibmdbm.a: $(OBJS)
X	ar cr libmdbm.a `lorder $(OBJS) | tsort`
X#	ranlib libmdbm.a
X
Xinstall:
X	install -m 444 -o bin -g bin -c libmdbm.a $(DESTDIR)/usr/lib
X	ln $(DESTDIR)/usr/lib/libmdbm.a $(DESTDIR)/usr/lib/libdbm.a
X#	ranlib $(DESTDIR)/usr/lib/libmdbm.a
X	install -m 444 -o bin -g bin -c mdbm.h $(DESTDIR)/include
X	install -c mdbm.3x $(DESTDIR)/usr/man/man3
X
Xtestdbm: testdbm.o libmdbm.a
X	cc $(CFLAGS) -o testdbm testdbm.o libmdbm.a
X
Xdumpdbm: dumpdbm.o libmdbm.a
X	cc $(CFLAGS) -o dumpdbm dumpdbm.o libmdbm.a
X
Xclean:
X	rm -f libmdbm.a *.o a.out testdbm dumpdbm core
X
Xlint:	$(SRCS) $(HDRS)
X	lint -h $(SRCS) | egrep -v 'possible pointer alignment problem'
X
Xaccess.o: mdbm.h mdbm_local.h
Xadditem.o: mdbm.h mdbm_local.h
Xcheckblock.o: mdbm.h mdbm_local.h
Xclose.o: mdbm.h mdbm_local.h
Xdelete.o: mdbm.h mdbm_local.h
Xdelitem.o: mdbm.h mdbm_local.h
Xfetch.o: mdbm.h mdbm_local.h
Xfirsthash.o: mdbm.h mdbm_local.h
Xfirstkey.o: mdbm.h mdbm_local.h
Xhash.o: mdbm.h mdbm_local.h
Xnextkey.o: mdbm.h mdbm_local.h
Xopen.o: mdbm.h mdbm_local.h
Xsearch.o: mdbm_local.h
Xstore.o: mdbm.h mdbm_local.h
Xsync.o: mdbm.h mdbm_local.h
X
X
END_OF_./mdbm/Makefile
if test 1830 -ne `wc -c <./mdbm/Makefile`; then
    echo shar: \"./mdbm/Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/access.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/access.c\"
else
echo shar: Extracting \"./mdbm/access.c\" \(1210 characters\)
sed "s/^X//" >./mdbm/access.c <<'END_OF_./mdbm/access.c'
X#ifndef lint
Xstatic char rcsid[] = "$Header: /ful/chris/dist/mdbm/access.c,v 1.1 84/08/12 09:54:48 chris Rel $";
X#endif
X
X#include <stdio.h>
X#include "mdbm.h"
X#include "mdbm_local.h"
X
X/*
X * Read in the appropriate data block for an item whose hash index is
X * hash.  The hash index specifies the data block in an indirect way:
X * if the bit in the map is set then more bits of the hash value should
X * be considered.  If it is not set then we have the right hash bits
X * and the block number is just the low bits of the hash value.
X *
X * Return the hash mask that gets the right block number.
X */
Xint mdbm_access (d, hash)
Xregister struct mdbm *d;
Xregister long hash;
X{
X    register long   hmask,
X                    b;
X
X    for (hmask = 0;; hmask = (hmask << 1) + 1) {
X	b = (hash & hmask) + hmask;/* map bit number */
X	if (b < d -> mdbm_maxbit) {
X	    register int    i,
X	                    n;
X
X	    n = b % BYTESIZ;	/* bit index */
X	    b /= BYTESIZ;	/* byte index */
X	    i = b % d -> mdbm_msize;/* byte offset in map */
X	    b /= d -> mdbm_msize;/* map block number */
X	    MDBM_MREAD (d, b);
X	    if (d -> mdbm_m[i] & (1 << n))
X		continue;
X	}
X	b = hash & hmask;
X	MDBM_DREAD (d, b);
X	return hmask;
X    }
X}
END_OF_./mdbm/access.c
if test 1210 -ne `wc -c <./mdbm/access.c`; then
    echo shar: \"./mdbm/access.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/bcmp.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/bcmp.c\"
else
echo shar: Extracting \"./mdbm/bcmp.c\" \(383 characters\)
sed "s/^X//" >./mdbm/bcmp.c <<'END_OF_./mdbm/bcmp.c'
X/*
X * bcmp
X *
X * compare count bytes at s1 and s2; return 0 iff equal
X *
X * N.B.: Beware large counts (>32767) on machines with 16 bit `int's.
X * (This routine should really be rewritten for those.)
X */
Xbcmp (s1, s2, count)
Xregister char *s1, *s2;
Xregister int count;
X{
X    while (--count >= 0)
X	if (*s1++ != *s2++)
X	    return 1;		/* or ``return *--s1 - *--s2;'' */
X    return 0;
X}
END_OF_./mdbm/bcmp.c
if test 383 -ne `wc -c <./mdbm/bcmp.c`; then
    echo shar: \"./mdbm/bcmp.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/bcopy.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/bcopy.c\"
else
echo shar: Extracting \"./mdbm/bcopy.c\" \(356 characters\)
sed "s/^X//" >./mdbm/bcopy.c <<'END_OF_./mdbm/bcopy.c'
X/*
X * bcopy - copy count bytes from "from" to "to" - not guaranteed to work
X * if "from" and "to" overlap
X *
X * N.B.: Beware large counts (>32767) on machines with 16 bit `int's.
X * (This routine should really be rewritten for those.)
X */
Xbcopy (from, to, count)
Xregister char *from, *to;
Xregister int count;
X{
X    while (--count >= 0)
X	*to++ = *from++;
X}
END_OF_./mdbm/bcopy.c
if test 356 -ne `wc -c <./mdbm/bcopy.c`; then
    echo shar: \"./mdbm/bcopy.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/bzero.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/bzero.c\"
else
echo shar: Extracting \"./mdbm/bzero.c\" \(284 characters\)
sed "s/^X//" >./mdbm/bzero.c <<'END_OF_./mdbm/bzero.c'
X/*
X * bzero - zero count bytes at address addr
X *
X * N.B.: Beware large counts (>32767) on machines with 16 bit `int's.
X * (This routine should really be rewritten for those.)
X */
Xbzero (addr, count)
Xregister char *addr;
Xregister int count;
X{
X    while (--count >= 0)
X	*addr++ = 0;
X}
END_OF_./mdbm/bzero.c
if test 284 -ne `wc -c <./mdbm/bzero.c`; then
    echo shar: \"./mdbm/bzero.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/checkblock.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/checkblock.c\"
else
echo shar: Extracting \"./mdbm/checkblock.c\" \(724 characters\)
sed "s/^X//" >./mdbm/checkblock.c <<'END_OF_./mdbm/checkblock.c'
X#ifndef lint
Xstatic char rcsid[] = "$Header: /ful/chris/dist/mdbm/checkblock.c,v 1.1 84/08/12 09:56:16 chris Rel $";
X#endif
X
X#include <stdio.h>
X#include "mdbm.h"
X#include "mdbm_local.h"
X
X/*
X * Perform some sanity checks on a data block
X */
Xmdbm_checkblock (buf, size)
Xchar *buf;
Xint   size;
X{
X    register struct mdbm_dblock *db = (struct mdbm_dblock *) buf;
X    register struct mdbm_dentry *de;
X    register int    i,
X		    t = size;
X
X    de = &db -> db_e[1];
X    for (i = 1; i < db -> db_n; i++) {
X	if (de -> de_off > t)
X	    goto bad;
X	t = de -> de_off;
X	de++;
X    }
X    if (&buf[t] < (char *) de)
X	goto bad;
X    return;
X
Xbad: 
X    printf ("mdbm: bad block\n");
X    fflush(stdout);
X    abort ();
X    bzero (buf, size);
X}
END_OF_./mdbm/checkblock.c
if test 724 -ne `wc -c <./mdbm/checkblock.c`; then
    echo shar: \"./mdbm/checkblock.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/close.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/close.c\"
else
echo shar: Extracting \"./mdbm/close.c\" \(454 characters\)
sed "s/^X//" >./mdbm/close.c <<'END_OF_./mdbm/close.c'
X#ifndef lint
Xstatic char rcsid[] = "$Header: /ful/chris/dist/mdbm/close.c,v 1.1 84/08/12 09:57:45 chris Rel $";
X#endif
X
X#include <stdio.h>
X#include "mdbm.h"
X#include "mdbm_local.h"
X
X/*
X * Close a database
X */
Xmdbm_close (d)
Xregister struct mdbm *d;
X{
X    MDBM_SYNC (d);
X    (void) close (d -> mdbm_datafd);
X    (void) close (d -> mdbm_mapfd);
X    free (d -> mdbm_d);
X    free (d -> mdbm_s);
X    free (d -> mdbm_m);
X    free ((char *) d);
X    return 0;
X}
END_OF_./mdbm/close.c
if test 454 -ne `wc -c <./mdbm/close.c`; then
    echo shar: \"./mdbm/close.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/compare.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/compare.c\"
else
echo shar: Extracting \"./mdbm/compare.c\" \(492 characters\)
sed "s/^X//" >./mdbm/compare.c <<'END_OF_./mdbm/compare.c'
X#ifndef lint
Xstatic char rcsid[] = "$Header: /ful/chris/dist/mdbm/compare.c,v 1.1 84/08/12 09:57:59 chris Rel $";
X#endif
X
X/*
X * Compare strings s1 and s2 for len bytes; return the difference
X * between the first differing characters.  Could probably use strncmp
X * but I don't trust it to work the same way when encountering \0s.
X */
Xmdbm_compare (s1, s2, len)
Xregister char *s1, *s2;
Xregister int len;
X{
X    while (--len >= 0)
X	if (*s1++ != *s2++)
X	    return *--s1 - *--s2;
X    return 0;
X}
END_OF_./mdbm/compare.c
if test 492 -ne `wc -c <./mdbm/compare.c`; then
    echo shar: \"./mdbm/compare.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/dbm.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/dbm.h\"
else
echo shar: Extracting \"./mdbm/dbm.h\" \(319 characters\)
sed "s/^X//" >./mdbm/dbm.h <<'END_OF_./mdbm/dbm.h'
X/*
X * Multiple key database library compatibility include file
X * David M. Ihnat, 1988
X */
X
X#include <mdbm.h>
X
Xextern datum   fetch ();
Xextern datum   firstkey ();
Xextern datum   nextkey ();
Xextern long    forder ();
Xextern int     delete ();
Xextern int     store ();
Xextern struct mdbm *open ();
Xextern int	close ();
X
END_OF_./mdbm/dbm.h
if test 319 -ne `wc -c <./mdbm/dbm.h`; then
    echo shar: \"./mdbm/dbm.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/dbmcompat.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/dbmcompat.c\"
else
echo shar: Extracting \"./mdbm/dbmcompat.c\" \(4647 characters\)
sed "s/^X//" >./mdbm/dbmcompat.c <<'END_OF_./mdbm/dbmcompat.c'
X/*
X * Compat - provides mdbm <--> dbm compatibility
X *
X * Author: David M. Ihnat, 2/9/87
X * 
X * This is a work in the Public Domain.
X */
X#include <stdio.h>
X#include <errno.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <fcntl.h>
X#include "mdbm.h"
X
Xstatic struct mdbm *compat_dat = (struct mdbm *)NULL;
X/**/
Xdbminit(file)
Xchar *file;
X{
X	/*
X	 * This is interesting; 'dbm' uses two files, '<file>.dir' and
X	 * '<file>.pag'; 'mdbm' uses '<file>.map' and '<file>.dat'.  There
X	 * also exists the possibility that calling programs may need to know
X	 * about the original files' existence and/or size, while all the mdbm
X	 * routines insist on the new file names.  Solution?  The following:
X	 *
X	 * 1) If called, and the old files don't exist, error--in
X	 *    the old 'dbm' scheme, they had to create the old files.
X	 *
X	 * 2) If called and the 'old' name files exist, AND they're of zero
X	 *    then LINK them to the new name files, since they're just creating
X	 *    the database.  This will satisfy both the old and new routines.
X	 *
X	 * 3) If called, and the 'old' name files exist and are NOT of zero
X	 *    length, then they MUST be already linked to the corresponding
X	 *    new-name file, else they could be trying to feed us an old-format
X	 *    'dbm' database.
X	 */
X
X	/* Only one database may be open at any one time under 'dbm' */
X	if(compat_dat != (struct mdbm *)NULL)
X		(void)mdbm_close(compat_dat);
X
X	/*
X	 * Ok, do the files exist (and, of course, if so, are they accessible?)
X	 */
X	if(dbm_fcheck(file,".dir",".map"))
X		return(-1);
X
X	if(dbm_fcheck(file,".pag",".dat"))
X		return(-1);
X
X	/* OK, all files either newly set up or already exist!  Continue... */
X	compat_dat =
X		mdbm_open(file,O_RDWR,0,(int *)NULL,(int *)NULL,(char *)NULL);
X
X	if(compat_dat == (struct mdbm *)NULL)
X		return(-1);
X
X	(void)mdbm_setflags(compat_dat,MDBM_ISAUTOW);
X
X	return(0);
X}
X/**/
Xdatum
Xfetch(key)
Xdatum key;
X{
X	return(mdbm_fetch(compat_dat,key));
X}
X/**/
Xstore(key,content)
Xdatum key,content;
X{
X	return(mdbm_store(compat_dat,key,content,MDBM_REPLACE));
X}
X/**/
Xdelete(key)
Xdatum key;
X{
X	return(mdbm_delete(compat_dat,key));
X}
X/**/
Xdatum
Xfirstkey()
X{
X	return(mdbm_firstkey(compat_dat));
X}
X/**/
Xdatum
Xnextkey(key)
Xdatum key;
X{
X	return(mdbm_nextkey(compat_dat,key));
X}
X/**/
Xstatic int
Xdbm_fcheck(file,old,new)
Xchar *file, *old, *new;
X{
X	register char *old_file, *new_file;
X	register int retval1, retval2;
X	struct stat old_statbuf, new_statbuf;
X
X	char *malloc();
X
X	/*
X	 * This routine performs all the validity checks.  Note that, on error
X	 * returns, the 'malloc'd space isn't released.  This isn't too evil an
X	 * action, since failure here should mean further processing can't normally
X	 * continue.
X	 */
X
X	/* Allocate enough space for '<file>.[map|dat]' and '<file>.[dir|pag]'*/
X	old_file = malloc((unsigned)(strlen(file) + 5));
X	new_file = malloc((unsigned)(strlen(file) + 5));
X
X	if(old_file == (char *)NULL || new_file == (char *)NULL)
X	{
X		fprintf(stderr,"dbmcompat: Couldn't allocate memory (1)\n");
X		return(-1);
X	}
X
X	/* Setup for test of the old/new file set */
X	strcpy(old_file,file);
X	strcat(old_file,old);
X
X	strcpy(new_file,file);
X	strcat(new_file,new);
X
X	retval1= stat(old_file,&old_statbuf);
X	if(retval1)
X		retval1 = errno;
X
X	retval2= stat(new_file,&new_statbuf);
X	if(retval2)
X		retval2 = errno;
X
X	if(retval1)
X	{
X		/* Something's fatally wrong */
X		if(retval1 == ENOENT)	/* Ok...not there... */
X		{
X			fprintf(stderr,"dbmcompat: No file %s\n",old_file);
X		}else
X		{ /* Couldn't get to it for some reason! */
X			fprintf(stderr,
X				"dbmcompat: Can't get to file %s: %d\n",
X				old_file,retval1);
X		}
X		return(-1);
X	}
X
X	/*
X	 * Got here; file exists & we can get to it.  Does the corresponding
X	 * 'new' file?
X	 */
X	if(retval2)
X	{
X		if(retval2 == ENOENT) /* Ok, not there... */
X		{
X			if(old_statbuf.st_size != (off_t)0)
X			{
X				fprintf(stderr,"dbmcompat: No %s and %s is non-zero size.",
X					new_file,old_file);
X				fprintf(stderr,"Possibly old 'dbm' database?\n");
X				return(-1);
X			}else
X			{
X				/* Interesting--could be initializing new database. */
X				if(link(old_file,new_file))
X				{
X					/* Ouch! */
X					perror("dbmcompat");
X					return(-1);
X				}
X			}
X		}else
X		{
X			fprintf(stderr,"dbmcompat: %s inacessible: %d\n",
X				new_file,retval2);
X			return(-1);
X		}
X	}else
X	{
X		/* It exists; had better be linked to the old file! */
X		if((old_statbuf.st_dev != new_statbuf.st_dev) ||
X		   (old_statbuf.st_ino != new_statbuf.st_ino))
X		{
X			fprintf(stderr,"dbmcompat: %s and %s are not linked!\n",
X				old_file,new_file);
X			return(-1);
X		}
X	}
X
X	/* Wow--it's all OK! */
X	(void)free(old_file);
X	(void)free(new_file);
X
X	return(0);
X}
END_OF_./mdbm/dbmcompat.c
if test 4647 -ne `wc -c <./mdbm/dbmcompat.c`; then
    echo shar: \"./mdbm/dbmcompat.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/delete.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/delete.c\"
else
echo shar: Extracting \"./mdbm/delete.c\" \(1007 characters\)
sed "s/^X//" >./mdbm/delete.c <<'END_OF_./mdbm/delete.c'
X#ifndef lint
Xstatic char rcsid[] = "$Header: /ful/chris/dist/mdbm/delete.c,v 1.1 84/08/12 09:58:22 chris Rel $";
X#endif
X
X#include <stdio.h>
X#include <errno.h>
X#include "mdbm.h"
X#include "mdbm_local.h"
X
X/*
X * Delete datum under key in dbm d
X */
Xmdbm_delete (d, key)
Xregister struct mdbm *d;
Xdatum key;
X{
X#define db ((struct mdbm_dblock *) d -> mdbm_d)
X    register struct mdbm_dentry *de;
X    long    keyblock;
X    int     keyindex;
X    extern int errno;
X
X    de = mdbm_search (d, key.dptr, key.dsize, &keyblock, &keyindex, 0);
X    if (de == 0) {
X	errno = ENOENT;
X	return (-1);
X    }
X    if (d -> mdbm_flags & MDBM_ISRONLY) {
X	errno = EPERM;
X	return (-1);
X    }
X
X /* delete the datum */
X    mdbm_delitem (d, de - db -> db_e);
X
X /* delete the key */
X    de = mdbm_search (d, key.dptr, key.dsize, &keyblock, &keyindex, 1);
X    MDBM_DREAD (d, keyblock);
X    de = &db -> db_e[keyindex];
X    de -> de_outx = 0;		/* not in use as a key anymore */
X    mdbm_delitem (d, keyindex);
X    MDBM_AUTO (d);
X    return 0;
X}
END_OF_./mdbm/delete.c
if test 1007 -ne `wc -c <./mdbm/delete.c`; then
    echo shar: \"./mdbm/delete.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/delitem.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/delitem.c\"
else
echo shar: Extracting \"./mdbm/delitem.c\" \(1356 characters\)
sed "s/^X//" >./mdbm/delitem.c <<'END_OF_./mdbm/delitem.c'
X#ifndef lint
Xstatic char rcsid[] = "$Header: /ful/chris/dist/mdbm/delitem.c,v 1.1 84/08/12 09:58:37 chris Rel $";
X#endif lint
X
X#include <stdio.h>
X#include "mdbm.h"
X#include "mdbm_local.h"
X
X/*
X * Delete item 'n' from current data buffer of dbm d
X */
Xmdbm_delitem (d, n)
Xregister struct mdbm *d;
Xregister int n;
X{
X    register int    i;
X#define db ((struct mdbm_dblock *) d -> mdbm_d)
X    register struct mdbm_dentry *de;
X
X    if (n < 0 || n >= db -> db_n)
X	goto bad;
X    de = &db -> db_e[n];
X    if (de -> de_links > 1) {
X	de -> de_links--;
X	goto done;
X    }
X    db -> db_n--;
X    i = (n ? de[-1].de_off : d -> mdbm_dsize) - de -> de_off;
X    if (i) {			/* delete i bytes of text */
X	if (n < db -> db_n) {
X	    register char  *to,
X	                   *from;
X	    register int    bytes;
X
X	    to = d -> mdbm_d + (n ? de[-1].de_off : d -> mdbm_dsize);
X	    from = to - i;
X	    bytes = de -> de_off - db -> db_e[db -> db_n].de_off;
X	    while (--bytes >= 0)
X		*--to = *--from;
X	}
X	bzero (d -> mdbm_d + db -> db_e[db -> db_n].de_off, i);
X    }
X    {
X	register struct mdbm_dentry *e;
X
X	e = &db -> db_e[db -> db_n];
X	while (de < e) {
X	    *de = de[1];
X	    de -> de_off += i;
X	    de++;
X	}
X	bzero ((char *) e, sizeof e);
X    }
Xdone:
X    d -> mdbm_flags |= MDBM_DDIRTY;
X    return;
X
Xbad:
X    printf ("mdbm bug: bad delitem\n");
X    fflush(stdout);
X    abort ();
X}
END_OF_./mdbm/delitem.c
if test 1356 -ne `wc -c <./mdbm/delitem.c`; then
    echo shar: \"./mdbm/delitem.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/dumpdbm.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/dumpdbm.c\"
else
echo shar: Extracting \"./mdbm/dumpdbm.c\" \(1830 characters\)
sed "s/^X//" >./mdbm/dumpdbm.c <<'END_OF_./mdbm/dumpdbm.c'
X#include "mdbm.h"
X#include "mdbm_local.h"
X#include <stdio.h>
X#include <sys/types.h>
X#ifdef SYSV
X#include <fcntl.h>
X#else
X#include <sys/file.h>
X#endif
X#include <sys/stat.h>
X#include <signal.h>
X
Xabort () { kill (getpid (), SIGILL); }
X
Xmain (argc, argv)
Xint argc;
Xchar **argv;
X{
X    register struct mdbm *mp;
X    register struct mdbm_dblock *db;
X    register struct mdbm_dentry *de;
X    int dsize, msize, blocks;
X    register int i, j, len;
X    struct stat sb;
X
X    if (argc < 2) {
X	fprintf (stderr, "Usage: dumpdbm dbname\n");
X	exit (1);
X    }
X    if (argc > 2)
X	signal (SIGILL, SIG_IGN);
X    dsize = msize = 0;
X    mp = mdbm_open (argv[1], O_RDONLY, 0, &dsize, &msize, (char *) 0);
X    if (!mp) {
X	perror (argv[1]);
X	exit (1);
X    }
X    printf ("dbm %s: dsize = %d, msize = %d\n", argv[1], dsize, msize);
X    (void) fstat (mp -> mdbm_datafd, &sb);
X    blocks = sb.st_size / dsize;
X    printf ("(%d data blocks)\n", blocks);
X    db = (struct mdbm_dblock *) mp -> mdbm_d;
X    for (i = 0; i < blocks; i++) {
X	MDBM_DREAD (mp, i);
X	printf ("block %d: %d entries\n", i, db -> db_n);
X	for (j = 0, de = db -> db_e; j < db -> db_n; j++, de++) {
X	    printf ("\t%2d: @%4d links=%2d inx=%4d outx=%4d outh=%08x ",
X		    j, de -> de_off, de -> de_links, de -> de_inx,
X		    de -> de_outx, de -> de_outh);
X	    len = (j ? de[-1].de_off : dsize) - de -> de_off;
X	    pr_entry (mp -> mdbm_d + de -> de_off, len);
X	}
X    }
X    (void) mdbm_close (mp);
X    exit (0);
X}
X
Xpr_entry (s, len)
Xregister char *s;
Xregister int len;
X{
X    register int c;
X
X    putchar ('"');
X    while (--len >= 0) {
X	c = *s++ & 0377;
X	if (c & 0200)
X	    putchar ('M'), putchar ('-'), c &= 0177;
X	if (c == 0177)
X	    putchar ('^'), putchar ('?');
X	else if (c < ' ')
X	    putchar ('^'), putchar (c + '@');
X	else
X	    putchar (c);
X    }
X    putchar ('"');
X    putchar ('\n');
X}
END_OF_./mdbm/dumpdbm.c
if test 1830 -ne `wc -c <./mdbm/dumpdbm.c`; then
    echo shar: \"./mdbm/dumpdbm.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/fetch.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/fetch.c\"
else
echo shar: Extracting \"./mdbm/fetch.c\" \(670 characters\)
sed "s/^X//" >./mdbm/fetch.c <<'END_OF_./mdbm/fetch.c'
X#ifndef lint
Xstatic char rcsid[] = "$Header: /ful/chris/dist/mdbm/fetch.c,v 1.1 84/08/12 09:59:20 chris Rel $";
X#endif
X
X#include <stdio.h>
X#include "mdbm.h"
X#include "mdbm_local.h"
X
X/*
X * Find datum in dbm d, given key
X */
Xdatum mdbm_fetch (d, key)
Xregister struct mdbm *d;
Xdatum key;
X{
X#define db ((struct mdbm_dblock *) d -> mdbm_d)
X    register struct mdbm_dentry *de;
X    datum item;
X
X    de = mdbm_search (d, key.dptr, key.dsize, (long *) 0, (int *) 0, 0);
X    if (de) {
X	item.dptr = d -> mdbm_d + de -> de_off;
X	item.dsize = (de > db -> db_e ? de[-1].de_off : d -> mdbm_dsize) -
X	    de -> de_off;
X    }
X    else
X	item.dptr = 0, item.dsize = 0;
X    return item;
X}
END_OF_./mdbm/fetch.c
if test 670 -ne `wc -c <./mdbm/fetch.c`; then
    echo shar: \"./mdbm/fetch.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/firsthash.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/firsthash.c\"
else
echo shar: Extracting \"./mdbm/firsthash.c\" \(1440 characters\)
sed "s/^X//" >./mdbm/firsthash.c <<'END_OF_./mdbm/firsthash.c'
X#ifndef lint
Xstatic char rcsid[] = "$Header: /ful/chris/dist/mdbm/firsthash.c,v 1.1 84/08/12 09:59:59 chris Rel $";
X#endif
X
X#include <stdio.h>
X#include "mdbm.h"
X#include "mdbm_local.h"
X
X/*
X * Return the first datum in dbm d with hash value hash
X */
Xdatum mdbm_firsthash (d, hash)
Xregister struct mdbm *d;
Xlong hash;
X{
X#define db ((struct mdbm_dblock *) d -> mdbm_d)
X    register struct mdbm_dentry *de;
X    register int    i;
X    char   *bp;
X    int     bl;
X    char   *ip;
X    int     il,
X            found;
X    long    hmask;
X    datum rval;
X
Xloop: 
X /* Suck in the block for the given hash, then find the "first" key. */
X    hmask = mdbm_access (d, hash);
X    found = 0;
X#ifdef lint			/* lint doesn't realize that 'found'
X				   overrides the tests on bl and bp */
X    bl = 0;
X    bp = 0;
X#endif lint
X    for (i = 0, de = db -> db_e; i < db -> db_n; i++, de++) {
X	if (de -> de_outx == 0)	/* not a key */
X	    continue;
X	il = (i ? de[-1].de_off : d -> mdbm_dsize) - de -> de_off;
X	ip = d -> mdbm_d + de -> de_off;
X	if (!found || il < bl || (il == bl && mdbm_compare (ip, bp, il) < 0)) {
X	    bl = il;
X	    bp = ip;
X	    found++;
X	}
X    }
X    if (found) {
X	bcopy (bp, rval.dptr = d -> mdbm_s, rval.dsize = bl);
X	return rval;
X    }
X
X /* No item with this hash, so get next hash and try again */
X    hash = mdbm_hashinc (hash, hmask);
X    if (hash == 0) {		/* no more */
X	rval.dsize = 0;
X	rval.dptr = 0;
X	return rval;
X    }
X    goto loop;
X}
END_OF_./mdbm/firsthash.c
if test 1440 -ne `wc -c <./mdbm/firsthash.c`; then
    echo shar: \"./mdbm/firsthash.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/firstkey.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/firstkey.c\"
else
echo shar: Extracting \"./mdbm/firstkey.c\" \(306 characters\)
sed "s/^X//" >./mdbm/firstkey.c <<'END_OF_./mdbm/firstkey.c'
X#ifndef lint
Xstatic char rcsid[] = "$Header: /ful/chris/dist/mdbm/firstkey.c,v 1.1 84/08/12 10:00:27 chris Rel $";
X#endif
X
X#include <stdio.h>
X#include "mdbm.h"
X#include "mdbm_local.h"
X
X/*
X * Return the "first" key in dbm d
X */
Xdatum mdbm_firstkey (d)
Xstruct mdbm *d;
X{
X    return mdbm_firsthash (d, 0L);
X}
END_OF_./mdbm/firstkey.c
if test 306 -ne `wc -c <./mdbm/firstkey.c`; then
    echo shar: \"./mdbm/firstkey.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/hash.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/hash.c\"
else
echo shar: Extracting \"./mdbm/hash.c\" \(1708 characters\)
sed "s/^X//" >./mdbm/hash.c <<'END_OF_./mdbm/hash.c'
X#include <stdio.h>
X#include "mdbm.h"
X#include "mdbm_local.h"
X
Xint hitab[16] = {
X/* ken's
X	055,043,036,054,063,014,004,005,
X	010,064,077,000,035,027,025,071, */
X
X	61, 57, 53, 49, 45, 41, 37, 33,
X	29, 25, 21, 17, 13,  9,  5,  1,
X};
X
Xlong hltab[64] = {
X	06100151277L,06106161736L,06452611562L,05001724107L,
X	02614772546L,04120731531L,04665262210L,07347467531L,
X	06735253126L,06042345173L,03072226605L,01464164730L,
X	03247435524L,07652510057L,01546775256L,05714532133L,
X	06173260402L,07517101630L,02431460343L,01743245566L,
X	00261675137L,02433103631L,03421772437L,04447707466L,
X	04435620103L,03757017115L,03641531772L,06767633246L,
X	02673230344L,00260612216L,04133454451L,00615531516L,
X	06137717526L,02574116560L,02304023373L,07061702261L,
X	05153031405L,05322056705L,07401116734L,06552375715L,
X	06165233473L,05311063631L,01212221723L,01052267235L,
X	06000615237L,01075222665L,06330216006L,04402355630L,
X	01451177262L,02000133436L,06025467062L,07121076461L,
X	03123433522L,01010635225L,01716177066L,05161746527L,
X	01736635071L,06243505026L,03637211610L,01756474365L,
X	04723077174L,03642763134L,05750130273L,03655541561L,
X};
X
X/*
X * Calculate the hash val for the given item.
X */
Xlong mdbm_calchash (s, len)
Xregister char *s;
Xregister int   len;
X{
X    register int    hashi = 0;
X    register long   hashl = 0L;
X
X    while (--len >= 0) {
X	register int    f = *s++;
X
X#if BYTESIZ > 4 && BYTESIZ <= 8	/* an easy optimization */
X	hashi += hitab[f & 15];
X	hashl += hltab[hashi & 63];
X	f >>= 4;
X	hashi += hitab[f & 15];
X	hashl += hltab[hashi & 63];
X#else
X	register int    j;
X
X	for (j = 0; j < BYTESIZ; j += 4) {
X	    hashi += hitab[f & 15];
X	    hashl += hltab[hashi & 63];
X	    f >>= 4;
X	}
X#endif
X    }
X    return hashl;
X}
END_OF_./mdbm/hash.c
if test 1708 -ne `wc -c <./mdbm/hash.c`; then
    echo shar: \"./mdbm/hash.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/hashinc.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/hashinc.c\"
else
echo shar: Extracting \"./mdbm/hashinc.c\" \(447 characters\)
sed "s/^X//" >./mdbm/hashinc.c <<'END_OF_./mdbm/hashinc.c'
X#ifndef lint
Xstatic char rcsid[] = "$Header: /ful/chris/dist/mdbm/hashinc.c,v 1.1 84/08/12 10:01:19 chris Rel $";
X#endif
X
X/*
X * Return the next hash number for this dbm, or 0 for no more
X */
Xlong mdbm_hashinc (hash, hmask)
Xregister long hash, hmask;
X{
X    register long   bit;
X
X    hash &= hmask;
X    bit = hmask + 1;
X    for (;;) {
X	bit >>= 1;
X	if (bit == 0)
X	    return 0L;
X	if ((hash & bit) == 0)
X	    return hash | bit;
X	hash &= ~bit;
X    }
X}
END_OF_./mdbm/hashinc.c
if test 447 -ne `wc -c <./mdbm/hashinc.c`; then
    echo shar: \"./mdbm/hashinc.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/mdbm.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/mdbm.h\"
else
echo shar: Extracting \"./mdbm/mdbm.h\" \(2312 characters\)
sed "s/^X//" >./mdbm/mdbm.h <<'END_OF_./mdbm/mdbm.h'
X/* $Header: /ful/chris/dist/mdbm/mdbm.h,v 1.1 84/08/12 10:05:08 chris Rel $ */
X
X/*
X * Multiple key database library (-lmdbm)
X */
X
X/* structure describing an open mdbm file */
Xstruct mdbm {
X	int	mdbm_flags;	/* flags (see below) */
X	int	mdbm_datafd;	/* data area file descriptor */
X	int	mdbm_mapfd;	/* bitmap file descriptor */
X	int	mdbm_dsize;	/* data buffer size */
X	int	mdbm_msize;	/* bitmap buffer size */
X	long	mdbm_maxbit;	/* max possible set bit in map + 1 */
X	long	mdbm_dblock;	/* index of current data block */
X	long	mdbm_mblock;	/* index of current map block */
X	char   *mdbm_d;		/* current data block */
X	char   *mdbm_s;		/* secondary data block */
X	char   *mdbm_m;		/* current map block */
X};
X
X/* structure giving (external) description of data and keys */
Xtypedef struct {
X	char   *dptr;
X	int	dsize;
X} datum;
X
X/*
X * mdbm_flags
X */
X#define	MDBM_ISRONLY	0x01	/* true => db is readonly */
X#define	MDBM_ISAUTOW	0x02	/* true => do all writes immediately */
X#define	MDBM_DDIRTY	0x04	/* true => data buffer out of sync */
X#define	MDBM_MDIRTY	0x08	/* true => map buffer out of sync */
X
X#define MDBM_UF		0x02	/* user allowed to modify only these flags */
X
X/*
X * flags to mdbm_store()
X */
X#define MDBM_INSERT	0	/* insert only; abort if key found */
X#define MDBM_REPLACE	1	/* replace (or insert if not found) */
X
Xdatum   mdbm_fetch ();
Xdatum   mdbm_firstkey ();
Xdatum   mdbm_nextkey ();
Xlong    mdbm_forder ();
Xint     mdbm_delete ();
Xint     mdbm_store ();
Xstruct mdbm *mdbm_open ();
Xint	mdbm_close ();
X
X/*
X * open flags the same as those for the open() system call
X * with the exception that we force O_RDWR for O_WRONLY opens.
X */
X
X/*
X * mdbm files contain a descriptive comment whose length is not
X * longer than this, and is (supposed to be) null terminated.
X */
X#define MDBM_CSIZ 248
X
X/*
X * ``routines'' to examine and alter flags
X */
X#define mdbm_getflags(m) \
X	((m) -> mdbm_flags)
X#define mdbm_setflags(m,f) \
X	((m) -> mdbm_flags &= ~MDBM_UF, (m) -> mdbm_flags |= (f) & MDBM_UF)
X#define mdbm_bisflags(m,f) \
X	((m) -> mdbm_flags |= (f) & MDBM_UF)
X#define mdbm_bicflags(m,f) \
X	((m) -> mdbm_flags &= ~((f) & MDBM_UF))
X
X/*
X * BSD-isms
X */
X#define	SYSV
X
X#ifdef SYSV
X#define bcmp(s1, s2, cnt) memcmp(s1,s2,cnt)
X#define bcopy(fr, to, cnt) memcpy(to,fr,cnt)
X#define bzero(addr,cnt) memset(addr,'\0',cnt)
X#endif
END_OF_./mdbm/mdbm.h
if test 2312 -ne `wc -c <./mdbm/mdbm.h`; then
    echo shar: \"./mdbm/mdbm.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/mdbm_local.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/mdbm_local.h\"
else
echo shar: Extracting \"./mdbm/mdbm_local.h\" \(4198 characters\)
sed "s/^X//" >./mdbm/mdbm_local.h <<'END_OF_./mdbm/mdbm_local.h'
X/* $Header: /ful/chris/dist/mdbm/mdbm_local.h,v 1.1 84/08/12 10:05:28 chris Rel $ */
X
X/*
X * Definitions local to the various mdbm source files
X */
X
X#define BYTESIZ		8	/* size of a byte */
X#define MAXUSHORT	65535	/* largest legal value for unsigned short */
X
X/* Default database sizes for new databases */
X#define MDBM_DefaultDataSize	1024	/* data buffer block size */
X#define MDBM_DefaultMapSize	4096	/* bitmap buffer block size */
X
X/* Minimum sizes.  Requests for anything smaller will be brought up
X   to these values. */
X#define MDBM_MinDataSize	128	/* minimum data buffer size */
X#define MDBM_MinMapSize		128	/* minimum map buffer size */
X
X/*
X * This structure goes in at the front of the map file.  It describes
X * the per-database info.  Typically the "comment" field contains the
X * name of the database.
X */
Xstruct mdbm_h {
X	int	mh_dsize;	/* size of data file blocks */
X	int	mh_msize;	/* size of map file blocks */
X	char	mh_comment[MDBM_CSIZ];/* whatever you like */
X};
X
X/*
X * Within the map file, we simply have bits set whenever a data block
X * was split.  The data file is more complex.  It contains the following
X * info in each block:
X *	# entries in block
X *	entries
X *	free space
X *	text
X *
X * where the format of an entry is (as given by struct mdbm_dentry)
X *	<off, links, inx, outx, outh>
X *
X * off is the offset within the block of the text (and thus also specifies
X * the size of the text string); links is the number of links to this item;
X * inx is the ``in index'' number of this item; outx is the ``out index''
X * number of this item; and outh is the out hash.
X *
X * If an item is in use as a key, its outx will contain a nonzero
X * number which is repeated in the inx field of its datum.  The hash value
X * in outh will (by the usual extensible hashing rules) determine a block
X * number, and the item with the matching inx field in that block is the
X * datum under the key in question.
X *
X * An item's inx field will always contain a nonzero number that is unique
X * to the block in which the item resides.
X */
Xstruct mdbm_dblock {
X	int db_n;	/* number of entries */
X	struct mdbm_dentry {
X		unsigned short de_off;	/* offset to beginning of text */
X		unsigned short de_links;/* number of links */
X		unsigned short de_inx;	/* in index */
X		unsigned short de_outx;	/* out index */
X		unsigned long  de_outh;	/* out hash */
X	} db_e[1];	/* actually db_e[db_n], but can't say that */
X};
X
X/* Some macros to simplify(?) things a bit */
X
X/* Read block blk (size sz offset off) from file f into buffer buf */
X#define MDBM_RBLK(f,blk,buf,sz,off) \
X	((void) lseek (f, (blk)*(sz)+(off), 0), (void) read (f, buf, sz))
X
X/* Write block blk (size sz offset off) to file f from buffer buf */
X#define	MDBM_WBLK(f,blk,buf,sz,off) \
X	((void) lseek (f, (blk)*(sz)+(off), 0), (void) write (f, buf, sz))
X
X/* Write (if needed) */
X#define MDBM_DSYNC(d) \
X    if ((d) -> mdbm_flags & MDBM_DDIRTY) { \
X	MDBM_WBLK ((d) -> mdbm_datafd, (d) -> mdbm_dblock, (d) -> mdbm_d, \
X		   (d) -> mdbm_dsize, 0); \
X	(d) -> mdbm_flags &= ~MDBM_DDIRTY; \
X    }
X
X#define MDBM_MSYNC(d) \
X    if ((d) -> mdbm_flags & MDBM_MDIRTY) { \
X	MDBM_WBLK ((d) -> mdbm_mapfd, (d) -> mdbm_mblock, (d) -> mdbm_m, \
X		   (d) -> mdbm_msize, sizeof (struct mdbm_h)); \
X	(d) -> mdbm_flags &= ~MDBM_MDIRTY; \
X    }
X
X#define MDBM_SYNC(d) { MDBM_DSYNC(d); MDBM_MSYNC(d); }
X
X/* Do autowrites */
X#define	MDBM_AUTO(d) if ((d) -> mdbm_flags & MDBM_ISAUTOW) MDBM_SYNC (d)
X
X/* Read data block b */
X#define	MDBM_DREAD(d,b) \
X    if ((d) -> mdbm_dblock != (b)) { \
X	MDBM_DSYNC (d); \
X	bzero ((d) -> mdbm_d, (d) -> mdbm_dsize); \
X	MDBM_RBLK ((d) -> mdbm_datafd, (d) -> mdbm_dblock = (b), \
X		   (d) -> mdbm_d, (d) -> mdbm_dsize, 0); \
X	mdbm_checkblock ((d) -> mdbm_d, (d) -> mdbm_dsize); \
X    }
X
X/* Read map block b */
X#define MDBM_MREAD(d,b) \
X    if ((d) -> mdbm_mblock != (b)) { \
X	MDBM_MSYNC (d); \
X	bzero ((d) -> mdbm_m, (d) -> mdbm_msize); \
X	MDBM_RBLK ((d) -> mdbm_mapfd, (d) -> mdbm_mblock = (b), \
X		   (d) -> mdbm_m, (d) -> mdbm_msize, sizeof (struct mdbm_h)); \
X    }
X
X/*
X * function types
X */
Xlong	mdbm_calchash ();
Xlong	mdbm_hashinc ();
Xstruct  mdbm_dentry *mdbm_search ();
Xdatum   mdbm_firsthash ();
Xlong	lseek ();
Xchar   *malloc ();
END_OF_./mdbm/mdbm_local.h
if test 4198 -ne `wc -c <./mdbm/mdbm_local.h`; then
    echo shar: \"./mdbm/mdbm_local.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/nextkey.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/nextkey.c\"
else
echo shar: Extracting \"./mdbm/nextkey.c\" \(1627 characters\)
sed "s/^X//" >./mdbm/nextkey.c <<'END_OF_./mdbm/nextkey.c'
X#ifndef lint
Xstatic char rcsid[] = "$Header: /ful/chris/dist/mdbm/nextkey.c,v 1.1 84/08/12 10:01:55 chris Rel $";
X#endif
X
X#include <stdio.h>
X#include "mdbm.h"
X#include "mdbm_local.h"
X
X/*
X * Return the "next" key in dbm d
X */
Xdatum mdbm_nextkey (d, key)
Xregister struct mdbm *d;
Xdatum key;
X{
X#define db ((struct mdbm_dblock *) d -> mdbm_d)
X    register struct mdbm_dentry *de;
X    register int    i;
X    char   *bp;
X    int     bl;
X    char   *ip;
X    int     il,
X            found;
X    long    hash,
X            hmask;
X    datum rval;
X
X /* Suck in the block for the given hash, then find the key that follows
X    the one given */
X    hash = mdbm_calchash (key.dptr, key.dsize);
X    hmask = mdbm_access (d, hash);
X    found = 0;
X#ifdef lint			/* lint doesn't realize that 'found'
X				   overrides the tests on bl and bp */
X    bl = 0;
X    bp = 0;
X#endif lint
X    for (i = 0, de = db -> db_e; i < db -> db_n; i++, de++) {
X	if (de -> de_outx == 0)	/* not a key */
X	    continue;
X	il = (i ? de[-1].de_off : d -> mdbm_dsize) - de -> de_off;
X	ip = d -> mdbm_d + de -> de_off;
X	if (il < key.dsize ||
X		(il == key.dsize && mdbm_compare (ip, key.dptr, il) <= 0))
X	    continue;
X	if (!found || il < bl || (il == bl && mdbm_compare (ip, bp, il) < 0)) {
X	    bl = il;
X	    bp = ip;
X	    found++;
X	}
X    }
X    if (found) {
X	bcopy (bp, rval.dptr = d -> mdbm_s, rval.dsize = bl);
X	return rval;
X    }
X
X /* No item with this hash, so get next hash and return its first item */
X    hash = mdbm_hashinc (hash, hmask);
X    if (hash == 0) {		/* no more */
X	rval.dsize = 0;
X	rval.dptr = 0;
X	return rval;
X    }
X    return mdbm_firsthash (d, hash);
X}
END_OF_./mdbm/nextkey.c
if test 1627 -ne `wc -c <./mdbm/nextkey.c`; then
    echo shar: \"./mdbm/nextkey.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/open.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/open.c\"
else
echo shar: Extracting \"./mdbm/open.c\" \(3310 characters\)
sed "s/^X//" >./mdbm/open.c <<'END_OF_./mdbm/open.c'
X#ifndef lint
Xstatic char rcsid[] = "$Header: /ful/chris/dist/mdbm/open.c,v 1.1 84/08/12 10:02:40 chris Rel $";
X#endif
X
X#include "mdbm.h"
X#include "mdbm_local.h"
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#ifdef SYSV
X#include <fcntl.h>
X#else
X#include <sys/file.h>
X#endif
X#include <errno.h>
X
X/*
X * Open or create a database
X */
Xstruct mdbm *mdbm_open (file, flags, mode, adsize, amsize, comment)
Xchar *file;
Xint flags, mode;
Xint *adsize, *amsize;
Xchar *comment;
X{
X    register struct mdbm   *d;
X    struct stat stat;
X    struct mdbm_h   mdbm_h;
X    int     dsize,
X            msize,
X            l;
X    char   *namebuf,
X           *p;
X    char   *strcpy ();
X    char   *strncpy ();
X    extern int  errno;
X
X /* get a descriptor */
X    if ((d = (struct mdbm *) malloc (sizeof *d)) == 0) {
X	errno = ENOMEM;
X	return 0;
X    }
X /* get enough room for the file names */
X    l = strlen (file);
X    if ((namebuf = malloc ((unsigned) (l + 5))) == 0) {
X	l = ENOMEM;
X	goto out;
X    }
X
X /* find out how big the buffers should be, if this is a new db */
X    dsize = adsize == 0 || *adsize == 0 ? MDBM_DefaultDataSize : *adsize;
X    msize = amsize == 0 || *amsize == 0 ? MDBM_DefaultMapSize : *amsize;
X    if (dsize < MDBM_MinDataSize)
X	dsize = MDBM_MinDataSize;
X    if (msize < MDBM_MinMapSize)
X	msize = MDBM_MinMapSize;
X
X /* fix up the mode, then open them files */
X    if ((flags & 3) == O_WRONLY)
X	flags = (flags & ~3) | O_RDWR;
X    (void) strcpy (namebuf, file);
X    p = &namebuf[l];
X    (void) strcpy (p, ".dat");
X    if ((d -> mdbm_datafd = open (namebuf, flags, mode)) < 0) {
X	l = errno;
X	goto out;
X    }
X    (void) strcpy (p, ".map");
X    if ((d -> mdbm_mapfd = open (namebuf, flags, mode)) < 0) {
X	l = errno;
X	goto out1;
X    }
X    free (namebuf);
X
X /* initialize the dbm descriptor */
X    d -> mdbm_flags = (flags & 3) == O_RDONLY ? MDBM_ISRONLY : 0;
X
X    (void) fstat (d -> mdbm_mapfd, &stat);
X    if (stat.st_size == 0) {
X	mdbm_h.mh_dsize = dsize;
X	mdbm_h.mh_msize = msize;
X	bzero (mdbm_h.mh_comment, MDBM_CSIZ);
X	(void) strncpy (mdbm_h.mh_comment,
X		comment && *comment ? comment : file, MDBM_CSIZ);
X	mdbm_h.mh_comment[MDBM_CSIZ - 1] = 0;
X	if ((d -> mdbm_flags & MDBM_ISRONLY) == 0)
X	    if (write (d -> mdbm_mapfd, (char *) & mdbm_h, sizeof mdbm_h) !=
X		    sizeof mdbm_h)
X		goto out2;
X    }
X    else {
X	if (read (d -> mdbm_mapfd, (char *) & mdbm_h, sizeof mdbm_h) !=
X		sizeof mdbm_h) {
X	    l = EINVAL;
X	    goto out2;
X	}
X	dsize = mdbm_h.mh_dsize;
X	msize = mdbm_h.mh_msize;
X    }
X    if (adsize)
X	*adsize = dsize;
X    if (amsize)
X	*amsize = msize;
X    if (comment)
X	(void) strncpy (comment, mdbm_h.mh_comment, MDBM_CSIZ);
X    if ((d -> mdbm_d = malloc ((unsigned) dsize)) == 0) {
X	l = ENOMEM;
X	goto out2;
X    }
X    if ((d -> mdbm_s = malloc ((unsigned) dsize)) == 0) {
X	free (d -> mdbm_d);
X	l = ENOMEM;
X	goto out2;
X    }
X    if ((d -> mdbm_m = malloc ((unsigned) msize)) == 0) {
X	free (d -> mdbm_s);
X	free (d -> mdbm_d);
X	l = ENOMEM;
X	goto out2;
X    }
X    d -> mdbm_dsize = dsize;
X    d -> mdbm_msize = msize;
X    d -> mdbm_maxbit = (stat.st_size - sizeof mdbm_h) * BYTESIZ;
X    d -> mdbm_dblock = -1;
X    d -> mdbm_mblock = -1;
X
X    return d;
X
Xout2: 
X    (void) close (d -> mdbm_datafd);
Xout1: 
X    (void) close (d -> mdbm_mapfd);
Xout: 
X    free ((char *) d);
X    errno = l;
X    return 0;
X}
END_OF_./mdbm/open.c
if test 3310 -ne `wc -c <./mdbm/open.c`; then
    echo shar: \"./mdbm/open.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/search.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/search.c\"
else
echo shar: Extracting \"./mdbm/search.c\" \(1528 characters\)
sed "s/^X//" >./mdbm/search.c <<'END_OF_./mdbm/search.c'
X#ifndef lint
Xstatic char rcsid[] = "$Header: /ful/chris/dist/mdbm/search.c,v 1.1 84/08/12 10:03:12 chris Rel $";
X#endif
X
X#include <stdio.h>
X#include "mdbm.h"
X#include "mdbm_local.h"
X
X/*
X * Search for the given key, and if found, return a pointer to the
X * datum under the key.  If ablock and aindex are nonzero, fill in
X * the block and index numbers of the key.  If justkey is true,
X * forget about the datum and stop when the key is found.
X *
X * (Workhorse for fetch, also used by delete & store.)
X */
Xstruct mdbm_dentry *mdbm_search (d, s, len, ablock, aindex, justkey)
Xregister struct mdbm *d;
Xchar *s;
Xregister int len;
Xlong *ablock;
Xint *aindex;
Xint justkey;
X{
X#define db ((struct mdbm_dblock *) d -> mdbm_d)
X    register struct mdbm_dentry *de;
X    register int    i;
X    register unsigned short outx;
X    long    outh;
X
X    (void) mdbm_access (d, mdbm_calchash (s, len));
X    for (i = 0, de = db -> db_e; i < db -> db_n; i++, de++) {
X	if (de -> de_outx == 0)	/* not a key */
X	    continue;
X	if (len == (i ? de[-1].de_off : d -> mdbm_dsize) - de -> de_off)
X	    if (bcmp (s, d -> mdbm_d + de -> de_off, len) == 0)
X		goto found;
X    }
X    return 0;
Xfound: 
X    if (ablock)
X	*ablock = d -> mdbm_dblock;
X    if (aindex)
X	*aindex = i;
X    if (justkey)
X	return de;
X    outx = de -> de_outx;
X    (void) mdbm_access (d, outh = de -> de_outh);
X    for (i = 0, de = db -> db_e; i < db -> db_n; i++, de++)
X	if (de -> de_inx == outx)
X	    return de;
X    printf ("mdbm bug: no datum for key (%d, %d)\n", outh, outx);
X    return 0;
X}
END_OF_./mdbm/search.c
if test 1528 -ne `wc -c <./mdbm/search.c`; then
    echo shar: \"./mdbm/search.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/sync.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/sync.c\"
else
echo shar: Extracting \"./mdbm/sync.c\" \(423 characters\)
sed "s/^X//" >./mdbm/sync.c <<'END_OF_./mdbm/sync.c'
X#ifndef lint
Xstatic char rcsid[] = "$Header: /ful/chris/dist/mdbm/sync.c,v 1.1 84/08/12 10:04:03 chris Rel $";
X#endif
X
X#include <stdio.h>
X#include "mdbm.h"
X#include "mdbm_local.h"
X
X/*
X * Sync the file attached to dbm d
X */
Xmdbm_sync (d)
Xregister struct mdbm *d;
X{
X    MDBM_SYNC (d);
X#ifdef SYSV
X    (void) sync ();
X    (void) sync ();
X#else
X    (void) fsync (d -> mdbm_datafd);
X    (void) fsync (d -> mdbm_mapfd);
X#endif
X}
END_OF_./mdbm/sync.c
if test 423 -ne `wc -c <./mdbm/sync.c`; then
    echo shar: \"./mdbm/sync.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/testdbm.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/testdbm.c\"
else
echo shar: Extracting \"./mdbm/testdbm.c\" \(5554 characters\)
sed "s/^X//" >./mdbm/testdbm.c <<'END_OF_./mdbm/testdbm.c'
X#ifndef lint
Xstatic char rcsid[] = "$Header: /ful/chris/dist/mdbm/testdbm.c,v 1.1 84/08/12 10:04:23 chris Rel $";
X#endif lint
X
X/*
X * testdbm - test the new multiple key database library
X */
X
X#include "mdbm.h"
X#include <stdio.h>
X#include <sys/types.h>
X#ifdef SYSV
X#include <fcntl.h>
X#else
X#include <sys/file.h>
X#endif
X#include <ctype.h>
X
Xstruct mdbm *mp;
X#define NAV 10
Xstruct stringarg {
X	int s_len;
X	char *s_str;
X} av[NAV];
X
Xint c_open (), c_close (), c_fetch (), c_insert (), c_replace ();
Xint c_delete (), c_list (), c_quit (), c_sync ();
X
Xstruct cmd {
X	char *c_name;
X	int (*c_func)();
X	int   c_args;
X} cmds[] = {
X	"open",		c_open,		2,
X	"open",		c_open,		4,
X	"open",		c_open,		5,
X	"close",	c_close,	1,
X	"fetch",	c_fetch,	2,
X	"get",		c_fetch,	2,
X	"insert",	c_insert,	3,
X	"store",	c_insert,	3,
X	"replace",	c_replace,	3,
X	"delete",	c_delete,	2,
X	"list",		c_list,		1,
X	"quit",		c_quit,		1,
X	"sync",		c_sync,		1,
X	0, 0, 0
X};
Xchar serrbuf[BUFSIZ];
X
X#define checkdb() \
X	if (!mp) { \
X		fprintf (stderr, "no database active\n"); \
X		return; \
X	} \
X	else
X
Xmain () {
X	char cmdbuf[BUFSIZ];
X
X	setbuf (stderr, serrbuf);
X	for (;;) {
X		fflush (stderr);
X		printf ("testdbm> ");
X		fflush (stdout);
X		if (fgets (cmdbuf, sizeof cmdbuf, stdin) == NULL) {
X			putchar ('\n');
X			c_quit (0);
X		}
X		if (doit (cmdbuf))
X			printf ("Eh?\n");
X	}
X}
X
Xdoit (s)
Xchar *s;
X{
X	register int argc = parse (s);
X	register struct cmd *cp;
X
X	if (argc < 1)
X		return 0;
X	if (av[0].s_len < 1)
X		return 1;
X	for (cp = cmds; cp -> c_name; cp++) {
X		if (cp -> c_args != argc)
X			continue;
X		if (strncmp (cp -> c_name, av[0].s_str, av[0].s_len) == 0) {
X			(*cp -> c_func) (argc);
X			return 0;
X		}
X	}
X	return 1;
X}
X
Xc_open (argc) {
X	int dsize, msize;
X	static char comment[MDBM_CSIZ];
X
X	if (mp)
X		(void) mdbm_close (mp);
X	if (argc == 5)
X		strncpy (comment, av[4].s_str, sizeof comment);
X	else
X		*comment = 0;
X	if (argc >= 4) {
X		dsize = atoi (av[2].s_str);
X		msize = atoi (av[3].s_str);
X	}
X	else
X		dsize = msize = 0;
X	mp = mdbm_open (av[1].s_str, O_RDWR|O_CREAT, 0666, &dsize, &msize, comment);
X	if (mp == 0) {
X		fprintf (stderr, "can't open ");
X		perror (av[1].s_str);
X		return;
X	}
X	comment[sizeof comment - 1] = 0;
X	printf ("opened %s - dsize %d, msize %d, comment %s\n",
X		av[1].s_str, dsize, msize, comment);
X}
X
Xc_close (argc) {
X	if (mp)
X		(void) mdbm_close (mp);
X	mp = 0;
X}
X
Xc_fetch (argc) {
X	datum key, dat;
X
X	checkdb ();
X	key.dptr = av[1].s_str;
X	key.dsize = av[1].s_len;
X	dat = mdbm_fetch (mp, key);
X	prdatum (key);
X	printf (": ");
X	if (dat.dptr == 0)
X		printf ("not found");
X	else
X		prdatum (dat);
X	putchar ('\n');
X}
X
Xprdatum (d)
Xdatum d;
X{
X	register char *p;
X	register int c;
X	register int i;
X
X	i = d.dsize;
X	p = d.dptr;
X	while (--i >= 0) {
X		c = *p++ & 0377;
X		if (c & 0200) {
X			putchar ('M'), putchar ('-');
X			c &= 0177;
X		}
X		if (c == 0177 || c < ' ') {
X			putchar ('^');
X			if (c == 0177)
X				putchar ('?');
X			else
X				putchar (c + '@');
X		}
X		else
X			putchar (c);
X	}
X}
X
Xc_insert (argc) {
X	datum key, dat;
X	int e;
X
X	checkdb ();
X	key.dptr = av[1].s_str;
X	key.dsize = av[1].s_len;
X	dat.dptr = av[2].s_str;
X	dat.dsize = av[2].s_len;
X	e = mdbm_store (mp, key, dat, MDBM_INSERT);
X	if (e == 0)
X		return;
X	if (e < 0)
X		perror ("store failed");
X	else
X		fprintf (stderr, "insert failed, key in use\n");
X}
X
Xc_replace (argc) {
X	datum key, dat;
X	int e;
X
X	checkdb ();
X	key.dptr = av[1].s_str;
X	key.dsize = av[1].s_len;
X	dat.dptr = av[2].s_str;
X	dat.dsize = av[2].s_len;
X	if (mdbm_store (mp, key, dat, MDBM_REPLACE))
X		perror ("store failed");
X}
X
Xc_delete (argc) {
X	datum key;
X
X	checkdb ();
X	key.dptr = av[1].s_str;
X	key.dsize = av[1].s_len;
X	if (mdbm_delete (mp, key))
X		perror ("delete failed");
X}
X
Xc_list () {
X	datum key, dat;
X
X	checkdb ();
X	for (key = mdbm_firstkey (mp); key.dptr; key = mdbm_nextkey (mp, key)) {
X		dat = mdbm_fetch (mp, key);
X		prdatum (key);
X		printf (": ");
X		if (dat.dptr == 0)
X			printf ("datum not found!");
X		else
X			prdatum (dat);
X		putchar ('\n');
X	}
X}
X
Xc_quit () {
X	if (mp)
X		(void) mdbm_close (mp);
X	exit (0);
X}
X
Xc_sync () {
X	checkdb ();
X	mdbm_sync (mp);
X}
X
Xparse (s)
Xregister char *s;
X{
X    register struct stringarg  *ap;
X    register int    aleft;
X    register int    qu = 0;
X    register char  *cp;
X    register int    c;
X    static char xbuf[BUFSIZ];
X    char *malloc ();
X
X    for (ap = av, aleft = NAV; --aleft >= 0; ap++)
X	if (ap -> s_str) {
X	    free (ap -> s_str);
X	    ap -> s_str = 0;
X	}
X
X    ap = av;
X    aleft = NAV;
X    while (*s) {
X	while (isspace (*s))
X	    s++;
X	if (!*s)
X	    break;
X	qu = 0;
X	cp = xbuf;
X	while (((c = *s) != 0) && (qu || !isspace (c))) {
X	    s++;
X	    if (qu == '\\') {
X		switch (c) {
X		    case 'n': 
X			c = '\n';
X			break;
X		    case 'r': 
X			c = '\r';
X			break;
X		    case 't': 
X			c = '\t';
X			break;
X		    case 'b': 
X			c = '\b';
X			break;
X		    case 'f': 
X			c = '\f';
X			break;
X		    case '0': 
X		    case '1': 
X		    case '2': 
X		    case '3': 
X		    case '4': 
X		    case '5': 
X		    case '6': 
X		    case '7': 
X			c -= '0';
X			if (*s >= '0' && *s <= '7') {
X			    c = (c << 3) + *s++ - '0';
X			    if (*s >= '0' && *s <= '7')
X				c = (c << 3) + *s++ - '0';
X			}
X			break;
X		}
X		*cp++ = c;
X		qu = 0;
X	    }
X	    else if (c == qu)
X		qu = 0;
X	    else if (qu == 0 && (c == '\'' || c == '"' || c == '\\'))
X		qu = c;
X	    else
X		*cp++ = c;
X	}
X	*cp++ = 0;
X	if (--aleft < 0) {
X	    fprintf (stderr, "too many argv's\n");
X	    return 0;
X	}
X	ap -> s_str = malloc (cp - xbuf);
X	ap -> s_len = cp - xbuf;
X	bcopy (xbuf, ap -> s_str, ap -> s_len);
X	ap -> s_len--;		/* stop counting trailing \0 */
X	ap++;
X    }
X    return NAV - aleft;
X}
END_OF_./mdbm/testdbm.c
if test 5554 -ne `wc -c <./mdbm/testdbm.c`; then
    echo shar: \"./mdbm/testdbm.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 1 \(of 2\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

---

But don't underestimate raw, frothing, manic hardware.
				(barry shein)
Randy Suess
..!att!chinet!randy
-- 
But don't underestimate raw, frothing, manic hardware.
				(barry shein)
Randy Suess
..!att!chinet!randy

randy@chinet.UUCP (Randy Suess) (06/14/88)

Part 2 of the mdbm shar


#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 2)."
# Contents:  ./mdbm/mdbm.3x ./mdbm/store.c
# Wrapped by randy@chinet on Wed Jun  8 13:52:20 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f ./mdbm/mdbm.3x -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/mdbm.3x\"
else
echo shar: Extracting \"./mdbm/mdbm.3x\" \(9018 characters\)
sed "s/^X//" >./mdbm/mdbm.3x <<'END_OF_./mdbm/mdbm.3x'
X.TH MDBM 3X 
X.UC 4 \" well not really but . . .
X.SH NAME
Xmdbm_open, mdbm_fetch, mdbm_store, mdbm_delete, mdbm_firstkey, ... \- multiple key hashed data base subroutines
X.SH SYNOPSIS
X.nf
X.PP
X.B #include <mdbm.h>
X.B "\fP/* \fBtypedef struct {"
X.B "	char *dptr;"
X.B "	int dsize;"
X.BR "} datum; " "*/ /* in <mdbm.h> */"
X.PP
X.B struct mdbm *
X.B mdbm_open(file, flags, mode, adsize, amsize, comment)
X.B char *file;
X.B int flags, mode;
X.B int *adsize, *amsize;
X.B char *comment;
X.PP
X.B datum mdbm_fetch(d, key)
X.B struct mdbm *d;
X.B datum key;
X.PP
X.B mdbm_store(d, key, content, replace)
X.B struct mdbm *d;
X.B datum key, content;
X.B int replace;
X.PP
X.B mdbm_delete(d, key)
X.B struct mdbm *d;
X.B datum key;
X.PP
X.B datum mdbm_firstkey(d)
X.B struct mdbm *d;
X.PP
X.B datum mdbm_nextkey(d, key)
X.B struct mdbm *d;
X.B datum key;
X.PP
X.B mdbm_sync(d)
X.B struct mdbm *d;
X.PP
X.B mdbm_close(d)
X.B struct mdbm *d;
X.PP
X.B mdbm_getflags(d, flags)
X.B struct mdbm *d;
X.B int flags;
X.PP
X.B mdbm_setflags(d, flags)
X.B struct mdbm *d;
X.B int flags;
X.PP
X.B mdbm_bisflags(d, flags)
X.B struct mdbm *d;
X.B int flags;
X.PP
X.B mdbm_bicflags(d, flags)
X.B struct mdbm *d;
X.B int flags;
X.SH DESCRIPTION
XThese functions maintain key/content pairs in a database.
XThe functions will handle very large (a billion blocks)
Xdatabases and will usually access a keyed item in one or two file
Xsystem accesses.  The functions are obtained with the loader option
X.BR \-lmdbm .
X.PP
X.IR Key s
Xand
X.IR content s
Xare described by the
X.I datum
Xtypedef, which is defined in the include file
X.IR mdbm.h .
XA
X.I datum
Xspecifies a string of
X.I dsize
Xbytes pointed to by
X.I dptr.
XArbitrary binary data, as well as normal ASCII strings, are allowed.
XThe database is stored in two files.  One file is a directory
Xcontaining a bit map and has ``.map'' as its suffix.  The second
Xfile contains all data and has ``.dat'' as its suffix.
X.PP
XBefore a database can be accessed, it must be opened by
X.I mdbm_open.
XThe
X.I flags
Xare simply passed to the open system call (see
X.IR open(2) ).
X(This is not strictly true:  if the read/write mode is O_WRONLY, it
Xis converted internally to O_RDWR.)
X.PP
XThe
X.I mode
Xparameter is only used with
X.B O_CREAT
Xwhen creating a new database.
XThe value is merely passed to the
X.I open
Xsystem call.
XIf
X.B O_CREAT
Xis not specified, the ``.map'' and ``.dat'' files must exist.
X.I mdbm_open
Xreturns a pointer to the database for use by the other mdbm routines.
XIf the database cannot be opened,
X.I mdbm_open
Xreturns NULL.
X.PP
XThe
X.I adsize
Xand
X.I amsize
Xparameters, if non-null, should point to integers containing the
Xdesired data and map block sizes of the database.  On return, these
Xvariables will have been filled in with the actual sizes in use.
X(The values are only used when creating a database, but are always
Xmodified on return.)  If the default sizes are acceptable, these
Xtwo parameters may be given as null pointers.
X.PP
XThe
X.I comment
Xparameter, like the
X.I adsize
Xand
X.I amsize
Xparameters, is ``value-result''.  When a new database is created
Xa comment of up to MDBM_CSIZ characters is stored along with it.
X.I Comment
Xshould be a pointer to an array of at least MDBM_CSIZ characters.
XIt will be used to initialize the comment for a new database and
Xwill be filled in with a null terminated string when opening an
Xexisting datbase.  If the comment information
Xis not desired, the parameter may be given as zero; in this case
Xthe file name will be used to initialize the comment field of a
Xnew database.
X.PP
XOnce open, the data stored under a key is accessed by
X.I mdbm_fetch
Xand data is placed under a key by
X.IR mdbm_store .
XA key (and its associated contents) is deleted by
X.IR mdbm_delete .
XA linear pass through all keys in a database
Xmay be made, in an (apparently) random order, by use of
X.I mdbm_firstkey
Xand
X.IR mdbm_nextkey .
X.I Mdbm_firstkey
Xwill return the first key in the database.  With any key
X.I mdbm_nextkey
Xwill return the next key in the database.
XThis code will traverse the database d:
X.IP
X.B for
X(key = mdbm_firstkey(d); key.dptr != NULL; key = mdbm_nextkey(d, key))
X.PP
X.I mdbm_sync
Xwill complete any pending writes on the database.  (If the
X.B MDBM_ISAUTOW
Xflag has been set \- see
X.I mdbm_setflags
Xbelow \- then no writes will be pending).  In any case
X.I mdbm_sync
Xcalls
X.I fsync
Xon the map and data file descriptors.
X.PP
XA database may be closed (and the associated storage and file
Xdescriptors released) with
X.IR mdbm_close .
X.PP
XWritable databases
X.I must
Xbe closed before exiting to ensure that all data are written.
X(To be precise, this is only necessary if the
X.B MDBM_ISAUTOW
Xflag was not on, and no
X.I mdbm_sync
Xhas been done since the last
X.IR mdbm_store ).
X.PP
XThe fourth parameter to store (``replace'') specifies what to
Xdo in the event of a key collision.  The value
X.B MDBM_INSERT
X(0) makes
X.I mdbm_store
Xreturn the error value 1 in the event that the given key already
Xpoints to a particular datum.  The value
X.B MDBM_REPLACE
X(actually your favorite nonzero value will do) tells
Xstore to go ahead and replace the old datum.
X.PP
XVarious flags may be examined and set with the
X.I mdbm_getflags
Xand
X.I mdbm_setflags
Xmacros.  Currently there are only four flags, and only one of these
Xis user settable.  They are:
X.TP
X.B MDBM_ISRONLY
XIndicates that a database was opened with O_RDONLY and cannot be written.
X.I (Store
Xand friends return an error indication and set
X.B errno
X(see
X.IR intro(2) )
Xto
X.B EPERM
Xif they are asked to operate on a read-only database.)
X.TP
X.B MDBM_ISAUTOW
XSpecifies that all modifications to the database be written to the system
Ximmediately (note that
X.IR fsync s
Xare
X.I not
Xdone in this case).  This might be useful for an interactive program,
Xto reduce the chances of loss of data in the event of a system crash.
XThis is currently the only user settable flag.
X.TP
X.B MDBM_DDIRTY
XIndicates that the data buffer is out of sync with its disk file.
X.TP
X.B MDBM_MDIRTY
XIndicates that the bitmap buffer is out of sync with its disk file.
X.PP
XThe
X.I mdbm_setflags
Xroutine will set the user-settable flags to the values in its second
Xargument.  The
X.I mdbm_getflags
Xroutine returns all the flags in the database.  The
X.I mdbm_bisflags
Xturns on the indicated user-settable flags, and the
X.I mdbm_bicflags
Xturns off the indicated flags.  E.g., The C statement
X.I mdbm_bisflags(d, \fP\fBMDBM_ISAUTOW\fP\fI)
Xwould turn on the auto-write flag.
X.SH "But what about multiple keys?"
X.PP
XThe database routines invisibly keep track of how many keys are pointing
Xto a particular datum, and ensure that the datum itself is not removed
Xuntil it is no longer in use.  In fact, a datum may also be used as a key.
XThus there is no storage penalty for having many keys that point to one
Xdatum or even to themselves.
X.PP
XThe implementation of this involved changing the underlying structure
Xof the database.  Keys and data are no longer stored in pairs; instead,
Xeach data block contains an arbitrary number of items each with
Xincoming and outgoing link indicies.  In addition to breaking anything
Xthat depended on the old implementation, this means that in most cases
Xtwo file system accesses are required to fetch a particular datum given
Xa key (one to find the key and another to find its datum).  However,
Xthis is offset by the new 4.2BSD file system, which will probably
Ximprove access times for all but the largest databases.
X.SH DIAGNOSTICS
XAll functions that return an
X.I int
Xindicate errors with negative values.  A zero return indicates OK.
XRoutines that return a
X.I datum
Xindicate errors with a NULL (0)
X.IR dptr .
X.I mdbm_open
Xreturns NULL on error.
X.SH AUTHORS
XI don't know who wrote the original dbm code, but Chris Torek
Xmodified it to handle multiple databases, changed the internal
Xformat to support multiple keys, and added anything
Xthat you see here and not in dbm (see
X.IR dbm(3) ).
X.SH "SEE ALSO"
X.I dbm(3)
X.SH BUGS
XThe ``.dat'' file will contain holes so that its apparent size is
X(usually) two to four times its actual content.  Older UNIX systems
Xmay create real file blocks for these holes when touched.  These files
Xcannot be copied by normal means (cp, cat, tp, tar, ar) without filling
Xin the holes.
X.PP
X.I Dptr
Xpointers returned by these subroutines
Xpoint into static storage that is changed by subsequent calls.
X.PP
XThe previously undocumented
X.I forder
Xfunction is defunct.  (It used to return the block number given a key.)
X.PP
XThe size of a key or content string must not exceed the data block size
Xused when creating the database.  Moreover, all strings that hash
Xtogether must fit on a single block.
X.I Mdbm_store
Xwill return an error in the event that a block fills with
Xinseparable data.
X.PP
X.I Mdbm_delete
Xdoes not physically reclaim file space,
Xalthough it does make it available for reuse.
X.PP
XDisk errors are not handled at all.  No warning is given when a
Xdisk read or write fails, and data may be lost or destroyed afterwards.
X.PP
XThe order of keys presented by
X.I mdbm_firstkey
Xand
X.I mdbm_nextkey
Xdepends on a hashing function, not on anything interesting.
END_OF_./mdbm/mdbm.3x
if test 9018 -ne `wc -c <./mdbm/mdbm.3x`; then
    echo shar: \"./mdbm/mdbm.3x\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ./mdbm/store.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"./mdbm/store.c\"
else
echo shar: Extracting \"./mdbm/store.c\" \(7864 characters\)
sed "s/^X//" >./mdbm/store.c <<'END_OF_./mdbm/store.c'
X#ifndef lint
Xstatic char rcsid[] = "$Header: /ful/chris/dist/mdbm/store.c,v 1.1 84/08/12 10:03:37 chris Rel $";
X#endif
X
X#include <stdio.h>
X#include <errno.h>
X#include "mdbm.h"
X#include "mdbm_local.h"
X
X/*
X * Exhaustively search for a valid inx index number for the new entry
X * in d.  We "guarantee" that one such will be available.  (Used by
X * mdbm_dostore)
X */
Xstatic unsigned short mdbm_inx (d)
Xregister struct mdbm *d;
X{
X#define db ((struct mdbm_dblock *) d -> mdbm_d)
X    register struct mdbm_dentry *de;
X    register int    i,
X                    n = db -> db_n - 1;
X    register unsigned short inx = 1;
X
X    for (;;) {
X	de = db -> db_e;
X	i = n;
X	while (--i >= 0) {
X	    if (de -> de_inx == inx)
X		goto nope;
X	    de++;
X	}
X	return inx;
Xnope:
X	if (inx == MAXUSHORT)
X	    break;
X	inx++;
X    }
X    printf ("mdbm bug: no inx's available (can't happen)\n");
X    fflush(stdout);
X    abort ();
X    return 1;
X#undef db
X}
X
X/*
X * Add an item to a data block, returning a pointer to the dentry
X * descriptor (or 0 if it doesn't fit).  The caller will fill in all
X * fields except the offset, and will fill in the text of the item.
X */
Xstatic struct mdbm_dentry *mdbm_additem (buf, dsize, len)
Xregister char *buf;
Xint dsize, len;
X{
X#define db ((struct mdbm_dblock *) buf)
X    register struct mdbm_dentry *de;
X    register int    i = db -> db_n;
X
X /* Figure out where the text should go.  If there are no entries in this
X    block, it will go at the end of the block; otherwise, it will go right
X    before the last entry.  It must not cross over the entry descriptor
X    area, which will be one larger than it is now. */
X    de = &db -> db_e[i];
X    i = (i ? de[-1].de_off : dsize) - len;
X    if (buf + i < (char *) &de[1])
X	return 0;
X
X    db -> db_n++;
X    de -> de_off = i;
X    return de;
X#undef db
X}
X
X/*
X * Actually store the text of an item in a dblock.  Fill in the supplied
X * pointer (if any) with the hash number of the item.  Also, if a split
X * occurs, check *asplit, and if the block numbers match, set *asplit,
X * otherwise clear it.  (Used by mdbm_store)
X */
Xstatic struct mdbm_dentry *mdbm_dostore (d, s, len, ahash, asplit)
Xregister struct mdbm *d;
Xchar *s;
Xint   len;
Xlong *ahash;
Xlong *asplit;
X{
X#define db ((struct mdbm_dblock *) d -> mdbm_d)
X    register struct mdbm_dentry *de;
X    register int    i;
X    long    hash;
X    long    hmask;
X    long    IfSplit;
X    unsigned int    minx = MAXUSHORT,
X                    maxx = 0;
X
X    hash = mdbm_calchash (s, len);
X    if (ahash)
X	*ahash = hash;
X    if (asplit) {
X	IfSplit = *asplit;
X	*asplit = 0;
X    }
Xloop:
X    {
X	register int rlen = len;
X
X	hmask = mdbm_access (d, hash);
X	for (i = 0, de = db -> db_e; i < db -> db_n; i++, de++) {
X	    if (rlen == (i ? de[-1].de_off : d -> mdbm_dsize) - de -> de_off)
X		if (bcmp (s, d -> mdbm_d + de -> de_off, rlen) == 0) {
X		    de -> de_links++;
X		    goto returnit;
X		}
X	    if (de -> de_inx < minx)
X		minx = de -> de_inx;
X	    if (de -> de_inx > maxx)
X		maxx = de -> de_inx;
X	}
X	de = mdbm_additem (d -> mdbm_d, d -> mdbm_dsize, rlen);
X    }
X    if (de) {
X	de -> de_links = 1;	/* will be either a key or a datum */
X	de -> de_outx = 0;	/* not a key (at least, not yet) */
X    /* inx will be one less than min inx (if possible), or one more than
X       max inx (if possible), that occur in the block.  If none of those
X       yeild results, we perform an exhaustive search.  Hopefully the
X       searches are rare. */
X	if (i == 0)
X	    de -> de_inx = 1;	/* first one, special case */
X	else if (minx < MAXUSHORT && minx > 1)
X	    de -> de_inx = minx - 1;
X	else if (maxx && maxx < MAXUSHORT)
X	    de -> de_inx = maxx + 1;
X	else
X	    de -> de_inx = mdbm_inx (d);
X	bcopy (s, d -> mdbm_d + de -> de_off, len);
Xreturnit:
X	d -> mdbm_flags |= MDBM_DDIRTY;
X	return de;
X    }
X /* Didn't fit; split the block to make room.  Presumably about half of the
X    existing entries will move to the new block. */
X    if (len + sizeof *db > d -> mdbm_dsize)
X	return 0;		/* hopeless! */
X /* If we are splitting the "interesting" block, make a note of that fact */
X    if (asplit && IfSplit == d -> mdbm_dblock)
X	*asplit = 1;
X    bzero (d -> mdbm_s, d -> mdbm_dsize);
X    hmask++;
X    for (i = 0, de = db -> db_e; i < db -> db_n;) {
X	register int    l;
X	register char  *p = d -> mdbm_d + de -> de_off;
X
X	l = (i ? de[-1].de_off : d -> mdbm_dsize) - de -> de_off;
X	if (mdbm_calchash (p, l) & hmask) {
X	    register struct mdbm_dentry *nde;
X
X	    nde = mdbm_additem (d -> mdbm_s, d -> mdbm_dsize, l);
X	    bcopy (p, d -> mdbm_s + nde -> de_off, l);
X	    nde -> de_links = de -> de_links;
X	    nde -> de_inx = de -> de_inx;
X	    nde -> de_outx = de -> de_outx;
X	    nde -> de_outh = de -> de_outh;
X	    de -> de_links = 1;	/* force mdbm_delitem to remove it */
X	    mdbm_delitem (d, de - db -> db_e);
X	}
X	else
X	    i++, de++;
X    }
X    MDBM_WBLK (d -> mdbm_datafd, d -> mdbm_dblock + hmask, d -> mdbm_s,
X	    d -> mdbm_dsize, 0);
X    d -> mdbm_flags |= MDBM_DDIRTY;
X    hmask--;
X /* Now mark the block as having been split by setting the appropriate bit in
X    the map. */
X    {
X	register long   bit = (hash & hmask) + hmask;
X	register int    n;
X	register long   bn;
X
X	n = bit % BYTESIZ;	/* bit index */
X	bn = bit / BYTESIZ;	/* byte index */
X	i = bn % d -> mdbm_msize;/* byte offset in block */
X	if (bit >= d -> mdbm_maxbit) {
X	    d -> mdbm_maxbit = bit + 1;
X	    bn /= d -> mdbm_msize;/* map block number */
X	    MDBM_MREAD (d, bn);	/* read will probably fail, but this fills
X				   in the block numbers and so forth */
X	}
X	d -> mdbm_m[i] |= 1 << n;/* set the bit */
X	d -> mdbm_flags |= MDBM_MDIRTY;
X    }
X    goto loop;
X#undef db
X}
X
X/*
X * Store dat as datum of key key in dbm d
X */
Xmdbm_store (d, key, dat, replace)
Xregister struct mdbm *d;
Xdatum key, dat;
Xint replace;			/* true => overwrite if exists */
X{
X#define db ((struct mdbm_dblock *) d -> mdbm_d)
X    register struct mdbm_dentry *de;
X    long    keyblock;
X    int     keyindex;
X    long    didsplit;
X    long    outh;
X    unsigned short  outx;
X    extern int  errno;
X
X    if (d -> mdbm_flags & MDBM_ISRONLY) {
X	errno = EPERM;
X	return (-1);
X    }
X /* Search for the key's datum.  If it is found, then delete the datum
X    (unless we are told not to) and store a new one, then modify the key's
X    description parameters to point to the new datum.  If it is not found,
X    then presumably there is no such key, so make a new one, then precede
X    as before. */
X    de = mdbm_search (d, key.dptr, key.dsize, &keyblock, &keyindex, 0);
X    if (de) {
X	if (!replace)
X	    return 1;
X	mdbm_delitem (d, de - db -> db_e);
X    /* now committed - if new datum doesn't fit, old pairing is gone! */
X    }
X    else {			/* create new key */
X	de = mdbm_dostore (d, key.dptr, key.dsize, (long *) 0, (long *) 0);
X	if (de == 0) {
X	    MDBM_AUTO (d);
X	    errno = ENOSPC;	/* presumably */
X	    return (-1);
X	}
X	de -> de_outx = 1;	/* force it to look like a key */
X	keyblock = d -> mdbm_dblock;
X	keyindex = de - db -> db_e;
X    }
X    didsplit = keyblock;
X    de = mdbm_dostore (d, dat.dptr, dat.dsize, &outh, &didsplit);
X    if (de)
X	outx = de -> de_inx;
X /* if the data store split the key's block, have to find the key again */
X    if (didsplit)
X	if (mdbm_search (d, key.dptr, key.dsize, &keyblock,
X		&keyindex, 1) == 0) {
X	    printf ("mdbm bug: post-split keysearch failed!\n");
X	    fflush(stdout);
X	    abort ();
X	}
X    if (!de) {			/* oops, go delete the key */
X	MDBM_DREAD (d, keyblock);
X	de = &db -> db_e[keyindex];
X	de -> de_outx = 0;	/* not a key anymore */
X	mdbm_delitem (d, keyindex);
X	MDBM_AUTO (d);
X	errno = ENOSPC;
X	return (-1);
X    }
X /* Replace the outx and outh numbers in the old (or new) key so that it
X    points to the new datum */
X    MDBM_DREAD (d, keyblock);
X    de = &db -> db_e[keyindex];
X    de -> de_outh = outh;
X    de -> de_outx = outx;
X    d -> mdbm_flags |= MDBM_DDIRTY;
X    MDBM_AUTO (d);
X    return 0;
X#undef db
X}
END_OF_./mdbm/store.c
if test 7864 -ne `wc -c <./mdbm/store.c`; then
    echo shar: \"./mdbm/store.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 2 \(of 2\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
But don't underestimate raw, frothing, manic hardware.
				(barry shein)
Randy Suess
..!att!chinet!randy

henry@utzoo.uucp (Henry Spencer) (06/15/88)

There is no known implementation of dbm that is not covered by AT&T
licensing restrictions, so I fear you're out of luck there.
-- 
Man is the best computer we can      |  Henry Spencer @ U of Toronto Zoology
put aboard a spacecraft. --Von Braun | {ihnp4,decvax,uunet!mnetor}!utzoo!henry

henry@utzoo.uucp (Henry Spencer) (06/18/88)

Everyone interested in dbm, please note:  mdbm is *not* public domain.
It contains and is derived from AT&T licensed software, and actually should
never have been posted.  If you made a copy, you should immediately delete
it, and then face New Jersey and abase yourself three times in hopes of
forgiveness for your sins. :-)

It sure would be nice to have a public-domain dbm.  Mdbm isn't it.
-- 
Man is the best computer we can      |  Henry Spencer @ U of Toronto Zoology
put aboard a spacecraft. --Von Braun | {ihnp4,decvax,uunet!mnetor}!utzoo!henry

zeeff@b-tech.UUCP (Jon Zeeff) (06/18/88)

In article <1988Jun14.232210.7726@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes:
>There is no known implementation of dbm that is not covered by AT&T
>licensing restrictions, so I fear you're out of luck there.

IBM put a copy of the dbm code in the X11 release (ie released the 
code) with a "copyright IBM with permission for anyone to use, copy, 
modify, etc" notice in it.  There are no "copyright AT&T" notices in it.  

Given this situation, it *is* legal for me to use and distribute this 
code.  There are no trade secret, copyright, or license violations 
in my doing so.  AT&T source license sites may be a different story.  
IBM and AT&T may have something to discuss, but that's not my 
concern.  

-- 
Jon Zeeff           		Branch Technology,
uunet!umix!b-tech!zeeff  	zeeff%b-tech.uucp@umix.cc.umich.edu

henry@utzoo.uucp (Henry Spencer) (06/20/88)

> IBM put a copy of the dbm code in the X11 release (ie released the 
> code) with a "copyright IBM with permission for anyone to use, copy, 
> modify, etc" notice in it.  There are no "copyright AT&T" notices in it.  
> 
> Given this situation, it *is* legal for me to use and distribute this 
> code.  There are no trade secret, copyright, or license violations 
> in my doing so...

Careful, it ain't necessarily so.  Agreed that IBM may get some harsh
words from AT&T.  Agreed, also, that someone innocently using the stuff
off the X tape is technically in the clear.  However, note the adverbs in
that sentence.  First, "innocently":  if you know full well -- or could
reasonably be expected to know -- that the stuff on the tape is pirated,
you may *not* be in the clear.  Second, "technically":  a lawsuit started
by a giant corporation can be painful and expensive even if you win.

Understand, I don't work for the AT&T Software Police :-).  I doubt that
AT&T is going to get very upset with you over personal use.  But if I
were considering incorporating that stuff in a commercial product (or a
non-commercial product), I for one would (a) hesitate, and (b) seriously
consider getting legal advice first.  Be careful, it's loaded.
-- 
Man is the best computer we can      |  Henry Spencer @ U of Toronto Zoology
put aboard a spacecraft. --Von Braun | {ihnp4,decvax,uunet!mnetor}!utzoo!henry