summaryrefslogtreecommitdiff
path: root/libdb
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2019-08-26 16:24:25 +0100
committerColin Watson <cjwatson@debian.org>2019-08-26 16:24:25 +0100
commit4022480a2cbcd303c5fcb3547dab2896ae1915a9 (patch)
treeaa7f325ed783df7e253f8474df7121c6f1f85ea2 /libdb
parent886374b96c0da5287b5a9eba5777cb2d9f0ea3d8 (diff)
parent1c9cb89a74a0e54309eff01adcac9775e8c0563a (diff)
Import man-db_2.8.7.orig.tar.xz
Diffstat (limited to 'libdb')
-rw-r--r--libdb/Makefile.am2
-rw-r--r--libdb/Makefile.in34
-rw-r--r--libdb/db_btree.c90
-rw-r--r--libdb/db_delete.c4
-rw-r--r--libdb/db_gdbm.c123
-rw-r--r--libdb/db_lookup.c38
-rw-r--r--libdb/db_ndbm.c81
-rw-r--r--libdb/db_storage.h9
-rw-r--r--libdb/db_store.c23
-rw-r--r--libdb/db_ver.c7
-rw-r--r--libdb/db_xdbm.c169
-rw-r--r--libdb/db_xdbm.h40
-rw-r--r--libdb/mydbm.h108
13 files changed, 466 insertions, 262 deletions
diff --git a/libdb/Makefile.am b/libdb/Makefile.am
index 0015b84b..2851dfa3 100644
--- a/libdb/Makefile.am
+++ b/libdb/Makefile.am
@@ -39,6 +39,8 @@ libmandb_la_SOURCES = \
db_storage.h \
db_store.c \
db_ver.c \
+ db_xdbm.c \
+ db_xdbm.h \
mydbm.h
libmandb_la_LIBADD = ../lib/libman.la $(DBLIBS)
diff --git a/libdb/Makefile.in b/libdb/Makefile.in
index afc0b5ea..04607282 100644
--- a/libdb/Makefile.in
+++ b/libdb/Makefile.in
@@ -184,6 +184,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/man-arg-automatic-create.m4 \
$(top_srcdir)/gl/m4/ltversion.m4 \
$(top_srcdir)/gl/m4/lt~obsolete.m4 \
$(top_srcdir)/gl/m4/malloc.m4 $(top_srcdir)/gl/m4/malloca.m4 \
+ $(top_srcdir)/gl/m4/manywarnings.m4 \
$(top_srcdir)/gl/m4/mbrtowc.m4 $(top_srcdir)/gl/m4/mbsinit.m4 \
$(top_srcdir)/gl/m4/mbsrtowcs.m4 \
$(top_srcdir)/gl/m4/mbstate_t.m4 $(top_srcdir)/gl/m4/mbtowc.m4 \
@@ -301,7 +302,8 @@ libmandb_la_DEPENDENCIES = ../lib/libman.la $(am__DEPENDENCIES_1)
am_libmandb_la_OBJECTS = libmandb_la-db_btree.lo \
libmandb_la-db_delete.lo libmandb_la-db_gdbm.lo \
libmandb_la-db_lookup.lo libmandb_la-db_ndbm.lo \
- libmandb_la-db_store.lo libmandb_la-db_ver.lo
+ libmandb_la-db_store.lo libmandb_la-db_ver.lo \
+ libmandb_la-db_xdbm.lo
libmandb_la_OBJECTS = $(am_libmandb_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@@ -331,7 +333,8 @@ am__depfiles_remade = ./$(DEPDIR)/libmandb_la-db_btree.Plo \
./$(DEPDIR)/libmandb_la-db_lookup.Plo \
./$(DEPDIR)/libmandb_la-db_ndbm.Plo \
./$(DEPDIR)/libmandb_la-db_store.Plo \
- ./$(DEPDIR)/libmandb_la-db_ver.Plo
+ ./$(DEPDIR)/libmandb_la-db_ver.Plo \
+ ./$(DEPDIR)/libmandb_la-db_xdbm.Plo
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -447,6 +450,7 @@ GNULIB_CHOWN = @GNULIB_CHOWN@
GNULIB_CLOSE = @GNULIB_CLOSE@
GNULIB_CLOSEDIR = @GNULIB_CLOSEDIR@
GNULIB_CONNECT = @GNULIB_CONNECT@
+GNULIB_COPY_FILE_RANGE = @GNULIB_COPY_FILE_RANGE@
GNULIB_CTIME = @GNULIB_CTIME@
GNULIB_DIRFD = @GNULIB_DIRFD@
GNULIB_DPRINTF = @GNULIB_DPRINTF@
@@ -654,6 +658,7 @@ GNULIB_STRSIGNAL = @GNULIB_STRSIGNAL@
GNULIB_STRSTR = @GNULIB_STRSTR@
GNULIB_STRTOD = @GNULIB_STRTOD@
GNULIB_STRTOK_R = @GNULIB_STRTOK_R@
+GNULIB_STRTOLD = @GNULIB_STRTOLD@
GNULIB_STRTOLL = @GNULIB_STRTOLL@
GNULIB_STRTOULL = @GNULIB_STRTOULL@
GNULIB_STRVERSCMP = @GNULIB_STRVERSCMP@
@@ -728,6 +733,7 @@ GNULIB_WRITE = @GNULIB_WRITE@
GNULIB__EXIT = @GNULIB__EXIT@
GREP = @GREP@
HAVE_ACCEPT4 = @HAVE_ACCEPT4@
+HAVE_ALLOCA_H = @HAVE_ALLOCA_H@
HAVE_ALPHASORT = @HAVE_ALPHASORT@
HAVE_ATOLL = @HAVE_ATOLL@
HAVE_BTOWC = @HAVE_BTOWC@
@@ -735,6 +741,7 @@ HAVE_C99_STDINT_H = @HAVE_C99_STDINT_H@
HAVE_CANONICALIZE_FILE_NAME = @HAVE_CANONICALIZE_FILE_NAME@
HAVE_CHOWN = @HAVE_CHOWN@
HAVE_CLOSEDIR = @HAVE_CLOSEDIR@
+HAVE_COPY_FILE_RANGE = @HAVE_COPY_FILE_RANGE@
HAVE_CRTDEFS_H = @HAVE_CRTDEFS_H@
HAVE_DECL_DIRFD = @HAVE_DECL_DIRFD@
HAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@
@@ -816,6 +823,7 @@ HAVE_GLOB_H = @HAVE_GLOB_H@
HAVE_GLOB_PATTERN_P = @HAVE_GLOB_PATTERN_P@
HAVE_GRANTPT = @HAVE_GRANTPT@
HAVE_GROUP_MEMBER = @HAVE_GROUP_MEMBER@
+HAVE_INITSTATE = @HAVE_INITSTATE@
HAVE_INTTYPES_H = @HAVE_INTTYPES_H@
HAVE_ISWBLANK = @HAVE_ISWBLANK@
HAVE_ISWCNTRL = @HAVE_ISWCNTRL@
@@ -838,6 +846,7 @@ HAVE_MBSINIT = @HAVE_MBSINIT@
HAVE_MBSLEN = @HAVE_MBSLEN@
HAVE_MBSNRTOWCS = @HAVE_MBSNRTOWCS@
HAVE_MBSRTOWCS = @HAVE_MBSRTOWCS@
+HAVE_MBTOWC = @HAVE_MBTOWC@
HAVE_MEMCHR = @HAVE_MEMCHR@
HAVE_MEMPCPY = @HAVE_MEMPCPY@
HAVE_MKDIRAT = @HAVE_MKDIRAT@
@@ -888,6 +897,7 @@ HAVE_SCANDIR = @HAVE_SCANDIR@
HAVE_SECURE_GETENV = @HAVE_SECURE_GETENV@
HAVE_SETENV = @HAVE_SETENV@
HAVE_SETHOSTNAME = @HAVE_SETHOSTNAME@
+HAVE_SETSTATE = @HAVE_SETSTATE@
HAVE_SIGACTION = @HAVE_SIGACTION@
HAVE_SIGHANDLER_T = @HAVE_SIGHANDLER_T@
HAVE_SIGINFO_T = @HAVE_SIGINFO_T@
@@ -907,6 +917,7 @@ HAVE_STRPBRK = @HAVE_STRPBRK@
HAVE_STRPTIME = @HAVE_STRPTIME@
HAVE_STRSEP = @HAVE_STRSEP@
HAVE_STRTOD = @HAVE_STRTOD@
+HAVE_STRTOLD = @HAVE_STRTOLD@
HAVE_STRTOLL = @HAVE_STRTOLL@
HAVE_STRTOULL = @HAVE_STRTOULL@
HAVE_STRUCT_RANDOM_DATA = @HAVE_STRUCT_RANDOM_DATA@
@@ -1007,8 +1018,6 @@ LIBICONV = @LIBICONV@
LIBINTL = @LIBINTL@
LIBMULTITHREAD = @LIBMULTITHREAD@
LIBOBJS = @LIBOBJS@
-LIBPTH = @LIBPTH@
-LIBPTH_PREFIX = @LIBPTH_PREFIX@
LIBS = @LIBS@
LIBSOCKET = @LIBSOCKET@
LIBTHREAD = @LIBTHREAD@
@@ -1031,7 +1040,6 @@ LTLIBICONV = @LTLIBICONV@
LTLIBINTL = @LTLIBINTL@
LTLIBMULTITHREAD = @LTLIBMULTITHREAD@
LTLIBOBJS = @LTLIBOBJS@
-LTLIBPTH = @LTLIBPTH@
LTLIBTHREAD = @LTLIBTHREAD@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
MAINT = @MAINT@
@@ -1177,6 +1185,7 @@ REPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@
REPLACE_GLOB = @REPLACE_GLOB@
REPLACE_GLOB_PATTERN_P = @REPLACE_GLOB_PATTERN_P@
REPLACE_GMTIME = @REPLACE_GMTIME@
+REPLACE_INITSTATE = @REPLACE_INITSTATE@
REPLACE_IOCTL = @REPLACE_IOCTL@
REPLACE_ISATTY = @REPLACE_ISATTY@
REPLACE_ISWBLANK = @REPLACE_ISWBLANK@
@@ -1225,6 +1234,7 @@ REPLACE_PUTENV = @REPLACE_PUTENV@
REPLACE_PWRITE = @REPLACE_PWRITE@
REPLACE_QSORT_R = @REPLACE_QSORT_R@
REPLACE_RAISE = @REPLACE_RAISE@
+REPLACE_RANDOM = @REPLACE_RANDOM@
REPLACE_RANDOM_R = @REPLACE_RANDOM_R@
REPLACE_READ = @REPLACE_READ@
REPLACE_READLINK = @REPLACE_READLINK@
@@ -1238,6 +1248,7 @@ REPLACE_RMDIR = @REPLACE_RMDIR@
REPLACE_SELECT = @REPLACE_SELECT@
REPLACE_SETENV = @REPLACE_SETENV@
REPLACE_SETLOCALE = @REPLACE_SETLOCALE@
+REPLACE_SETSTATE = @REPLACE_SETSTATE@
REPLACE_SLEEP = @REPLACE_SLEEP@
REPLACE_SNPRINTF = @REPLACE_SNPRINTF@
REPLACE_SPRINTF = @REPLACE_SPRINTF@
@@ -1258,6 +1269,7 @@ REPLACE_STRSIGNAL = @REPLACE_STRSIGNAL@
REPLACE_STRSTR = @REPLACE_STRSTR@
REPLACE_STRTOD = @REPLACE_STRTOD@
REPLACE_STRTOK_R = @REPLACE_STRTOK_R@
+REPLACE_STRTOLD = @REPLACE_STRTOLD@
REPLACE_STRUCT_LCONV = @REPLACE_STRUCT_LCONV@
REPLACE_STRUCT_TIMEVAL = @REPLACE_STRUCT_TIMEVAL@
REPLACE_SYMLINK = @REPLACE_SYMLINK@
@@ -1464,6 +1476,8 @@ libmandb_la_SOURCES = \
db_storage.h \
db_store.c \
db_ver.c \
+ db_xdbm.c \
+ db_xdbm.h \
mydbm.h
libmandb_la_LIBADD = ../lib/libman.la $(DBLIBS)
@@ -1555,6 +1569,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmandb_la-db_ndbm.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmandb_la-db_store.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmandb_la-db_ver.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmandb_la-db_xdbm.Plo@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@@ -1632,6 +1647,13 @@ libmandb_la-db_ver.lo: db_ver.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmandb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmandb_la-db_ver.lo `test -f 'db_ver.c' || echo '$(srcdir)/'`db_ver.c
+libmandb_la-db_xdbm.lo: db_xdbm.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmandb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmandb_la-db_xdbm.lo -MD -MP -MF $(DEPDIR)/libmandb_la-db_xdbm.Tpo -c -o libmandb_la-db_xdbm.lo `test -f 'db_xdbm.c' || echo '$(srcdir)/'`db_xdbm.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmandb_la-db_xdbm.Tpo $(DEPDIR)/libmandb_la-db_xdbm.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='db_xdbm.c' object='libmandb_la-db_xdbm.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmandb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmandb_la-db_xdbm.lo `test -f 'db_xdbm.c' || echo '$(srcdir)/'`db_xdbm.c
+
mostlyclean-libtool:
-rm -f *.lo
@@ -1773,6 +1795,7 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/libmandb_la-db_ndbm.Plo
-rm -f ./$(DEPDIR)/libmandb_la-db_store.Plo
-rm -f ./$(DEPDIR)/libmandb_la-db_ver.Plo
+ -rm -f ./$(DEPDIR)/libmandb_la-db_xdbm.Plo
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
@@ -1825,6 +1848,7 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/libmandb_la-db_ndbm.Plo
-rm -f ./$(DEPDIR)/libmandb_la-db_store.Plo
-rm -f ./$(DEPDIR)/libmandb_la-db_ver.Plo
+ -rm -f ./$(DEPDIR)/libmandb_la-db_xdbm.Plo
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
diff --git a/libdb/db_btree.c b/libdb/db_btree.c
index b4e426cc..917e286c 100644
--- a/libdb/db_btree.c
+++ b/libdb/db_btree.c
@@ -61,16 +61,22 @@ gl_set_t loop_check;
blocking method is used ": Try again". This adopts GNU dbm's approach. */
/* release the lock and close the database */
-int btree_close (DB *db)
+void man_btree_close (man_btree_wrapper wrap)
{
- (void) flock ((db->fd) (db), LOCK_UN);
- return (db->close) (db);
+ if (!wrap)
+ return;
+
+ free (wrap->name);
+ (void) flock ((wrap->file->fd) (wrap->file), LOCK_UN);
+ (wrap->file->close) (wrap->file);
+ free (wrap);
}
/* open a btree type database, with file locking. */
-DB *btree_flopen (char *filename, int flags, int mode)
+man_btree_wrapper man_btree_open (const char *name, int flags, int mode)
{
- DB *db;
+ man_btree_wrapper wrap;
+ DB *file;
BTREEINFO b;
int lock_op;
int lock_failed;
@@ -102,7 +108,7 @@ DB *btree_flopen (char *filename, int flags, int mode)
* and ignore the database if it's zero-length.
*/
struct stat iszero;
- if (stat (filename, &iszero) < 0)
+ if (stat (name, &iszero) < 0)
return NULL;
if (iszero.st_size == 0) {
errno = EINVAL;
@@ -114,54 +120,59 @@ DB *btree_flopen (char *filename, int flags, int mode)
/* opening the db is destructive, need to lock first */
int fd;
- db = NULL;
+ file = NULL;
lock_failed = 1;
- fd = open (filename, flags & ~O_TRUNC, mode);
+ fd = open (name, flags & ~O_TRUNC, mode);
if (fd != -1) {
if (!(lock_failed = flock (fd, lock_op)))
- db = dbopen (filename, flags, mode,
- DB_BTREE, &b);
+ file = dbopen (name, flags, mode,
+ DB_BTREE, &b);
close (fd);
}
} else {
- db = dbopen (filename, flags, mode, DB_BTREE, &b);
- if (db)
- lock_failed = flock ((db->fd) (db), lock_op);
+ file = dbopen (name, flags, mode, DB_BTREE, &b);
+ if (file)
+ lock_failed = flock ((file->fd) (file), lock_op);
}
- if (!db)
+ if (!file)
return NULL;
if (lock_failed) {
- gripe_lock (filename);
- btree_close (db);
+ gripe_lock (name);
+ (file->close) (file);
return NULL;
}
- return db;
+ wrap = xmalloc (sizeof *wrap);
+ wrap->name = xstrdup (name);
+ wrap->file = file;
+
+ return wrap;
}
/* do a replace when we have the duplicate flag set on the database -
we must do a del and insert, as a direct insert will not wipe out the
old entry */
-int btree_replace (DB *db, datum key, datum cont)
+int man_btree_replace (man_btree_wrapper wrap, datum key, datum cont)
{
- return (db->put) (db, (DBT *) &key, (DBT *) &cont, 0);
+ return (wrap->file->put) (wrap->file, (DBT *) &key, (DBT *) &cont, 0);
}
-int btree_insert (DB *db, datum key, datum cont)
+int man_btree_insert (man_btree_wrapper wrap, datum key, datum cont)
{
- return (db->put) (db, (DBT *) &key, (DBT *) &cont, R_NOOVERWRITE);
+ return (wrap->file->put) (wrap->file, (DBT *) &key, (DBT *) &cont,
+ R_NOOVERWRITE);
}
/* generic fetch routine for the btree database */
-datum btree_fetch (DB *db, datum key)
+datum man_btree_fetch (man_btree_wrapper wrap, datum key)
{
datum data;
memset (&data, 0, sizeof data);
- if ((db->get) (db, (DBT *) &key, (DBT *) &data, 0)) {
+ if ((wrap->file->get) (wrap->file, (DBT *) &key, (DBT *) &data, 0)) {
memset (&data, 0, sizeof data);
return data;
}
@@ -170,14 +181,15 @@ datum btree_fetch (DB *db, datum key)
}
/* return 1 if the key exists, 0 otherwise */
-int btree_exists (DB *db, datum key)
+int man_btree_exists (man_btree_wrapper wrap, datum key)
{
datum data;
- return ((db->get) (db, (DBT *) &key, (DBT *) &data, 0) ? 0 : 1);
+ return ((wrap->file->get) (wrap->file, (DBT *) &key, (DBT *) &data,
+ 0) ? 0 : 1);
}
/* initiate a sequential access */
-static datum btree_findkey (DB *db, u_int flags)
+static datum man_btree_findkey (man_btree_wrapper wrap, u_int flags)
{
datum key, data;
char *loop_check_key;
@@ -194,7 +206,8 @@ static datum btree_findkey (DB *db, u_int flags)
if (!loop_check)
loop_check = new_string_set (GL_HASH_SET);
- if (((db->seq) (db, (DBT *) &key, (DBT *) &data, flags))) {
+ if (((wrap->file->seq) (wrap->file, (DBT *) &key, (DBT *) &data,
+ flags))) {
memset (&key, 0, sizeof key);
return key;
}
@@ -218,26 +231,27 @@ static datum btree_findkey (DB *db, u_int flags)
}
/* return the first key in the db */
-datum btree_firstkey (DB *db)
+datum man_btree_firstkey (man_btree_wrapper wrap)
{
- return btree_findkey (db, R_FIRST);
+ return man_btree_findkey (wrap, R_FIRST);
}
/* return the next key in the db. NB. This routine only works if the cursor
- has been previously set by btree_firstkey() since it was last opened. So
+ has been previously set by man_btree_firstkey() since it was last opened. So
if we close/reopen a db mid search, we have to manually set up the
cursor again. */
-datum btree_nextkey (DB *db)
+datum man_btree_nextkey (man_btree_wrapper wrap)
{
- return btree_findkey (db, R_NEXT);
+ return man_btree_findkey (wrap, R_NEXT);
}
/* compound nextkey routine, initialising key and content */
-int btree_nextkeydata (DB *db, datum *key, datum *cont)
+int man_btree_nextkeydata (man_btree_wrapper wrap, datum *key, datum *cont)
{
int status;
- if ((status = (db->seq) (db, (DBT *) key, (DBT *) cont, R_NEXT)) != 0)
+ if ((status = (wrap->file->seq) (wrap->file, (DBT *) key, (DBT *) cont,
+ R_NEXT)) != 0)
return status;
*key = copy_datum (*key);
@@ -246,11 +260,11 @@ int btree_nextkeydata (DB *db, datum *key, datum *cont)
return 0;
}
-struct timespec btree_get_time (DB *db)
+struct timespec man_btree_get_time (man_btree_wrapper wrap)
{
struct stat st;
- if (fstat ((db->fd) (db), &st) < 0) {
+ if (fstat ((wrap->file->fd) (wrap->file), &st) < 0) {
struct timespec t;
t.tv_sec = -1;
t.tv_nsec = -1;
@@ -259,13 +273,13 @@ struct timespec btree_get_time (DB *db)
return get_stat_mtime (&st);
}
-void btree_set_time (DB *db, const struct timespec time)
+void man_btree_set_time (man_btree_wrapper wrap, const struct timespec time)
{
struct timespec times[2];
times[0] = time;
times[1] = time;
- futimens ((db->fd) (db), times);
+ futimens ((wrap->file->fd) (wrap->file), times);
}
#endif /* BTREE */
diff --git a/libdb/db_delete.c b/libdb/db_delete.c
index d1e99385..24ce1d83 100644
--- a/libdb/db_delete.c
+++ b/libdb/db_delete.c
@@ -104,7 +104,7 @@ int dbdelete (MYDBM_FILE dbf, const char *name, struct mandata *info)
error (0, 0,
_( "multi key %s does not exist"),
MYDBM_DPTR (multi_key));
- gripe_corrupt_data ();
+ gripe_corrupt_data (dbf);
}
MYDBM_DELETE (dbf, multi_key);
MYDBM_FREE_DPTR (multi_key);
@@ -132,7 +132,7 @@ int dbdelete (MYDBM_FILE dbf, const char *name, struct mandata *info)
MYDBM_FREE_DPTR (cont);
MYDBM_SET (cont, multi_content);
if (MYDBM_REPLACE (dbf, key, cont))
- gripe_replace_key (MYDBM_DPTR (key));
+ gripe_replace_key (dbf, MYDBM_DPTR (key));
gl_list_free (refs);
}
diff --git a/libdb/db_gdbm.c b/libdb/db_gdbm.c
index d8fb988d..1062f357 100644
--- a/libdb/db_gdbm.c
+++ b/libdb/db_gdbm.c
@@ -34,23 +34,16 @@
#include <sys/stat.h>
#include <unistd.h>
-#include "gl_hash_map.h"
-#include "gl_rbtree_list.h"
-#include "gl_xlist.h"
-#include "gl_xmap.h"
-#include "hash-pjw-bare.h"
#include "stat-time.h"
#include "timespec.h"
#include "manconfig.h"
#include "cleanup.h"
-#include "glcontainers.h"
+#include "db_xdbm.h"
#include "mydbm.h"
-static gl_map_t parent_keys;
-
/* setjmp/longjmp handling to defend against _gdbm_fatal exiting under our
* feet. Not thread-safe, but there is no plan for man-db to ever use
* threads.
@@ -103,111 +96,24 @@ man_gdbm_wrapper man_gdbm_open_wrapper (const char *name, int flags)
return wrap;
}
-static int datum_compare (const void *a, const void *b)
-{
- const datum *left = (const datum *) a;
- const datum *right = (const datum *) b;
- int cmp;
- size_t minsize;
-
- /* Sentinel NULL elements sort to the end. */
- if (!MYDBM_DPTR (*left))
- return 1;
- else if (!MYDBM_DPTR (*right))
- return -1;
-
- if (MYDBM_DSIZE (*left) < MYDBM_DSIZE (*right))
- minsize = MYDBM_DSIZE (*left);
- else
- minsize = MYDBM_DSIZE (*right);
- cmp = strncmp (MYDBM_DPTR (*left), MYDBM_DPTR (*right), minsize);
- if (cmp)
- return cmp;
- else if (MYDBM_DSIZE (*left) < MYDBM_DSIZE (*right))
- return 1;
- else if (MYDBM_DSIZE (*left) > MYDBM_DSIZE (*right))
- return -1;
- else
- return 0;
-}
-
-static bool datum_equals (const void *a, const void *b)
+static datum unsorted_firstkey (man_gdbm_wrapper wrap)
{
- return datum_compare (a, b) == 0;
+ return gdbm_firstkey (wrap->file);
}
-static size_t datum_hash (const void *value)
+static datum unsorted_nextkey (man_gdbm_wrapper wrap, datum key)
{
- const datum *d = value;
- return hash_pjw_bare (MYDBM_DPTR (*d), MYDBM_DSIZE (*d));
+ return gdbm_nextkey (wrap->file, key);
}
-static void datum_free (const void *value)
-{
- MYDBM_FREE_DPTR (*(datum *) value);
-}
-
-static datum empty_datum = { NULL, 0 };
-
-/* We keep a map of filenames to sorted lists of keys. Each list is stored
- * using a hash-based implementation that allows lookup by name and
- * traversal to the next item in O(log n) time, which is necessary for a
- * reasonable ordered implementation of nextkey.
- */
datum man_gdbm_firstkey (man_gdbm_wrapper wrap)
{
- gl_list_t keys;
- datum *key;
-
- /* Build the raw sorted list of keys. */
- keys = gl_list_create_empty (GL_RBTREE_LIST, datum_equals, datum_hash,
- datum_free, false);
- key = XMALLOC (datum);
- *key = gdbm_firstkey (wrap->file);
- while (MYDBM_DPTR (*key)) {
- datum *next;
-
- gl_sortedlist_add (keys, datum_compare, key);
- next = XMALLOC (datum);
- *next = gdbm_nextkey (wrap->file, *key);
- key = next;
- }
-
- if (!parent_keys) {
- parent_keys = new_string_map (GL_HASH_MAP,
- (gl_listelement_dispose_fn)
- gl_list_free);
- push_cleanup ((cleanup_fun) gl_map_free, parent_keys, 0);
- }
-
- /* Remember this structure for use by nextkey. */
- gl_map_put (parent_keys, xstrdup (wrap->name), keys);
-
- if (gl_list_size (keys))
- return copy_datum (*(datum *) gl_list_get_at (keys, 0));
- else
- return empty_datum;
+ return man_xdbm_firstkey (wrap, unsorted_firstkey, unsorted_nextkey);
}
datum man_gdbm_nextkey (man_gdbm_wrapper wrap, datum key)
{
- gl_list_t keys;
- gl_list_node_t node, next_node;
-
- if (!parent_keys)
- return empty_datum;
- keys = (gl_list_t) gl_map_get (parent_keys, wrap->name);
- if (!keys)
- return empty_datum;
-
- node = gl_sortedlist_search (keys, datum_compare, &key);
- if (!node)
- return empty_datum;
- next_node = gl_list_next_node (keys, node);
- if (!next_node)
- return empty_datum;
-
- return copy_datum (*(datum *) gl_list_node_value (keys, next_node));
+ return man_xdbm_nextkey (wrap, key);
}
struct timespec man_gdbm_get_time (man_gdbm_wrapper wrap)
@@ -232,17 +138,14 @@ void man_gdbm_set_time (man_gdbm_wrapper wrap, const struct timespec time)
futimens (gdbm_fdesc (wrap->file), times);
}
-void man_gdbm_close (man_gdbm_wrapper wrap)
+static void raw_close (man_gdbm_wrapper wrap)
{
- if (!wrap)
- return;
-
- if (parent_keys)
- gl_map_remove (parent_keys, wrap->name);
-
- free (wrap->name);
gdbm_close (wrap->file);
- free (wrap);
+}
+
+void man_gdbm_close (man_gdbm_wrapper wrap)
+{
+ man_xdbm_close (wrap, raw_close);
}
#ifndef HAVE_GDBM_EXISTS
diff --git a/libdb/db_lookup.c b/libdb/db_lookup.c
index 28cd90e2..9ff72d6c 100644
--- a/libdb/db_lookup.c
+++ b/libdb/db_lookup.c
@@ -70,23 +70,23 @@ datum copy_datum (datum dat)
/* gdbm does locking itself. */
#if defined(NDBM) || defined(BTREE)
-void gripe_lock (char *filename)
+void gripe_lock (const char *filename)
{
error (0, errno, _("can't lock index cache %s"), filename);
}
#endif /* NDBM || BTREE */
/* issue fatal message, then exit */
-void gripe_corrupt_data (void)
+void gripe_corrupt_data (MYDBM_FILE dbf)
{
- error (FATAL, 0, _("index cache %s corrupt"), database);
+ error (FATAL, 0, _("index cache %s corrupt"), dbf->name);
}
/* deal with situation where we cannot replace a key */
-void gripe_replace_key (const char *data)
+void gripe_replace_key (MYDBM_FILE dbf, const char *data)
{
error (0, 0, _("cannot replace key %s"), data);
- gripe_corrupt_data ();
+ gripe_corrupt_data (dbf);
}
static char *copy_if_set (const char *str)
@@ -97,7 +97,7 @@ static char *copy_if_set (const char *str)
return xstrdup (str);
}
-const char *dash_if_unset (const char *str)
+const char * _GL_ATTRIBUTE_CONST dash_if_unset (const char *str)
{
if (str)
return str;
@@ -171,7 +171,7 @@ char *name_to_key (const char *name)
}
/* return char ptr array to the data's fields */
-static char **split_data (char *content, char *start[])
+static char **split_data (MYDBM_FILE dbf, char *content, char *start[])
{
int count;
@@ -183,7 +183,7 @@ static char **split_data (char *content, char *start[])
ngettext ("only %d field in content",
"only %d fields in content", count),
count);
- gripe_corrupt_data ();
+ gripe_corrupt_data (dbf);
}
}
@@ -194,19 +194,19 @@ static char **split_data (char *content, char *start[])
ngettext ("only %d field in content",
"only %d fields in content", FIELDS - 1),
FIELDS - 1);
- gripe_corrupt_data ();
+ gripe_corrupt_data (dbf);
}
return start;
}
/* Parse the db-returned data and put it into a mandata format */
-void split_content (char *cont_ptr, struct mandata *pinfo)
+void split_content (MYDBM_FILE dbf, char *cont_ptr, struct mandata *pinfo)
{
char *start[FIELDS];
char **data;
- data = split_data (cont_ptr, start);
+ data = split_data (dbf, cont_ptr, start);
pinfo->name = copy_if_set (*(data++));
pinfo->ext = *(data++);
@@ -255,7 +255,7 @@ gl_list_t list_extensions (char *data)
gl_list_add_last (list, name_ext);
}
- debug ("found %zd names/extensions\n", gl_list_size (list));
+ debug ("found %zu names/extensions\n", gl_list_size (list));
return list;
}
@@ -296,7 +296,7 @@ static gl_list_t dblookup (MYDBM_FILE dbf, const char *page,
bool matches = false;
info = infoalloc ();
- split_content (MYDBM_DPTR (cont), info);
+ split_content (dbf, MYDBM_DPTR (cont), info);
if (!info->name)
info->name = xstrdup (page);
if (!(flags & MATCH_CASE) || STREQ (info->name, page)) {
@@ -357,13 +357,13 @@ static gl_list_t dblookup (MYDBM_FILE dbf, const char *page,
if (MYDBM_DPTR (multi_cont) == NULL) {
error (0, 0, _("bad fetch on multi key %s"),
MYDBM_DPTR (key));
- gripe_corrupt_data ();
+ gripe_corrupt_data (dbf);
}
MYDBM_FREE_DPTR (key);
/* Allocate info struct and add it to the list. */
info = infoalloc ();
- split_content (MYDBM_DPTR (multi_cont), info);
+ split_content (dbf, MYDBM_DPTR (multi_cont), info);
if (!info->name)
info->name = xstrdup (ref->name);
gl_list_add_last (infos, info);
@@ -427,7 +427,7 @@ gl_list_t dblookup_pattern (MYDBM_FILE dbf, const char *pattern,
#else /* BTREE */
int end;
- end = btree_nextkeydata (dbf, &key, &cont);
+ end = man_btree_nextkeydata (dbf, &key, &cont);
while (!end) {
#endif /* !BTREE */
struct mandata info;
@@ -442,7 +442,7 @@ gl_list_t dblookup_pattern (MYDBM_FILE dbf, const char *pattern,
error (FATAL, 0,
_("Database %s corrupted; rebuild with "
"mandb --create"),
- database);
+ dbf->name);
}
if (*MYDBM_DPTR (key) == '$')
@@ -453,7 +453,7 @@ gl_list_t dblookup_pattern (MYDBM_FILE dbf, const char *pattern,
/* a real page */
- split_content (MYDBM_DPTR (cont), &info);
+ split_content (dbf, MYDBM_DPTR (cont), &info);
/* If there's a section given, does it match either the
* section or extension of this page?
@@ -505,7 +505,7 @@ nextpage:
#else /* BTREE */
MYDBM_FREE_DPTR (cont);
MYDBM_FREE_DPTR (key);
- end = btree_nextkeydata (dbf, &key, &cont);
+ end = man_btree_nextkeydata (dbf, &key, &cont);
#endif /* !BTREE */
info.addr = NULL;
free_mandata_elements (&info);
diff --git a/libdb/db_ndbm.c b/libdb/db_ndbm.c
index 992173ae..64000c1c 100644
--- a/libdb/db_ndbm.c
+++ b/libdb/db_ndbm.c
@@ -41,21 +41,28 @@
#include "manconfig.h"
-#include "mydbm.h"
#include "db_storage.h"
+#include "db_xdbm.h"
+#include "mydbm.h"
/* release the lock and close the database */
-int ndbm_flclose (DBM *db)
+static void raw_close (man_ndbm_wrapper wrap)
+{
+ flock (dbm_dirfno (wrap->file), LOCK_UN);
+ dbm_close (wrap->file);
+}
+
+void man_ndbm_close (man_ndbm_wrapper wrap)
{
- flock (dbm_dirfno (db), LOCK_UN);
- dbm_close (db);
- return 0;
+ man_xdbm_close (wrap, raw_close);
}
/* open a ndbm type database, with file locking. */
-DBM* ndbm_flopen (char *filename, int flags, int mode)
+man_ndbm_wrapper man_ndbm_open (const char *name, int flags, int mode)
{
- DBM *db;
+ man_ndbm_wrapper wrap;
+ char *name_copy;
+ DBM *file;
int lock_op;
int lock_failed;
@@ -66,44 +73,76 @@ DBM* ndbm_flopen (char *filename, int flags, int mode)
lock_op = LOCK_SH | LOCK_NB;
}
+ /* At least GDBM's version of dbm_open declares the file name
+ * parameter as non-const. This is probably incorrect, but take a
+ * copy just in case.
+ */
+ name_copy = xstrdup (name);
+
if (flags & O_TRUNC) {
/* opening the db is destructive, need to lock first */
char *dir_fname;
int dir_fd;
- db = NULL;
+ file = NULL;
lock_failed = 1;
- dir_fname = xasprintf ("%s.dir", filename);
+ dir_fname = xasprintf ("%s.dir", name);
dir_fd = open (dir_fname, flags & ~O_TRUNC, mode);
free (dir_fname);
if (dir_fd != -1) {
if (!(lock_failed = flock (dir_fd, lock_op)))
- db = dbm_open (filename, flags, mode);
+ file = dbm_open (name_copy, flags, mode);
close (dir_fd);
}
} else {
- db = dbm_open (filename, flags, mode);
- if (db)
- lock_failed = flock (dbm_dirfno (db), lock_op);
+ file = dbm_open (name_copy, flags, mode);
+ if (file)
+ lock_failed = flock (dbm_dirfno (file), lock_op);
}
- if (!db)
+ free (name_copy);
+
+ if (!file)
return NULL;
if (lock_failed) {
- gripe_lock (filename);
- dbm_close (db);
+ gripe_lock (name);
+ dbm_close (file);
return NULL;
}
- return db;
+ wrap = xmalloc (sizeof *wrap);
+ wrap->name = xstrdup (name);
+ wrap->file = file;
+
+ return wrap;
+}
+
+static datum unsorted_firstkey (man_ndbm_wrapper wrap)
+{
+ return copy_datum (dbm_firstkey (wrap->file));
+}
+
+static datum unsorted_nextkey (man_ndbm_wrapper wrap, datum key _GL_UNUSED)
+{
+ return copy_datum (dbm_nextkey (wrap->file));
+}
+
+datum man_ndbm_firstkey (man_ndbm_wrapper wrap)
+{
+ return man_xdbm_firstkey (wrap, unsorted_firstkey, unsorted_nextkey);
+}
+
+datum man_ndbm_nextkey (man_ndbm_wrapper wrap, datum key)
+{
+ return man_xdbm_nextkey (wrap, key);
}
-struct timespec ndbm_get_time (DBM *db)
+struct timespec man_ndbm_get_time (man_ndbm_wrapper wrap)
{
struct stat st;
- if (fstat (dbm_dirfno (db), &st) < 0) {
+ if (fstat (dbm_dirfno (wrap->file), &st) < 0) {
struct timespec t;
t.tv_sec = -1;
t.tv_nsec = -1;
@@ -112,13 +151,13 @@ struct timespec ndbm_get_time (DBM *db)
return get_stat_mtime (&st);
}
-void ndbm_set_time (DBM *db, const struct timespec time)
+void man_ndbm_set_time (man_ndbm_wrapper wrap, const struct timespec time)
{
struct timespec times[2];
times[0] = time;
times[1] = time;
- futimens (dbm_dirfno (db), times);
+ futimens (dbm_dirfno (wrap->file), times);
}
#endif /* NDBM */
diff --git a/libdb/db_storage.h b/libdb/db_storage.h
index a04196bc..c6d412f9 100644
--- a/libdb/db_storage.h
+++ b/libdb/db_storage.h
@@ -90,12 +90,13 @@ extern int dbdelete (MYDBM_FILE dbf, const char *name, struct mandata *in);
extern void dbprintf (const struct mandata *info);
extern void free_mandata_elements (struct mandata *pinfo);
extern void free_mandata_struct (struct mandata *pinfo);
-extern void split_content (char *cont_ptr, struct mandata *pinfo);
+extern void split_content (MYDBM_FILE dbf, char *cont_ptr,
+ struct mandata *pinfo);
extern int compare_ids (char a, char b, int promote_links);
/* local to db routines */
-extern void gripe_lock (char *filename);
-extern void gripe_corrupt_data (void);
+extern void gripe_lock (const char *filename);
+extern void gripe_corrupt_data (MYDBM_FILE dbf);
extern datum make_multi_key (const char *page, const char *ext);
/* allocate a mandata structure */
@@ -104,7 +105,7 @@ extern datum make_multi_key (const char *page, const char *ext);
extern char *name_to_key (const char *name);
/* Returns a list of struct name_ext. */
extern gl_list_t list_extensions (char *data);
-extern void gripe_replace_key (const char *data);
+extern void gripe_replace_key (MYDBM_FILE dbf, const char *data);
extern const char *dash_if_unset (const char *str);
#endif
diff --git a/libdb/db_store.c b/libdb/db_store.c
index 062db71f..508a41aa 100644
--- a/libdb/db_store.c
+++ b/libdb/db_store.c
@@ -33,9 +33,6 @@
#include "timespec.h"
#include "xvasprintf.h"
-#include "gettext.h"
-#define _(String) gettext (String)
-
#include "manconfig.h"
#include "error.h"
@@ -52,7 +49,7 @@
* If promote_links is true, consider SO_MAN equivalent to ULT_MAN. This is
* appropriate when sorting candidate pages for display.
*/
-int compare_ids (char a, char b, int promote_links)
+int _GL_ATTRIBUTE_CONST compare_ids (char a, char b, int promote_links)
{
#ifdef FAVOUR_STRAYCATS
if (a == WHATIS_MAN && b == STRAY_CAT)
@@ -94,13 +91,13 @@ static int replace_if_necessary (MYDBM_FILE dbf,
timespec_cmp (newdata->mtime, olddata->mtime) > 0) {
debug ("replace_if_necessary(): newer mtime; replacing\n");
if (MYDBM_REPLACE (dbf, newkey, newcont))
- gripe_replace_key (MYDBM_DPTR (newkey));
+ gripe_replace_key (dbf, MYDBM_DPTR (newkey));
return 0;
}
if (compare_ids (newdata->id, olddata->id, 0) < 0) {
if (MYDBM_REPLACE (dbf, newkey, newcont))
- gripe_replace_key (MYDBM_DPTR (newkey));
+ gripe_replace_key (dbf, MYDBM_DPTR (newkey));
return 0;
}
@@ -221,7 +218,7 @@ int dbstore (MYDBM_FILE dbf, struct mandata *in, const char *base)
in->name = xstrdup (base);
oldcont = make_content (in);
if (MYDBM_REPLACE (dbf, oldkey, oldcont))
- gripe_replace_key (MYDBM_DPTR (oldkey));
+ gripe_replace_key (dbf, MYDBM_DPTR (oldkey));
MYDBM_FREE_DPTR (oldcont);
free (in->name);
in->name = NULL;
@@ -243,7 +240,7 @@ int dbstore (MYDBM_FILE dbf, struct mandata *in, const char *base)
MYDBM_FREE_DPTR (oldcont);
cont = MYDBM_FETCH (dbf, newkey);
- split_content (MYDBM_DPTR (cont), &info);
+ split_content (dbf, MYDBM_DPTR (cont), &info);
ret = replace_if_necessary (dbf, in, &info,
newkey, newcont);
/* MYDBM_FREE_DPTR (cont); */
@@ -270,7 +267,7 @@ int dbstore (MYDBM_FILE dbf, struct mandata *in, const char *base)
/* Try to replace the old simple data with the new stuff */
if (MYDBM_REPLACE (dbf, oldkey, newcont))
- gripe_replace_key (MYDBM_DPTR (oldkey));
+ gripe_replace_key (dbf, MYDBM_DPTR (oldkey));
MYDBM_FREE_DPTR (newcont);
} else { /* situation (3) */
@@ -285,7 +282,7 @@ int dbstore (MYDBM_FILE dbf, struct mandata *in, const char *base)
/* Extract the old singular reference */
- split_content (MYDBM_DPTR (oldcont), &old);
+ split_content (dbf, MYDBM_DPTR (oldcont), &old);
/* Create multi keys for both old
and new items, create new content */
@@ -336,7 +333,7 @@ int dbstore (MYDBM_FILE dbf, struct mandata *in, const char *base)
* certainly better.
*/
if (MYDBM_REPLACE (dbf, lastkey, lastcont))
- gripe_replace_key (MYDBM_DPTR (lastkey));
+ gripe_replace_key (dbf, MYDBM_DPTR (lastkey));
MYDBM_FREE_DPTR (lastkey);
MYDBM_FREE_DPTR (lastcont);
@@ -345,7 +342,7 @@ int dbstore (MYDBM_FILE dbf, struct mandata *in, const char *base)
newcont = make_content (in);
if (MYDBM_REPLACE (dbf, newkey, newcont))
- gripe_replace_key (MYDBM_DPTR (newkey));
+ gripe_replace_key (dbf, MYDBM_DPTR (newkey));
MYDBM_FREE_DPTR (newkey);
MYDBM_FREE_DPTR (newcont);
@@ -356,7 +353,7 @@ int dbstore (MYDBM_FILE dbf, struct mandata *in, const char *base)
"\t%s\t%s\t%s\t%s", old_name, old.ext, base, in->ext));
if (MYDBM_REPLACE (dbf, oldkey, newcont))
- gripe_replace_key (MYDBM_DPTR (oldkey));
+ gripe_replace_key (dbf, MYDBM_DPTR (oldkey));
/* MYDBM_FREE_DPTR (oldcont); */
free_mandata_elements (&old);
diff --git a/libdb/db_ver.c b/libdb/db_ver.c
index 5ac306d2..56b73392 100644
--- a/libdb/db_ver.c
+++ b/libdb/db_ver.c
@@ -50,11 +50,12 @@ int dbver_rd (MYDBM_FILE dbfile)
MYDBM_FREE_DPTR (key);
if (MYDBM_DPTR (content) == NULL) {
- debug (_("warning: %s has no version identifier\n"), database);
+ debug (_("warning: %s has no version identifier\n"),
+ dbfile->name);
return 1;
} else if (!STREQ (MYDBM_DPTR (content), VER_ID)) {
debug (_("warning: %s is version %s, expecting %s\n"),
- database, MYDBM_DPTR (content), VER_ID);
+ dbfile->name, MYDBM_DPTR (content), VER_ID);
MYDBM_FREE_DPTR (content);
return 1;
} else {
@@ -76,7 +77,7 @@ void dbver_wr (MYDBM_FILE dbfile)
if (MYDBM_INSERT (dbfile, key, content) != 0)
error (FATAL, 0,
_("fatal: unable to insert version identifier into %s"),
- database);
+ dbfile->name);
MYDBM_FREE_DPTR (key);
MYDBM_FREE_DPTR (content);
diff --git a/libdb/db_xdbm.c b/libdb/db_xdbm.c
new file mode 100644
index 00000000..f0a9932e
--- /dev/null
+++ b/libdb/db_xdbm.c
@@ -0,0 +1,169 @@
+/*
+ * db_xdbm.c: common code for gdbm and ndbm backends
+ *
+ * Copyright (C) 2003-2019 Colin Watson.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#if defined(GDBM) || defined(NDBM)
+
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "gl_hash_map.h"
+#include "gl_rbtree_list.h"
+#include "gl_xlist.h"
+#include "gl_xmap.h"
+#include "hash-pjw-bare.h"
+
+#include "manconfig.h"
+
+#include "cleanup.h"
+#include "glcontainers.h"
+
+#include "db_xdbm.h"
+#include "mydbm.h"
+
+static gl_map_t parent_keys;
+
+static int datum_compare (const void *a, const void *b)
+{
+ const datum *left = (const datum *) a;
+ const datum *right = (const datum *) b;
+ int cmp;
+ size_t minsize;
+
+ /* Sentinel NULL elements sort to the end. */
+ if (!MYDBM_DPTR (*left))
+ return 1;
+ else if (!MYDBM_DPTR (*right))
+ return -1;
+
+ if (MYDBM_DSIZE (*left) < MYDBM_DSIZE (*right))
+ minsize = MYDBM_DSIZE (*left);
+ else
+ minsize = MYDBM_DSIZE (*right);
+ cmp = strncmp (MYDBM_DPTR (*left), MYDBM_DPTR (*right), minsize);
+ if (cmp)
+ return cmp;
+ else if (MYDBM_DSIZE (*left) < MYDBM_DSIZE (*right))
+ return 1;
+ else if (MYDBM_DSIZE (*left) > MYDBM_DSIZE (*right))
+ return -1;
+ else
+ return 0;
+}
+
+static bool datum_equals (const void *a, const void *b)
+{
+ return datum_compare (a, b) == 0;
+}
+
+static size_t datum_hash (const void *value)
+{
+ const datum *d = value;
+ return hash_pjw_bare (MYDBM_DPTR (*d), MYDBM_DSIZE (*d));
+}
+
+static void datum_free (const void *value)
+{
+ MYDBM_FREE_DPTR (*(datum *) value);
+}
+
+static datum empty_datum = { NULL, 0 };
+
+/* We keep a map of filenames to sorted lists of keys. Each list is stored
+ * using a hash-based implementation that allows lookup by name and
+ * traversal to the next item in O(log n) time, which is necessary for a
+ * reasonable ordered implementation of nextkey.
+ */
+datum man_xdbm_firstkey (MYDBM_FILE dbf,
+ man_xdbm_unsorted_firstkey unsorted_firstkey,
+ man_xdbm_unsorted_nextkey unsorted_nextkey)
+{
+ gl_list_t keys;
+ datum *key;
+
+ /* Build the raw sorted list of keys. */
+ keys = gl_list_create_empty (GL_RBTREE_LIST, datum_equals, datum_hash,
+ datum_free, false);
+ key = XMALLOC (datum);
+ *key = unsorted_firstkey (dbf);
+ while (MYDBM_DPTR (*key)) {
+ datum *next;
+
+ gl_sortedlist_add (keys, datum_compare, key);
+ next = XMALLOC (datum);
+ *next = unsorted_nextkey (dbf, *key);
+ key = next;
+ }
+
+ if (!parent_keys) {
+ parent_keys = new_string_map (GL_HASH_MAP,
+ (gl_listelement_dispose_fn)
+ gl_list_free);
+ push_cleanup ((cleanup_fun) gl_map_free, parent_keys, 0);
+ }
+
+ /* Remember this structure for use by nextkey. */
+ gl_map_put (parent_keys, xstrdup (dbf->name), keys);
+
+ if (gl_list_size (keys))
+ return copy_datum (*(datum *) gl_list_get_at (keys, 0));
+ else
+ return empty_datum;
+}
+
+datum man_xdbm_nextkey (MYDBM_FILE dbf, datum key)
+{
+ gl_list_t keys;
+ gl_list_node_t node, next_node;
+
+ if (!parent_keys)
+ return empty_datum;
+ keys = (gl_list_t) gl_map_get (parent_keys, dbf->name);
+ if (!keys)
+ return empty_datum;
+
+ node = gl_sortedlist_search (keys, datum_compare, &key);
+ if (!node)
+ return empty_datum;
+ next_node = gl_list_next_node (keys, node);
+ if (!next_node)
+ return empty_datum;
+
+ return copy_datum (*(datum *) gl_list_node_value (keys, next_node));
+}
+
+void man_xdbm_close (MYDBM_FILE dbf, man_xdbm_raw_close raw_close)
+{
+ if (!dbf)
+ return;
+
+ if (parent_keys)
+ gl_map_remove (parent_keys, dbf->name);
+
+ free (dbf->name);
+ raw_close (dbf);
+ free (dbf);
+}
+
+#endif /* GDBM || NDBM */
diff --git a/libdb/db_xdbm.h b/libdb/db_xdbm.h
new file mode 100644
index 00000000..9d7f4bf7
--- /dev/null
+++ b/libdb/db_xdbm.h
@@ -0,0 +1,40 @@
+/*
+ * db_xdbm.c: interface to common code for gdbm and ndbm backends
+ *
+ * Copyright (C) 2019 Colin Watson.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef MAN_XDBM_H
+#define MAN_XDBM_H
+
+#if defined(GDBM) || defined(NDBM)
+
+#include "mydbm.h"
+
+typedef datum (*man_xdbm_unsorted_firstkey) (MYDBM_FILE dbf);
+typedef datum (*man_xdbm_unsorted_nextkey) (MYDBM_FILE dbf, datum key);
+typedef void (*man_xdbm_raw_close) (MYDBM_FILE dbf);
+
+datum man_xdbm_firstkey (MYDBM_FILE dbf,
+ man_xdbm_unsorted_firstkey firstkey,
+ man_xdbm_unsorted_nextkey nextkey);
+datum man_xdbm_nextkey (MYDBM_FILE dbf, datum key);
+void man_xdbm_close (MYDBM_FILE dbf, man_xdbm_raw_close raw_close);
+
+#endif /* GDBM || NDBM */
+
+#endif /* MAN_XDBM_H */
diff --git a/libdb/mydbm.h b/libdb/mydbm.h
index 32053e3e..31f1d756 100644
--- a/libdb/mydbm.h
+++ b/libdb/mydbm.h
@@ -98,30 +98,37 @@ void man_gdbm_close (man_gdbm_wrapper wrap);
# define BERKELEY_DB
# endif /* _DB_H_ */
-extern DBM *ndbm_flopen(char *file, int flags, int mode);
-extern struct timespec ndbm_get_time(DBM *db);
-extern void ndbm_set_time(DBM *db, const struct timespec time);
-extern int ndbm_flclose(DBM *db);
+typedef struct {
+ char *name;
+ DBM *file;
+} *man_ndbm_wrapper;
+
+extern man_ndbm_wrapper man_ndbm_open (const char *name, int flags, int mode);
+extern datum man_ndbm_firstkey (man_ndbm_wrapper wrap);
+extern datum man_ndbm_nextkey (man_ndbm_wrapper wrap, datum key);
+extern struct timespec man_ndbm_get_time (man_ndbm_wrapper wrap);
+extern void man_ndbm_set_time (man_ndbm_wrapper wrap, const struct timespec time);
+extern void man_ndbm_close (man_ndbm_wrapper wrap);
# define DB_EXT ""
-# define MYDBM_FILE DBM*
+# define MYDBM_FILE man_ndbm_wrapper
# define MYDBM_DPTR(d) ((d).dptr)
# define MYDBM_SET_DPTR(d, value) ((d).dptr = (value))
# define MYDBM_DSIZE(d) ((d).dsize)
-# define MYDBM_CTRWOPEN(file) ndbm_flopen(file, O_TRUNC|O_CREAT|O_RDWR, DBMODE)
-# define MYDBM_CRWOPEN(file) ndbm_flopen(file, O_CREAT|O_RDWR, DBMODE)
-# define MYDBM_RWOPEN(file) ndbm_flopen(file, O_RDWR, DBMODE)
-# define MYDBM_RDOPEN(file) ndbm_flopen(file, O_RDONLY, DBMODE)
-# define MYDBM_INSERT(db, key, cont) dbm_store(db, key, cont, DBM_INSERT)
-# define MYDBM_REPLACE(db, key, cont) dbm_store(db, key, cont, DBM_REPLACE)
-# define MYDBM_EXISTS(db, key) (dbm_fetch(db, key).dptr != NULL)
-# define MYDBM_DELETE(db, key) dbm_delete(db, key)
-# define MYDBM_FETCH(db, key) copy_datum(dbm_fetch(db, key))
-# define MYDBM_CLOSE(db) ndbm_flclose(db)
-# define MYDBM_FIRSTKEY(db) copy_datum(dbm_firstkey(db))
-# define MYDBM_NEXTKEY(db, key) copy_datum(dbm_nextkey(db))
-# define MYDBM_GET_TIME(db) ndbm_get_time(db)
-# define MYDBM_SET_TIME(db, time) ndbm_set_time(db, time)
+# define MYDBM_CTRWOPEN(file) man_ndbm_open(file, O_TRUNC|O_CREAT|O_RDWR, DBMODE)
+# define MYDBM_CRWOPEN(file) man_ndbm_open(file, O_CREAT|O_RDWR, DBMODE)
+# define MYDBM_RWOPEN(file) man_ndbm_open(file, O_RDWR, DBMODE)
+# define MYDBM_RDOPEN(file) man_ndbm_open(file, O_RDONLY, DBMODE)
+# define MYDBM_INSERT(db, key, cont) dbm_store((db)->file, key, cont, DBM_INSERT)
+# define MYDBM_REPLACE(db, key, cont) dbm_store((db)->file, key, cont, DBM_REPLACE)
+# define MYDBM_EXISTS(db, key) (dbm_fetch((db)->file, key).dptr != NULL)
+# define MYDBM_DELETE(db, key) dbm_delete((db)->file, key)
+# define MYDBM_FETCH(db, key) copy_datum(dbm_fetch((db)->file, key))
+# define MYDBM_CLOSE(db) man_ndbm_close(db)
+# define MYDBM_FIRSTKEY(db) man_ndbm_firstkey(db)
+# define MYDBM_NEXTKEY(db, key) man_ndbm_nextkey(db, key)
+# define MYDBM_GET_TIME(db) man_ndbm_get_time(db)
+# define MYDBM_SET_TIME(db, time) man_ndbm_set_time(db, time)
# define MYDBM_REORG(db) /* nothing - not implemented */
# elif defined(BTREE) && !defined(NDBM) && !defined(GDBM)
@@ -131,39 +138,48 @@ extern int ndbm_flclose(DBM *db);
# include <limits.h>
# include BDB_H
+typedef struct {
+ char *name;
+ DB *file;
+} *man_btree_wrapper;
+
typedef DBT datum;
-extern DB *btree_flopen(char *filename, int flags, int mode);
-extern int btree_close(DB *db);
-extern int btree_exists(DB *db, datum key);
-extern datum btree_fetch(DB *db, datum key);
-extern int btree_insert(DB *db, datum key, datum cont);
-extern datum btree_firstkey(DB *db);
-extern datum btree_nextkey(DB *db);
-extern int btree_replace(DB *db, datum key, datum content);
-extern int btree_nextkeydata(DB *db, datum *key, datum *cont);
-extern struct timespec btree_get_time(DB *db);
-extern void btree_set_time(DB *db, const struct timespec time);
+extern man_btree_wrapper man_btree_open (const char *filename, int flags,
+ int mode);
+extern void man_btree_close (man_btree_wrapper wrap);
+extern int man_btree_exists (man_btree_wrapper wrap, datum key);
+extern datum man_btree_fetch (man_btree_wrapper wrap, datum key);
+extern int man_btree_insert (man_btree_wrapper wrap, datum key, datum cont);
+extern datum man_btree_firstkey (man_btree_wrapper wrap);
+extern datum man_btree_nextkey (man_btree_wrapper wrap);
+extern int man_btree_replace (man_btree_wrapper wrap,
+ datum key, datum content);
+extern int man_btree_nextkeydata (man_btree_wrapper wrap,
+ datum *key, datum *cont);
+extern struct timespec man_btree_get_time (man_btree_wrapper wrap);
+extern void man_btree_set_time (man_btree_wrapper wrap,
+ const struct timespec time);
# define DB_EXT ".bt"
-# define MYDBM_FILE DB*
+# define MYDBM_FILE man_btree_wrapper
# define MYDBM_DPTR(d) ((char *) (d).data)
# define MYDBM_SET_DPTR(d, value) ((d).data = (char *) (value))
# define MYDBM_DSIZE(d) ((d).size)
-# define MYDBM_CTRWOPEN(file) btree_flopen(file, O_TRUNC|O_CREAT|O_RDWR, DBMODE)
-# define MYDBM_CRWOPEN(file) btree_flopen(file, O_CREAT|O_RDWR, DBMODE)
-# define MYDBM_RWOPEN(file) btree_flopen(file, O_RDWR, DBMODE)
-# define MYDBM_RDOPEN(file) btree_flopen(file, O_RDONLY, DBMODE)
-# define MYDBM_INSERT(db, key, cont) btree_insert(db, key, cont)
-# define MYDBM_REPLACE(db, key, cont) btree_replace(db, key, cont)
-# define MYDBM_EXISTS(db, key) btree_exists(db, key)
-# define MYDBM_DELETE(db, key) ((db->del)(db, &key, 0) ? -1 : 0)
-# define MYDBM_FETCH(db, key) btree_fetch(db, key)
-# define MYDBM_CLOSE(db) btree_close(db)
-# define MYDBM_FIRSTKEY(db) btree_firstkey(db)
-# define MYDBM_NEXTKEY(db, key) btree_nextkey(db)
-# define MYDBM_GET_TIME(db) btree_get_time(db)
-# define MYDBM_SET_TIME(db, time) btree_set_time(db, time)
+# define MYDBM_CTRWOPEN(file) man_btree_open(file, O_TRUNC|O_CREAT|O_RDWR, DBMODE)
+# define MYDBM_CRWOPEN(file) man_btree_open(file, O_CREAT|O_RDWR, DBMODE)
+# define MYDBM_RWOPEN(file) man_btree_open(file, O_RDWR, DBMODE)
+# define MYDBM_RDOPEN(file) man_btree_open(file, O_RDONLY, DBMODE)
+# define MYDBM_INSERT(db, key, cont) man_btree_insert(db, key, cont)
+# define MYDBM_REPLACE(db, key, cont) man_btree_replace(db, key, cont)
+# define MYDBM_EXISTS(db, key) man_btree_exists(db, key)
+# define MYDBM_DELETE(db, key) (((db)->file->del)((db)->file, &key, 0) ? -1 : 0)
+# define MYDBM_FETCH(db, key) man_btree_fetch(db, key)
+# define MYDBM_CLOSE(db) man_btree_close(db)
+# define MYDBM_FIRSTKEY(db) man_btree_firstkey(db)
+# define MYDBM_NEXTKEY(db, key) man_btree_nextkey(db)
+# define MYDBM_GET_TIME(db) man_btree_get_time(db)
+# define MYDBM_SET_TIME(db, time) man_btree_set_time(db, time)
# define MYDBM_REORG(db) /* nothing - not implemented */
# else /* not GDBM or NDBM or BTREE */
@@ -174,8 +190,6 @@ extern void btree_set_time(DB *db, const struct timespec time);
#define MYDBM_SET(d, value) do { MYDBM_SET_DPTR(d, value); MYDBM_RESET_DSIZE(d); } while (0)
#define MYDBM_FREE_DPTR(d) do { free (MYDBM_DPTR (d)); MYDBM_SET_DPTR (d, NULL); } while (0)
-extern char *database;
-
/* db_lookup.c */
extern datum copy_datum (datum dat);