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