aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac10
-rw-r--r--src/Makefile.am1
-rw-r--r--src/debug.c106
-rw-r--r--src/findkey.c19
-rw-r--r--src/gdbm.h.in23
-rw-r--r--src/gdbmdefs.h37
-rw-r--r--src/gdbmfetch.c7
-rw-r--r--src/gdbmopen.c39
-rw-r--r--src/gdbmseq.c15
-rw-r--r--src/gdbmstore.c15
-rw-r--r--src/gdbmtool.c383
-rw-r--r--src/gdbmtool.h2
-rw-r--r--src/gram.y4
-rw-r--r--src/hash.c2
-rw-r--r--tests/Makefile.am4
-rw-r--r--tests/gtload.c33
16 files changed, 594 insertions, 106 deletions
diff --git a/configure.ac b/configure.ac
index da5b938..4b23931 100644
--- a/configure.ac
+++ b/configure.ac
@@ -176,10 +176,16 @@ AM_CONDITIONAL([GDBM_COND_READLINE], [test "$status_readline" = "yes"])
# Additional debugging
AC_ARG_ENABLE([debug],
AC_HELP_STRING([--enable-debug],
- [provide additional debugging functions]),
+ [provide additional debugging information]),
[status_debug=$withval],
[status_debug=no])
+AC_SUBST([GDBM_DEBUG_ENABLE])
+if test "$status_debug" = "yes"; then
+ GDBM_DEBUG_ENABLE=1
+else
+ GDBM_DEBUG_ENABLE=0
+fi
AM_CONDITIONAL([GDBM_COND_DEBUG_ENABLE], [test "$status_debug" = "yes"])
# Initialize the test suite.
@@ -197,7 +203,7 @@ Compatibility library ......................... $status_compat
Compatibility export tool ..................... $status_export
Memory mapped I/O ............................. $mapped_io
GNU Readline .................................. $status_readline
-Debugging functions ........................... $status_debug
+Debugging support ............................. $status_debug
*******************************************************************
EOF
diff --git a/src/Makefile.am b/src/Makefile.am
index 0eed6e3..a30efc4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -68,7 +68,6 @@ libgdbm_la_SOURCES = \
if GDBM_COND_DEBUG_ENABLE
libgdbm_la_SOURCES += debug.c
- AM_CPPFLAGS += -DGDBM_DEBUG_ENABLE=1
endif
libgdbm_la_LDFLAGS = -version-info $(VI_CURRENT):$(VI_REVISION):$(VI_AGE)
diff --git a/src/debug.c b/src/debug.c
index ceb0f02..d13d48c 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -17,6 +17,112 @@
#include "autoconf.h"
#include "gdbmdefs.h"
+gdbm_debug_printer_t gdbm_debug_printer;
+int gdbm_debug_flags;
+
+struct gdbm_debug_token_desc
+{
+ char const *name;
+ int flag;
+};
+
+struct gdbm_debug_token_desc const gdbm_debug_token_tab[] = {
+ { "err", GDBM_DEBUG_ERR },
+ { "open", GDBM_DEBUG_OPEN },
+ { "store", GDBM_DEBUG_STORE },
+ { "read", GDBM_DEBUG_READ },
+ { "lookup", GDBM_DEBUG_LOOKUP },
+ { "all", GDBM_DEBUG_ALL },
+ { NULL, 0 }
+};
+
+int
+gdbm_debug_token (char const *tok)
+{
+ int i;
+
+ for (i = 0; gdbm_debug_token_tab[i].name; i++)
+ if (strcmp (gdbm_debug_token_tab[i].name, tok) == 0)
+ return gdbm_debug_token_tab[i].flag;
+
+ return 0;
+}
+
+void
+gdbm_debug_parse_state (int (*f) (void *, int, char const *), void *d)
+{
+ int i;
+
+ for (i = 0; gdbm_debug_token_tab[i].name; i++)
+ {
+ if (gdbm_debug_token_tab[i].flag == GDBM_DEBUG_ALL)
+ continue;
+ if (gdbm_debug_flags & gdbm_debug_token_tab[i].flag)
+ {
+ if (f (d, gdbm_debug_token_tab[i].flag, gdbm_debug_token_tab[i].name))
+ break;
+ }
+ }
+}
+
+#define DATBUFSIZE 69
+
+static int
+datbuf_format (char vbuf[DATBUFSIZE], const char *buf, size_t size)
+{
+ char *p = vbuf;
+ char *q = vbuf + 51;
+ int i;
+ size_t j = 0;
+
+ for (i = 0; i < 16; i++)
+ {
+ unsigned c;
+ if (j < size)
+ {
+ c = *(const unsigned char*)buf++;
+ j++;
+ }
+ else
+ c = 0;
+ sprintf(p, "%02X ", c);
+ p += 3;
+ *q++ = isprint(c) ? c : '.';
+ if (i == 7)
+ {
+ *p++ = ' ';
+ *q++ = ' ';
+ }
+ }
+ *p++ = ' ';
+ *p = ' ';
+ *q = 0;
+ return j;
+}
+
+void
+gdbm_debug_datum (datum dat, char const *pfx)
+{
+ char const *buf = dat.dptr;
+ size_t size = dat.dsize;
+ char vbuf[DATBUFSIZE];
+
+ if (!buf)
+ {
+ gdbm_debug_printer ("%s%s\n", pfx, "NULL");
+ return;
+ }
+
+ while (size)
+ {
+ size_t rd = datbuf_format (vbuf, buf, size);
+ gdbm_debug_printer ("%s%s\n", pfx, vbuf);
+ size -= rd;
+ buf += rd;
+ }
+}
+
+
struct hook_list
{
struct hook_list *next;
diff --git a/src/findkey.c b/src/findkey.c
index 1f56083..a757d92 100644
--- a/src/findkey.c
+++ b/src/findkey.c
@@ -107,8 +107,14 @@ _gdbm_findkey (GDBM_FILE dbf, datum key, char **ret_dptr, int *ret_hash_val)
int home_loc; /* The home location in the bucket. */
int key_size; /* Size of the key on the file. */
+ GDBM_DEBUG_DATUM (GDBM_DEBUG_LOOKUP, key, "%s: fetching key:", dbf->name);
+
/* Compute hash value and load proper bucket. */
_gdbm_hash_key (dbf, key, &new_hash_val, &bucket_dir, &elem_loc);
+
+ GDBM_DEBUG (GDBM_DEBUG_LOOKUP, "%s: location = %#4x:%d:%d", dbf->name,
+ new_hash_val, bucket_dir, elem_loc);
+
if (ret_hash_val)
*ret_hash_val = new_hash_val;
if (_gdbm_get_bucket (dbf, bucket_dir))
@@ -121,9 +127,10 @@ _gdbm_findkey (GDBM_FILE dbf, datum key, char **ret_dptr, int *ret_hash_val)
&& dbf->cache_entry->ca_data.dptr != NULL
&& memcmp (dbf->cache_entry->ca_data.dptr, key.dptr, key.dsize) == 0)
{
+ GDBM_DEBUG (GDBM_DEBUG_LOOKUP, "%s: found in cache", dbf->name);
/* This is it. Return the cache pointer. */
if (ret_dptr)
- *ret_dptr = dbf->cache_entry->ca_data.dptr+key.dsize;
+ *ret_dptr = dbf->cache_entry->ca_data.dptr + key.dsize;
return dbf->cache_entry->ca_data.elem_loc;
}
@@ -150,10 +157,15 @@ _gdbm_findkey (GDBM_FILE dbf, datum key, char **ret_dptr, int *ret_hash_val)
The only way to tell is to read it. */
file_key = _gdbm_read_entry (dbf, elem_loc);
if (!file_key)
- return -1;
+ {
+ GDBM_DEBUG (GDBM_DEBUG_LOOKUP, "%s: error reading entry: %s",
+ dbf->name, gdbm_db_strerror (dbf));
+ return -1;
+ }
if (memcmp (file_key, key.dptr, key_size) == 0)
{
/* This is the item. */
+ GDBM_DEBUG (GDBM_DEBUG_LOOKUP, "%s: found", dbf->name);
if (ret_dptr)
*ret_dptr = file_key + key.dsize;
return elem_loc;
@@ -167,9 +179,12 @@ _gdbm_findkey (GDBM_FILE dbf, datum key, char **ret_dptr, int *ret_hash_val)
bucket_hash_val = dbf->bucket->h_table[elem_loc].hash_value;
}
}
+ GDBM_DEBUG (GDBM_DEBUG_LOOKUP, "%s: next location = %#4x:%d:%d",
+ dbf->name, bucket_hash_val, bucket_dir, elem_loc);
}
/* If we get here, we never found the key. */
+ GDBM_DEBUG (GDBM_DEBUG_LOOKUP, "%s: not found", dbf->name);
gdbm_set_errno (dbf, GDBM_ITEM_NOT_FOUND, FALSE);
return -1;
diff --git a/src/gdbm.h.in b/src/gdbm.h.in
index 4ee3a11..3d3a7d0 100644
--- a/src/gdbm.h.in
+++ b/src/gdbm.h.in
@@ -240,6 +240,29 @@ extern const char *gdbm_db_strerror (GDBM_FILE dbf);
extern int gdbm_version_cmp (int const a[], int const b[]);
+#if @GDBM_DEBUG_ENABLE@
+# define GDBM_DEBUG_ENABLE 1
+
+typedef void (*gdbm_debug_printer_t) (char const *, ...);
+extern gdbm_debug_printer_t gdbm_debug_printer;
+extern int gdbm_debug_flags;
+
+# define GDBM_DEBUG_ERR 0x00000001
+# define GDBM_DEBUG_OPEN 0x00000002
+# define GDBM_DEBUG_READ 0x00000004
+# define GDBM_DEBUG_STORE 0x00000008
+# define GDBM_DEBUG_LOOKUP 0x00000010
+
+# define GDBM_DEBUG_ALL 0xffffffff
+
+extern int gdbm_debug_token (char const *tok);
+extern void gdbm_debug_parse_state (int (*f) (void *, int, char const *),
+ void *d);
+
+extern void gdbm_debug_datum (datum dat, char const *pfx);
+
+#endif
+
# if defined(__cplusplus) || defined(c_plusplus)
}
# endif
diff --git a/src/gdbmdefs.h b/src/gdbmdefs.h
index 035fbbe..631c9cd 100644
--- a/src/gdbmdefs.h
+++ b/src/gdbmdefs.h
@@ -253,6 +253,41 @@ struct gdbm_file_info
/* Debugging hooks */
#ifdef GDBM_DEBUG_ENABLE
+#if __STDC_VERSION__ < 199901L
+# if __GNUC__ >= 2
+# define __func__ __FUNCTION__
+# else
+# define __func__ "<unknown>"
+# endif
+#endif
+
+#define _gdbm_str_(s) #s
+#define _gdbm_cat_(a,b) a ":" _gdbm_str_(b)
+#define __gdbm_locus__ _gdbm_cat_(__FILE__,__LINE__)
+
+# define GDBM_DEBUG(flags, fmt, ...) \
+ do \
+ { \
+ if (gdbm_debug_printer && gdbm_debug_flags & (flags)) \
+ SAVE_ERRNO (gdbm_debug_printer (__gdbm_locus__ ":%s: " fmt "\n", \
+ __func__, __VA_ARGS__)); \
+ } \
+ while (0)
+
+# define GDBM_DEBUG_DATUM(flags, dat, fmt, ...) \
+ do \
+ { \
+ if (gdbm_debug_printer && gdbm_debug_flags & (flags)) \
+ { \
+ SAVE_ERRNO( \
+ gdbm_debug_printer (__gdbm_locus__ ":%s: " fmt "\n", \
+ __func__, __VA_ARGS__); \
+ gdbm_debug_datum (dat, __gdbm_locus__": "); \
+ ); \
+ } \
+ } \
+ while (0)
+
typedef int (*gdbm_debug_hook) (char const *, int, char const *, void *);
extern void _gdbm_debug_hook_install (char const *, gdbm_debug_hook, void *);
extern void _gdbm_debug_hook_remove (char const *);
@@ -264,6 +299,8 @@ extern int _gdbm_debug_hook_val (char const *);
# define GDBM_DEBUG_ALLOC(id, stmt) \
(GDBM_DEBUG_HOOK(id) ? NULL : (stmt))
#else
+# define GDBM_DEBUG(flags, fmt, ...)
+# define GDBM_DEBUG_DATUM(flags, dat, fmt, ...)
# define GDBM_DEBUG_HOOK(id) 0
# define GDBM_DEBUG_OVERRIDE(id, stmt) (stmt)
# define GDBM_DEBUG_ALLOC(id, stmt) (stmt)
diff --git a/src/gdbmfetch.c b/src/gdbmfetch.c
index 8deee9c..4710cda 100644
--- a/src/gdbmfetch.c
+++ b/src/gdbmfetch.c
@@ -33,6 +33,8 @@ gdbm_fetch (GDBM_FILE dbf, datum key)
int elem_loc; /* The location in the bucket. */
char *find_data; /* Returned from find_key. */
+ GDBM_DEBUG_DATUM (GDBM_DEBUG_READ, key, "%s: fetching key:", dbf->name);
+
/* Set the default return value. */
return_val.dptr = NULL;
return_val.dsize = 0;
@@ -61,7 +63,12 @@ gdbm_fetch (GDBM_FILE dbf, datum key)
return return_val;
}
memcpy (return_val.dptr, find_data, return_val.dsize);
+
+ GDBM_DEBUG_DATUM (GDBM_DEBUG_READ, return_val,
+ "%s: found", dbf->name);
}
+ else
+ GDBM_DEBUG (GDBM_DEBUG_READ, "%s: key not found", dbf->name);
return return_val;
}
diff --git a/src/gdbmopen.c b/src/gdbmopen.c
index 3891b7c..ce739c2 100644
--- a/src/gdbmopen.c
+++ b/src/gdbmopen.c
@@ -115,7 +115,7 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
dbf->fast_write = TRUE; /* Default to setting fast_write. */
dbf->file_locking = TRUE; /* Default to doing file locking. */
dbf->central_free = FALSE; /* Default to not using central_free. */
- dbf->coalesce_blocks = FALSE; /* Default to not coalescing blocks. */
+ dbf->coalesce_blocks = FALSE; /* Default to not coalesce blocks. */
dbf->need_recovery = FALSE;
dbf->last_error = GDBM_NO_ERROR;
@@ -186,6 +186,8 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
flags &= ~GDBM_BSEXACT;
}
compute_directory_size (dbf, block_size, &dir_size, &dir_bits);
+ GDBM_DEBUG (GDBM_DEBUG_OPEN, "%s: computed dir_size=%d, dir_bits=%d",
+ dbf->name, dir_size, dir_bits);
/* Check for correct block_size. */
if (dir_size != block_size)
{
@@ -200,6 +202,7 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
else
block_size = dir_size;
}
+ GDBM_DEBUG (GDBM_DEBUG_OPEN, "%s: block_size=%d", dbf->name, block_size);
/* Get space for the file header. It will be written to disk, so
make sure there's no garbage in it. */
@@ -312,6 +315,9 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
rc = _gdbm_full_read (dbf, &partial_header, sizeof (gdbm_file_header));
if (rc)
{
+ GDBM_DEBUG (GDBM_DEBUG_ERR|GDBM_DEBUG_OPEN,
+ "%s: error reading partial header: %s",
+ dbf->name, strerror (errno));
if (!(flags & GDBM_CLOERROR))
dbf->desc = -1;
SAVE_ERRNO (gdbm_close (dbf));
@@ -323,6 +329,10 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
if (partial_header.header_magic != GDBM_MAGIC
&& partial_header.header_magic != GDBM_OMAGIC)
{
+ GDBM_DEBUG (GDBM_DEBUG_ERR|GDBM_DEBUG_OPEN,
+ "%s: unexpected magic: %#4x",
+ dbf->name, partial_header.header_magic);
+
if (!(flags & GDBM_CLOERROR))
dbf->desc = -1;
gdbm_close (dbf);
@@ -347,6 +357,9 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
dbf->header = (gdbm_file_header *) malloc (partial_header.block_size);
if (dbf->header == NULL)
{
+ GDBM_DEBUG (GDBM_DEBUG_ERR|GDBM_DEBUG_OPEN,
+ "%s: can't allocate header",
+ dbf->name);
if (!(flags & GDBM_CLOERROR))
dbf->desc = -1;
gdbm_close (dbf);
@@ -355,9 +368,12 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
}
memcpy (dbf->header, &partial_header, sizeof (gdbm_file_header));
rc = _gdbm_full_read (dbf, &dbf->header->avail.av_table[1],
- dbf->header->block_size-sizeof (gdbm_file_header));
+ dbf->header->block_size - sizeof (gdbm_file_header));
if (rc)
{
+ GDBM_DEBUG (GDBM_DEBUG_ERR|GDBM_DEBUG_OPEN,
+ "%s: error reading av_table",
+ dbf->name);
if (!(flags & GDBM_CLOERROR))
dbf->desc = -1;
SAVE_ERRNO (gdbm_close (dbf));
@@ -369,6 +385,9 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
dbf->dir = (off_t *) malloc (dbf->header->dir_size);
if (dbf->dir == NULL)
{
+ GDBM_DEBUG (GDBM_DEBUG_ERR|GDBM_DEBUG_OPEN,
+ "%s: can't allocate directory",
+ dbf->name);
if (!(flags & GDBM_CLOERROR))
dbf->desc = -1;
gdbm_close (dbf);
@@ -380,6 +399,9 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
file_pos = __lseek (dbf, dbf->header->dir, SEEK_SET);
if (file_pos != dbf->header->dir)
{
+ GDBM_DEBUG (GDBM_DEBUG_ERR|GDBM_DEBUG_OPEN,
+ "%s: __lseek: %s",
+ dbf->name, strerror (errno));
if (!(flags & GDBM_CLOERROR))
dbf->desc = -1;
SAVE_ERRNO (gdbm_close (dbf));
@@ -390,6 +412,9 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
rc = _gdbm_full_read (dbf, dbf->dir, dbf->header->dir_size);
if (rc)
{
+ GDBM_DEBUG (GDBM_DEBUG_ERR|GDBM_DEBUG_OPEN,
+ "%s: error reading dir: %s",
+ dbf->name, strerror (errno));
if (!(flags & GDBM_CLOERROR))
dbf->desc = -1;
SAVE_ERRNO (gdbm_close (dbf));
@@ -407,6 +432,10 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
else
{
/* gdbm_errno should already be set. */
+ GDBM_DEBUG (GDBM_DEBUG_ERR|GDBM_DEBUG_OPEN,
+ "%s: _gdbm_mapped_init failed: %s",
+ dbf->name, strerror (errno));
+
if (!(flags & GDBM_CLOERROR))
dbf->desc = -1;
SAVE_ERRNO (gdbm_close (dbf));
@@ -424,7 +453,9 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
dbf->directory_changed = FALSE;
dbf->bucket_changed = FALSE;
dbf->second_changed = FALSE;
-
+
+ GDBM_DEBUG (GDBM_DEBUG_ALL, "%s: opened successfully", dbf->name);
+
/* Everything is fine, return the pointer to the file
information structure. */
return dbf;
@@ -457,7 +488,7 @@ gdbm_open (const char *file, int block_size, int flags, int mode,
int fd;
/* additional bits for open(2) flags */
int fbits = 0;
-
+
switch (flags & GDBM_OPENMASK)
{
case GDBM_READER:
diff --git a/src/gdbmseq.c b/src/gdbmseq.c
index 4320366..08a8f10 100644
--- a/src/gdbmseq.c
+++ b/src/gdbmseq.c
@@ -101,6 +101,8 @@ gdbm_firstkey (GDBM_FILE dbf)
/* Set the default return value for not finding a first entry. */
return_val.dptr = NULL;
+ GDBM_DEBUG (GDBM_DEBUG_READ, "%s: getting first key", dbf->name);
+
/* Return immediately if the database needs recovery */
GDBM_ASSERT_CONSISTENCY (dbf, return_val);
@@ -113,6 +115,11 @@ gdbm_firstkey (GDBM_FILE dbf)
/* Look for first entry. */
get_next_key (dbf, -1, &return_val);
+ if (return_val.dptr)
+ GDBM_DEBUG_DATUM (GDBM_DEBUG_READ, return_val, "%s: found", dbf->name);
+ else
+ GDBM_DEBUG (GDBM_DEBUG_READ, "%s: key not found", dbf->name);
+
return return_val;
}
@@ -128,6 +135,8 @@ gdbm_nextkey (GDBM_FILE dbf, datum key)
/* Set the default return value for no next entry. */
return_val.dptr = NULL;
+ GDBM_DEBUG_DATUM (GDBM_DEBUG_READ, key, "%s: getting next key", dbf->name);
+
/* Return immediately if the database needs recovery */
GDBM_ASSERT_CONSISTENCY (dbf, return_val);
@@ -137,6 +146,7 @@ gdbm_nextkey (GDBM_FILE dbf, datum key)
/* Do we have a valid key? */
if (key.dptr == NULL)
{
+ GDBM_DEBUG (GDBM_DEBUG_READ, "%s: key not found", dbf->name);
gdbm_set_errno (dbf, GDBM_ITEM_NOT_FOUND, FALSE); /* FIXME: special error code perhaps */
return return_val;
}
@@ -148,5 +158,10 @@ gdbm_nextkey (GDBM_FILE dbf, datum key)
/* Find the next key. */
get_next_key (dbf, elem_loc, &return_val);
+ if (return_val.dptr)
+ GDBM_DEBUG_DATUM (GDBM_DEBUG_READ, return_val, "%s: found", dbf->name);
+ else
+ GDBM_DEBUG (GDBM_DEBUG_READ, "%s: key not found", dbf->name);
+
return return_val;
}
diff --git a/src/gdbmstore.c b/src/gdbmstore.c
index 1d7c648..050b0a9 100644
--- a/src/gdbmstore.c
+++ b/src/gdbmstore.c
@@ -47,12 +47,16 @@ gdbm_store (GDBM_FILE dbf, datum key, datum content, int flags)
int new_size; /* Used in allocating space. */
int rc;
+ GDBM_DEBUG_DATUM (GDBM_DEBUG_STORE, key, "%s: storing key:", dbf->name);
+
/* Return immediately if the database needs recovery */
GDBM_ASSERT_CONSISTENCY (dbf, -1);
/* First check to make sure this guy is a writer. */
if (dbf->read_write == GDBM_READER)
{
+ GDBM_DEBUG (GDBM_DEBUG_STORE|GDBM_DEBUG_ERR,
+ "%s: can't store: not a writer", dbf->name);
gdbm_set_errno (dbf, GDBM_READER_CANT_STORE, FALSE);
return -1;
}
@@ -61,6 +65,8 @@ gdbm_store (GDBM_FILE dbf, datum key, datum content, int flags)
NULL dptr returned by a lookup procedure indicates an error. */
if ((key.dptr == NULL) || (content.dptr == NULL))
{
+ GDBM_DEBUG (GDBM_DEBUG_STORE|GDBM_DEBUG_ERR,
+ "%s: can't store: invalid key or content", dbf->name);
gdbm_set_errno (dbf, GDBM_ILLEGAL_DATA, FALSE);
return -1;
}
@@ -97,6 +103,8 @@ gdbm_store (GDBM_FILE dbf, datum key, datum content, int flags)
}
else
{
+ GDBM_DEBUG (GDBM_DEBUG_STORE|GDBM_DEBUG_ERR,
+ "%s: cannot replace", dbf->name);
gdbm_set_errno (dbf, GDBM_CANNOT_REPLACE, FALSE);
return 1;
}
@@ -148,6 +156,8 @@ gdbm_store (GDBM_FILE dbf, datum key, datum content, int flags)
__lseek (dbf, file_adr, SEEK_SET));
if (file_pos != file_adr)
{
+ GDBM_DEBUG (GDBM_DEBUG_STORE|GDBM_DEBUG_ERR,
+ "%s: lseek: %s", dbf->name, strerror (errno));
gdbm_set_errno (dbf, GDBM_FILE_SEEK_ERROR, TRUE);
_gdbm_fatal (dbf, _("lseek error"));
return -1;
@@ -157,6 +167,8 @@ gdbm_store (GDBM_FILE dbf, datum key, datum content, int flags)
_gdbm_full_write (dbf, key.dptr, key.dsize));
if (rc)
{
+ GDBM_DEBUG (GDBM_DEBUG_STORE|GDBM_DEBUG_ERR,
+ "%s: writing key: %s", dbf->name, strerror (errno));
gdbm_set_errno (dbf, rc, TRUE);
_gdbm_fatal (dbf, gdbm_strerror (rc));
return -1;
@@ -167,6 +179,9 @@ gdbm_store (GDBM_FILE dbf, datum key, datum content, int flags)
content.dptr, content.dsize));
if (rc)
{
+ GDBM_DEBUG (GDBM_DEBUG_STORE|GDBM_DEBUG_ERR,
+ "%s: writing content: %s",
+ dbf->name, strerror (errno));
gdbm_set_errno (dbf, rc, TRUE);
_gdbm_fatal (dbf, gdbm_strerror (rc));
return -1;
diff --git a/src/gdbmtool.c b/src/gdbmtool.c
index 97ba0c1..c3d5009 100644
--- a/src/gdbmtool.c
+++ b/src/gdbmtool.c
@@ -181,9 +181,9 @@ print_bucket (FILE *fp, hash_bucket *bucket, const char *mesg, ...)
}
fprintf (fp, _("\nAvail count = %1d\n"), bucket->av_count);
- fprintf (fp, _("Avail adr size\n"));
+ fprintf (fp, _("Address size\n"));
for (index = 0; index < bucket->av_count; index++)
- fprintf (fp, "%9lu%9d\n",
+ fprintf (fp, "%11lu%9d\n",
(unsigned long) bucket->bucket_avail[index].av_adr,
bucket->bucket_avail[index].av_size);
}
@@ -357,11 +357,14 @@ get_screen_lines ()
void
open_handler (struct handler_param *param)
{
- if (opendb (PARAM_STRING (param, 0)) == 0)
+ char *name = tildexpand (PARAM_STRING (param, 0));
+ if (opendb (name) == 0)
{
free (file_name);
- file_name = estrdup (PARAM_STRING (param, 0));
+ file_name = name;
}
+ else
+ free (name);
}
/* Close database */
@@ -446,7 +449,7 @@ fetch_handler (struct handler_param *param)
free (return_data.dptr);
}
else if (gdbm_errno == GDBM_ITEM_NOT_FOUND)
- fprintf (stderr, _("No such item found.\n"));
+ terror ("%s", _("No such item found."));
else
terror (_("Can't fetch data: %s"), gdbm_strerror (gdbm_errno));
}
@@ -458,7 +461,7 @@ store_handler (struct handler_param *param)
if (gdbm_store (gdbm_file,
PARAM_DATUM (param, 0), PARAM_DATUM (param, 1),
GDBM_REPLACE) != 0)
- fprintf (stderr, _("Item not inserted.\n"));
+ terror ("%s", _("Item not inserted."));
}
/* first - begin iteration */
@@ -513,7 +516,7 @@ nextkey_handler (struct handler_param *param)
}
else if (gdbm_errno == GDBM_ITEM_NOT_FOUND)
{
- fprintf (stderr, _("No such item found.\n"));
+ terror ("%s", _("No such item found."));
free (key_data.dptr);
key_data.dptr = NULL;
}
@@ -526,9 +529,9 @@ void
reorganize_handler (struct handler_param *param GDBM_ARG_UNUSED)
{
if (gdbm_reorganize (gdbm_file))
- fprintf (stderr, _("Reorganization failed.\n"));
+ terror ("%s", _("Reorganization failed."));
else
- fprintf (stderr, _("Reorganization succeeded.\n"));
+ fprintf (param->fp, _("Reorganization succeeded."));
}
static void
@@ -715,7 +718,7 @@ print_bucket_begin (struct handler_param *param, size_t *exp_count)
if (temp >= GDBM_DIR_COUNT (gdbm_file))
{
- fprintf (stderr, _("Not a bucket.\n"));
+ terror (_("Not a bucket."));
return 1;
}
_gdbm_get_bucket (gdbm_file, temp);
@@ -723,7 +726,6 @@ print_bucket_begin (struct handler_param *param, size_t *exp_count)
*exp_count = bucket_print_lines (gdbm_file->bucket) + 3;
return 0;
}
-
/* dir - print hash directory */
int
@@ -740,7 +742,7 @@ void
print_dir_handler (struct handler_param *param)
{
int i;
-
+
fprintf (param->fp, _("Hash table directory.\n"));
fprintf (param->fp, _(" Size = %d. Bits = %d. \n\n"),
gdbm_file->header->dir_size, gdbm_file->header->dir_bits);
@@ -791,15 +793,15 @@ hash_handler (struct handler_param *param)
{
int hashval, bucket, off;
_gdbm_hash_key (gdbm_file, PARAM_DATUM (param, 0),
- &hashval, &bucket, &off);
+ &hashval, &bucket, &off);
fprintf (param->fp, _("hash value = %x, bucket #%u, slot %u"),
- hashval,
- hashval >> (GDBM_HASH_BITS - gdbm_file->header->dir_bits),
- hashval % gdbm_file->header->bucket_elems);
+ hashval,
+ hashval >> (GDBM_HASH_BITS - gdbm_file->header->dir_bits),
+ hashval % gdbm_file->header->bucket_elems);
}
else
fprintf (param->fp, _("hash value = %x"),
- _gdbm_hash (PARAM_DATUM (param, 0)));
+ _gdbm_hash (PARAM_DATUM (param, 0)));
fprintf (param->fp, ".\n");
}
@@ -813,7 +815,7 @@ print_cache_begin (struct handler_param *param GDBM_ARG_UNUSED, size_t *exp_coun
*exp_count = gdbm_file->bucket_cache ? gdbm_file->cache_size + 1 : 1;
return 0;
}
-
+
void
print_cache_handler (struct handler_param *param)
{
@@ -836,13 +838,13 @@ list_begin (struct handler_param *param GDBM_ARG_UNUSED, size_t *exp_count)
if (exp_count)
{
gdbm_count_t count;
-
+
if (gdbm_count (gdbm_file, &count))
- *exp_count = 0;
+ *exp_count = 0;
else if (count > SIZE_T_MAX)
- *exp_count = SIZE_T_MAX;
+ *exp_count = SIZE_T_MAX;
else
- *exp_count = count;
+ *exp_count = count;
}
return 0;
@@ -861,18 +863,18 @@ list_handler (struct handler_param *param)
data = gdbm_fetch (gdbm_file, key);
if (!data.dptr)
- {
- terror (_("cannot fetch data; the key was:"));
- datum_format (stderr, &key, dsdef[DS_KEY]);
- }
+ {
+ terror (_("cannot fetch data; the key was:"));
+ datum_format (stderr, &key, dsdef[DS_KEY]);
+ }
else
- {
- datum_format (param->fp, &key, dsdef[DS_KEY]);
- fputc (' ', param->fp);
- datum_format (param->fp, &data, dsdef[DS_CONTENT]);
- fputc ('\n', param->fp);
- free (data.dptr);
- }
+ {
+ datum_format (param->fp, &key, dsdef[DS_KEY]);
+ fputc (' ', param->fp);
+ datum_format (param->fp, &data, dsdef[DS_CONTENT]);
+ fputc ('\n', param->fp);
+ free (data.dptr);
+ }
free (key.dptr);
key = nextkey;
}
@@ -896,20 +898,20 @@ export_handler (struct handler_param *param)
int flags = GDBM_WRCREAT;
int i;
int filemode;
-
+
for (i = 1; i < param->argc; i++)
{
if (strcmp (PARAM_STRING (param, i), "truncate") == 0)
- flags = GDBM_NEWDB;
+ flags = GDBM_NEWDB;
else if (strcmp (PARAM_STRING (param, i), "binary") == 0)
- format = GDBM_DUMP_FMT_BINARY;
+ format = GDBM_DUMP_FMT_BINARY;
else if (strcmp (PARAM_STRING (param, i), "ascii") == 0)
- format = GDBM_DUMP_FMT_ASCII;
+ format = GDBM_DUMP_FMT_ASCII;
else
- {
- terror (_("unrecognized argument: %s"), PARAM_STRING (param, i));
- return;
- }
+ {
+ terror (_("unrecognized argument: %s"), PARAM_STRING (param, i));
+ return;
+ }
}
if (variable_get ("filemode", VART_INT, (void**) &filemode))
@@ -917,7 +919,7 @@ export_handler (struct handler_param *param)
if (gdbm_dump (gdbm_file, PARAM_STRING (param, 0), format, flags, filemode))
{
terror (_("error dumping database: %s"),
- gdbm_strerror (gdbm_errno));
+ gdbm_strerror (gdbm_errno));
}
}
@@ -930,23 +932,23 @@ import_handler (struct handler_param *param)
int meta_mask = 0;
int i;
int rc;
-
+
for (i = 1; i < param->argc; i++)
{
if (strcmp (PARAM_STRING (param, i), "replace") == 0)
- flag = GDBM_REPLACE;
+ flag = GDBM_REPLACE;
else if (strcmp (PARAM_STRING (param, i), "nometa") == 0)
- meta_mask = GDBM_META_MASK_MODE | GDBM_META_MASK_OWNER;
+ meta_mask = GDBM_META_MASK_MODE | GDBM_META_MASK_OWNER;
else
- {
- terror (_("unrecognized argument: %s"),
- PARAM_STRING (param, i));
- return;
- }
+ {
+ terror (_("unrecognized argument: %s"),
+ PARAM_STRING (param, i));
+ return;
+ }
}
rc = gdbm_load (&gdbm_file, PARAM_STRING (param, 0), flag,
- meta_mask, &err_line);
+ meta_mask, &err_line);
if (rc && gdbm_errno == GDBM_NO_DBNAME)
{
int t = open_mode;
@@ -956,29 +958,29 @@ import_handler (struct handler_param *param)
open_mode = t;
if (rc)
- return;
+ return;
rc = gdbm_load (&gdbm_file, PARAM_STRING (param, 0), flag,
- meta_mask, &err_line);
+ meta_mask, &err_line);
}
if (rc)
{
switch (gdbm_errno)
- {
- case GDBM_ERR_FILE_OWNER:
- case GDBM_ERR_FILE_MODE:
- terror (_("error restoring metadata: %s (%s)"),
- gdbm_strerror (gdbm_errno), strerror (errno));
- break;
-
- default:
- if (err_line)
- terror ("%s:%lu: %s", PARAM_STRING (param, 0), err_line,
- gdbm_strerror (gdbm_errno));
- else
- terror (_("cannot load from %s: %s"), PARAM_STRING (param, 0),
- gdbm_strerror (gdbm_errno));
- }
+ {
+ case GDBM_ERR_FILE_OWNER:
+ case GDBM_ERR_FILE_MODE:
+ terror (_("error restoring metadata: %s (%s)"),
+ gdbm_strerror (gdbm_errno), strerror (errno));
+ break;
+
+ default:
+ if (err_line)
+ terror ("%s:%lu: %s", PARAM_STRING (param, 0), err_line,
+ gdbm_strerror (gdbm_errno));
+ else
+ terror (_("cannot load from %s: %s"), PARAM_STRING (param, 0),
+ gdbm_strerror (gdbm_errno));
+ }
return;
}
@@ -1003,6 +1005,77 @@ status_handler (struct handler_param *param)
dsprint (param->fp, DS_CONTENT, dsdef[DS_CONTENT]);
}
+#ifdef GDBM_DEBUG_ENABLE
+static int
+debug_flag_printer (void *data, int flag, char const *tok)
+{
+ FILE *fp = data;
+ fprintf (fp, " %s", tok);
+ return 0;
+}
+#endif
+
+void
+debug_handler (struct handler_param *param)
+{
+#ifdef GDBM_DEBUG_ENABLE
+ if (param->vararg)
+ {
+ struct gdbmarg *arg;
+ int i;
+
+ for (arg = param->vararg, i = 0; arg; arg = arg->next, i++)
+ {
+ if (arg->type == GDBM_ARG_STRING)
+ {
+ int flag;
+ int negate;
+ char const *tok = arg->v.string;
+
+ if (tok[0] == '-')
+ {
+ ++tok;
+ negate = 1;
+ }
+ else if (tok[0] == '+')
+ {
+ ++tok;
+ negate = 0;
+ }
+ else
+ negate = 0;
+
+ flag = gdbm_debug_token (tok);
+ if (flag)
+ {
+ if (negate)
+ gdbm_debug_flags &= ~flag;
+ else
+ gdbm_debug_flags |= flag;
+ }
+ else
+ terror (_("unknown debug flag: %s"), tok);
+ }
+ else
+ terror (_("invalid type of argument %d"), i);
+ }
+ }
+ else
+ {
+ fprintf (param->fp, _("Debug flags:"));
+ if (gdbm_debug_flags)
+ {
+ gdbm_debug_parse_state (debug_flag_printer, param->fp);
+ }
+ else
+ fprintf (param->fp, " %s", _("none"));
+ fputc ('\n', param->fp);
+ }
+#else
+ terror ("%s", _("compiled without debug support"));
+#endif
+}
+
void
source_handler (struct handler_param *param)
{
@@ -1034,6 +1107,8 @@ struct command
void (*handler) (struct handler_param *param);
void (*end) (void *data);
struct argdef args[NARGS];
+ int variadic;
+ int repeat;
char *doc;
};
@@ -1041,47 +1116,73 @@ struct command command_tab[] = {
#define S(s) #s, sizeof (#s) - 1
{ S(count), T_CMD,
checkdb, count_handler, NULL,
- { { NULL } }, N_("count (number of entries)") },
+ { { NULL } },
+ FALSE,
+ FALSE,
+ N_("count (number of entries)") },
{ S(delete), T_CMD,
checkdb, delete_handler, NULL,
- { { N_("KEY"), GDBM_ARG_DATUM, DS_KEY }, { NULL } }, N_("delete a record") },
+ { { N_("KEY"), GDBM_ARG_DATUM, DS_KEY }, { NULL } },
+ FALSE,
+ FALSE,
+ N_("delete a record") },
{ S(export), T_CMD,
checkdb, export_handler, NULL,
{ { N_("FILE"), GDBM_ARG_STRING },
{ "[truncate]", GDBM_ARG_STRING },
{ "[binary|ascii]", GDBM_ARG_STRING },
{ NULL } },
+ FALSE,
+ FALSE,
N_("export") },
{ S(fetch), T_CMD,
checkdb, fetch_handler, NULL,
- { { N_("KEY"), GDBM_ARG_DATUM, DS_KEY }, { NULL } }, N_("fetch record") },
+ { { N_("KEY"), GDBM_ARG_DATUM, DS_KEY }, { NULL } },
+ FALSE,
+ FALSE,
+ N_("fetch record") },
{ S(import), T_CMD,
NULL, import_handler, NULL,
{ { N_("FILE"), GDBM_ARG_STRING },
{ "[replace]", GDBM_ARG_STRING },
{ "[nometa]" , GDBM_ARG_STRING },
{ NULL } },