aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile.am4
-rw-r--r--NEWS33
-rw-r--r--README2
-rw-r--r--README-alpha2
-rw-r--r--README-hacking2
-rwxr-xr-xbootstrap2
-rw-r--r--compat/Makefile.am2
-rw-r--r--compat/close.c2
-rw-r--r--compat/dbm-priv.h2
-rw-r--r--compat/dbm.h2
-rw-r--r--compat/dbmclose.c2
-rw-r--r--compat/dbmdelete.c4
-rw-r--r--compat/dbmdirfno.c2
-rw-r--r--compat/dbmerr.c2
-rw-r--r--compat/dbmfetch.c2
-rw-r--r--compat/dbminit.c4
-rw-r--r--compat/dbmopen.c6
-rw-r--r--compat/dbmpagfno.c2
-rw-r--r--compat/dbmrdonly.c2
-rw-r--r--compat/dbmseq.c2
-rw-r--r--compat/dbmstore.c2
-rw-r--r--compat/delete.c4
-rw-r--r--compat/fetch.c2
-rw-r--r--compat/ndbm.h2
-rw-r--r--compat/seq.c4
-rw-r--r--compat/store.c2
-rw-r--r--configure.ac10
-rw-r--r--doc/Makefile.am2
-rw-r--r--doc/fdl.texi2
-rw-r--r--doc/gdbm.32
-rw-r--r--doc/gdbm.texi143
-rw-r--r--doc/gdbm_dump.12
-rw-r--r--doc/gdbm_load.12
-rw-r--r--doc/gdbmtool.12
-rw-r--r--fuzz/build_seed.sh2
-rw-r--r--fuzz/gdbm_fuzzer.c2
-rw-r--r--fuzz/gdbm_fuzzer.rc2
-rw-r--r--po/Makevars2
-rw-r--r--po/POTFILES.in24
-rw-r--r--src/.gitignore13
-rw-r--r--src/Makefile.am63
-rw-r--r--src/avail.c2
-rw-r--r--src/base64.c2
-rw-r--r--src/bucket.c422
-rw-r--r--src/cachetree.c484
-rw-r--r--src/debug.c2
-rw-r--r--src/falloc.c8
-rw-r--r--src/findkey.c24
-rw-r--r--src/fullio.c2
-rw-r--r--src/gdbm.h.in15
-rw-r--r--src/gdbm.magic2
-rw-r--r--src/gdbmclose.c2
-rw-r--r--src/gdbmconst.h2
-rw-r--r--src/gdbmcount.c2
-rw-r--r--src/gdbmdefs.h38
-rw-r--r--src/gdbmdelete.c10
-rw-r--r--src/gdbmdump.c2
-rw-r--r--src/gdbmerrno.c4
-rw-r--r--src/gdbmexists.c4
-rw-r--r--src/gdbmexp.c2
-rw-r--r--src/gdbmfdesc.c2
-rw-r--r--src/gdbmfetch.c2
-rw-r--r--src/gdbmimp.c4
-rw-r--r--src/gdbmload.c2
-rw-r--r--src/gdbmopen.c21
-rw-r--r--src/gdbmreorg.c2
-rw-r--r--src/gdbmseq.c4
-rw-r--r--src/gdbmsetopt.c91
-rw-r--r--src/gdbmstore.c5
-rw-r--r--src/gdbmsync.c2
-rw-r--r--src/gettext.h2
-rw-r--r--src/hash.c2
-rw-r--r--src/lock.c2
-rw-r--r--src/mmap.c6
-rw-r--r--src/proto.h24
-rw-r--r--src/recover.c14
-rw-r--r--src/systems.h4
-rw-r--r--src/update.c18
-rw-r--r--src/version.c2
-rw-r--r--tests/.gitignore3
-rw-r--r--tests/Makefile.am12
-rw-r--r--tests/atlocal.in4
-rw-r--r--tests/blocksize00.at2
-rw-r--r--tests/blocksize01.at2
-rw-r--r--tests/blocksize02.at2
-rw-r--r--tests/cloexec00.at2
-rw-r--r--tests/cloexec01.at2
-rw-r--r--tests/cloexec02.at2
-rw-r--r--tests/cloexec03.at2
-rw-r--r--tests/closerr.c2
-rw-r--r--tests/conv.at2
-rw-r--r--tests/create00.at2
-rw-r--r--tests/d_creat_ce.c2
-rw-r--r--tests/dbmcreate00.at2
-rw-r--r--tests/dbmcvt.at2
-rw-r--r--tests/dbmdel00.at2
-rw-r--r--tests/dbmdel01.at2
-rw-r--r--tests/dbmdel02.at2
-rw-r--r--tests/dbmfetch00.at2
-rw-r--r--tests/dbmfetch01.at2
-rw-r--r--tests/dbmfetch02.at2
-rw-r--r--tests/dbmfetch03.at2
-rw-r--r--tests/delete00.at2
-rw-r--r--tests/delete01.at2
-rw-r--r--tests/delete02.at2
-rw-r--r--tests/dtdel.c2
-rw-r--r--tests/dtdump.c2
-rw-r--r--tests/dtfetch.c2
-rw-r--r--tests/dtload.c2
-rw-r--r--tests/dump00.at2
-rw-r--r--tests/fdop.c2
-rw-r--r--tests/fetch00.at2
-rw-r--r--tests/fetch01.at2
-rw-r--r--tests/g_open_ce.c2
-rw-r--r--tests/g_reorg_ce.c2
-rw-r--r--tests/gdbmtool/config/default.exp2
-rw-r--r--tests/gdbmtool00.at2
-rw-r--r--tests/gdbmtool01.at2
-rw-r--r--tests/gdbmtool02.at2
-rw-r--r--tests/gdbmtool03.at2
-rw-r--r--tests/gtcacheopt.c273
-rw-r--r--tests/gtconv.c2
-rw-r--r--tests/gtdel.c2
-rw-r--r--tests/gtdump.c2
-rw-r--r--tests/gtfetch.c2
-rw-r--r--tests/gtload.c17
-rw-r--r--tests/gtopt.c2
-rw-r--r--tests/gtrecover.c2
-rw-r--r--tests/gtver.c2
-rw-r--r--tests/num2word.c2
-rw-r--r--tests/progname.h2
-rw-r--r--tests/setopt00.at2
-rw-r--r--tests/setopt01.at2
-rw-r--r--tests/setopt02.at20
-rw-r--r--tests/t_wordwrap.c181
-rw-r--r--tests/testsuite.at6
-rw-r--r--tests/version.at2
-rw-r--r--tests/wordwrap.at129
-rw-r--r--tools/.gitignore6
-rw-r--r--tools/Makefile.am80
-rw-r--r--tools/datconv.c (renamed from src/datconv.c)2
-rw-r--r--tools/err.c (renamed from src/err.c)2
-rw-r--r--tools/gdbm_dump.c (renamed from src/gdbm_dump.c)2
-rw-r--r--tools/gdbm_load.c (renamed from src/gdbm_load.c)2
-rw-r--r--tools/gdbmapp.h (renamed from src/gdbmapp.h)23
-rw-r--r--tools/gdbmshell.c (renamed from src/gdbmshell.c)555
-rw-r--r--tools/gdbmtool.c (renamed from src/gdbmtool.c)10
-rw-r--r--tools/gdbmtool.h (renamed from src/gdbmtool.h)34
-rw-r--r--tools/gdbmtool.supp (renamed from src/gdbmtool.supp)0
-rw-r--r--tools/gram.y (renamed from src/gram.y)11
-rw-r--r--tools/input-argv.c (renamed from src/input-argv.c)2
-rw-r--r--tools/input-file.c (renamed from src/input-file.c)2
-rw-r--r--tools/input-null.c (renamed from src/input-null.c)2
-rw-r--r--tools/input-rl.c (renamed from src/input-rl.c)2
-rw-r--r--tools/input-std.c (renamed from src/input-std.c)2
-rw-r--r--tools/lex.l (renamed from src/lex.l)114
-rw-r--r--tools/mem.c (renamed from src/mem.c)2
-rw-r--r--tools/parseopt.c (renamed from src/parseopt.c)409
-rw-r--r--tools/progname.c (renamed from src/progname.c)2
-rw-r--r--tools/util.c (renamed from src/util.c)2
-rw-r--r--tools/var.c (renamed from src/var.c)21
-rw-r--r--tools/wordwrap.c635
163 files changed, 2860 insertions, 1416 deletions
diff --git a/.gitignore b/.gitignore
index ffc6ef1..d92fbbe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,7 @@
*.cflow
.deps
.emacs*
+.gdbinit
.libs
ABOUT-NLS
ChangeLog
diff --git a/Makefile.am b/Makefile.am
index 25e200d..59e2643 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- Makefile -*-
-# Copyright (C) 2007-2021 Free Software Foundation, Inc.
+# Copyright (C) 2007-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ EXTRA_DIST = build-aux/config.rpath NOTE-WARNING
if COMPAT_OPT
MAYBE_COMPAT = compat
endif
-SUBDIRS = po src doc $(MAYBE_COMPAT) tests
+SUBDIRS = po src tools doc $(MAYBE_COMPAT) tests
AM_DISTCHECK_CONFIGURE_FLAGS = --enable-libgdbm-compat
diff --git a/NEWS b/NEWS
index 73cb98d..e597c6f 100644
--- a/NEWS
+++ b/NEWS
@@ -1,10 +1,37 @@
-GNU dbm NEWS -- history of user-visible changes. 2021-10-19
-Copyright (C) 1990-2021 Free Software Foundation, Inc.
+GNU dbm NEWS -- history of user-visible changes. 2021-11-14
+Copyright (C) 1990-2022 Free Software Foundation, Inc.
See the end of file for copying conditions.
Please send gdbm bug reports to <bug-gdbm@gnu.org>.
-Version 1.22
+Version 1.22.90 (git)
+
+* Bucket cache switched from balanced tree to hash table
+
+* New option codes for gdbm_setopt
+
+** GDBM_GETDBFORMAT
+
+Return the database format.
+
+** GDBM_GETDIRDEPTH
+
+Return the directory depth, i.e. the number of initial (most significant)
+bits in hash value that are interpreted as index to the directory.
+
+** GDBM_GETBUCKETSIZE
+
+Return maximum number of keys per bucket.
+
+** GDBM_GETCACHEAUTO
+
+Return the status of the automatic cache adjustment.
+
+** GDBM_SETCACHEAUTO
+
+Enable or disable automatic cache adjustment.
+
+Version 1.22, 2021-10-19
* Fix file header validation
diff --git a/README b/README
index 185c2e3..54af553 100644
--- a/README
+++ b/README
@@ -92,7 +92,7 @@ To track the development, visit
* Copyright information:
-Copyright (C) 2011-2021 Free Software Foundation, Inc.
+Copyright (C) 2011-2022 Free Software Foundation, Inc.
Permission is granted to anyone to make or distribute verbatim copies
of this document as received, in any medium, provided that the
diff --git a/README-alpha b/README-alpha
index 02c09e4..c848244 100644
--- a/README-alpha
+++ b/README-alpha
@@ -49,7 +49,7 @@ See the files INSTALL and README for the detailed instructions.
* Copyright information:
-Copyright (C) 1990-2021 Free Software Foundation, Inc.
+Copyright (C) 1990-2022 Free Software Foundation, Inc.
Permission is granted to anyone to make or distribute verbatim copies
of this document as received, in any medium, provided that the
diff --git a/README-hacking b/README-hacking
index e6e5534..9f62dad 100644
--- a/README-hacking
+++ b/README-hacking
@@ -35,7 +35,7 @@ Once done, proceed as described in the file README.
* Copyright information
-Copyright (C) 2011-2021 Free Software Foundation, Inc.
+Copyright (C) 2011-2022 Free Software Foundation, Inc.
Permission is granted to anyone to make or distribute verbatim copies
of this document as received, in any medium, provided that the
diff --git a/bootstrap b/bootstrap
index 5f14f18..04f81f5 100755
--- a/bootstrap
+++ b/bootstrap
@@ -1,5 +1,5 @@
#! /bin/sh
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/compat/Makefile.am b/compat/Makefile.am
index 3265c43..538b138 100644
--- a/compat/Makefile.am
+++ b/compat/Makefile.am
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- Makefile -*-
-# Copyright (C) 2007-2021 Free Software Foundation, Inc.
+# Copyright (C) 2007-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/compat/close.c b/compat/close.c
index 9fb79ad..ab2a3e1 100644
--- a/compat/close.c
+++ b/compat/close.c
@@ -1,7 +1,7 @@
/* close.c - Close the "original" style database. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1993-2021 Free Software Foundation, Inc.
+ Copyright (C) 1993-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/compat/dbm-priv.h b/compat/dbm-priv.h
index 7d76a11..03693ae 100644
--- a/compat/dbm-priv.h
+++ b/compat/dbm-priv.h
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/compat/dbm.h b/compat/dbm.h
index 53b7fdb..6220430 100644
--- a/compat/dbm.h
+++ b/compat/dbm.h
@@ -1,7 +1,7 @@
/* dbm.h - The include file for dbm users. */
/* This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/compat/dbmclose.c b/compat/dbmclose.c
index 9212d3e..2bad3c5 100644
--- a/compat/dbmclose.c
+++ b/compat/dbmclose.c
@@ -1,7 +1,7 @@
/* dbmclose.c - The the dbm file. This is the NDBM interface. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/compat/dbmdelete.c b/compat/dbmdelete.c
index 631d9f6..f6b5ea1 100644
--- a/compat/dbmdelete.c
+++ b/compat/dbmdelete.c
@@ -1,8 +1,8 @@
/* dbmdelete.c - Remove the key and its associated data from the database.
- This is the NDBM unix interface name. */
+ This is the NDBM UNIX interface name. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/compat/dbmdirfno.c b/compat/dbmdirfno.c
index f6c32c0..c5891ab 100644
--- a/compat/dbmdirfno.c
+++ b/compat/dbmdirfno.c
@@ -1,7 +1,7 @@
/* dbmdirfno.c - The .dir file number for NDBM interface. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/compat/dbmerr.c b/compat/dbmerr.c
index de0dd58..6c1fa70 100644
--- a/compat/dbmerr.c
+++ b/compat/dbmerr.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/compat/dbmfetch.c b/compat/dbmfetch.c
index ce645af..bebfc62 100644
--- a/compat/dbmfetch.c
+++ b/compat/dbmfetch.c
@@ -1,7 +1,7 @@
/* dbmfetch.c - Find a key and return the associated data. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/compat/dbminit.c b/compat/dbminit.c
index d8af045..881c4fb 100644
--- a/compat/dbminit.c
+++ b/compat/dbminit.c
@@ -2,7 +2,7 @@
DBM interface. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,7 +25,7 @@ DBM *_gdbm_file;
/* Initialize dbm system. FILE is a pointer to the file name. In
standard dbm, the database is found in files called FILE.pag and
- FILE.dir. To make gdbm compatable with dbm using the dbminit call,
+ FILE.dir. To make gdbm compatible with dbm using the dbminit call,
the same file names are used. Specifically, dbminit will use the file
name FILE.pag in its call to gdbm open. If the file (FILE.pag) has a
size of zero bytes, a file initialization procedure is performed,
diff --git a/compat/dbmopen.c b/compat/dbmopen.c
index 1c2e4b0..e0056c8 100644
--- a/compat/dbmopen.c
+++ b/compat/dbmopen.c
@@ -2,7 +2,7 @@
NDBM interface for dbm use. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -178,7 +178,7 @@ ndbm_open_dir_file (const char *base, int pagfd, int mode)
/* Initialize ndbm system. FILE is a pointer to the file name. In
standard dbm, the database is found in files called FILE.pag and
- FILE.dir. To make gdbm compatable with dbm using the dbminit call,
+ FILE.dir. To make gdbm compatible with dbm using the dbminit call,
the same file names are used. Specifically, dbminit will use the file
name FILE.pag in its call to gdbm open. If the file (FILE.pag) has a
size of zero bytes, a file initialization procedure is performed,
@@ -194,7 +194,7 @@ ndbm_open_dir_file (const char *base, int pagfd, int mode)
FLAGS and MODE are the same as for the open(2) call. This call will
look at the FLAGS and decide what call to make to gdbm_open. For
FLAGS == O_RDONLY, it will be a GDBM_READER, if FLAGS == O_RDWR|O_CREAT,
- it will be a GDBM_WRCREAT (creater and writer) and if the FLAGS == O_RDWR,
+ it will be a GDBM_WRCREAT (creator and writer) and if the FLAGS == O_RDWR,
it will be a GDBM_WRITER and if FLAGS contain O_TRUNC then it will be
a GDBM_NEWDB. The O_CLOEXEC bit raises GDBM_CLOEXEC flag.
All other values of FLAGS are ignored. */
diff --git a/compat/dbmpagfno.c b/compat/dbmpagfno.c
index e2ad0a1..4656bcf 100644
--- a/compat/dbmpagfno.c
+++ b/compat/dbmpagfno.c
@@ -1,7 +1,7 @@
/* dbmpagfno.c - The .pag file number for NDBM interface. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/compat/dbmrdonly.c b/compat/dbmrdonly.c
index 9123303..ed8d031 100644
--- a/compat/dbmrdonly.c
+++ b/compat/dbmrdonly.c
@@ -1,7 +1,7 @@
/* dbmrdonly.c - Check to see if a database is read only, NDBM style. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1993-2021 Free Software Foundation, Inc.
+ Copyright (C) 1993-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/compat/dbmseq.c b/compat/dbmseq.c
index 973eff1..72e389a 100644
--- a/compat/dbmseq.c
+++ b/compat/dbmseq.c
@@ -2,7 +2,7 @@
interface. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/compat/dbmstore.c b/compat/dbmstore.c
index 5b2bde0..dad5e17 100644
--- a/compat/dbmstore.c
+++ b/compat/dbmstore.c
@@ -1,7 +1,7 @@
/* dbmstore.c - Add a new key/data pair to the database. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/compat/delete.c b/compat/delete.c
index 152c094..e67c814 100644
--- a/compat/delete.c
+++ b/compat/delete.c
@@ -1,8 +1,8 @@
/* delete.c - Remove the key and its associated data from the database.
- This is the original unix interface name. */
+ This is the original UNIX interface name. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/compat/fetch.c b/compat/fetch.c
index 4d2c300..1145df6 100644
--- a/compat/fetch.c
+++ b/compat/fetch.c
@@ -1,7 +1,7 @@
/* fetch.c - Find a key and return the associated data. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/compat/ndbm.h b/compat/ndbm.h
index c5901df..034d1cd 100644
--- a/compat/ndbm.h
+++ b/compat/ndbm.h
@@ -1,7 +1,7 @@
/* ndbm.h - The include file for ndbm users. */
/* This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/compat/seq.c b/compat/seq.c
index 534d662..770e8eb 100644
--- a/compat/seq.c
+++ b/compat/seq.c
@@ -1,8 +1,8 @@
/* seq.c - This is the sequential visit of the database. This defines two
- user-visable routines that are used together. This is the DBM interface. */
+ user-visible routines that are used together. This is the DBM interface. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/compat/store.c b/compat/store.c
index 69dac6f..7afe7a1 100644
--- a/compat/store.c
+++ b/compat/store.c
@@ -1,7 +1,7 @@
/* store.c - Add a new key/data pair to the database. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/configure.ac b/configure.ac
index a79c974..699a29c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2007-2021 Free Software Foundation, Inc.
+# Copyright (C) 2007-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -16,6 +16,7 @@
m4_define([_GDBM_VERSION_MAJOR], 1)
m4_define([_GDBM_VERSION_MINOR], 22)
+m4_define([_GDBM_VERSION_PATCH], 90)
AC_INIT([gdbm],
_GDBM_VERSION_MAJOR._GDBM_VERSION_MINOR[]m4_ifdef([_GDBM_VERSION_PATCH],._GDBM_VERSION_PATCH),
@@ -227,12 +228,6 @@ AM_CONDITIONAL([GDBM_COND_DEBUG_ENABLE], [test "$status_debug" = "yes"])
AC_SUBST(YFLAGS_DEBUG)
AC_SUBST(LFLAGS_DEBUG)
if test "$want_gdbmtool_debug" = yes; then
- if ! $LEX --version 2>/dev/null | grep -q flex; then
- AC_MSG_ERROR([--enable-gdbmtool-debug requires flex, which is not available])
- fi
- if ! $YACC --version 2>/dev/null | grep -q bison; then
- AC_MSG_ERROR([--enable-gdbmtool-debug requires bison, which is not available])
- fi
YFLAGS_DEBUG=-t
LFLAGS_DEBUG=-d
fi
@@ -280,6 +275,7 @@ status_ficlone=$status_ficlone])
AC_CONFIG_FILES([Makefile
src/Makefile
src/gdbm.h
+ tools/Makefile
doc/Makefile
compat/Makefile])
diff --git a/doc/Makefile.am b/doc/Makefile.am
index dfb1a2a..5d719ab 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- Makefile -*-
-# Copyright (C) 2007-2021 Free Software Foundation, Inc.
+# Copyright (C) 2007-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/doc/fdl.texi b/doc/fdl.texi
index d0ff5f2..7d7127c 100644
--- a/doc/fdl.texi
+++ b/doc/fdl.texi
@@ -5,7 +5,7 @@
@c hence no sectioning command or @node.
@display
-Copyright @copyright{} 2000-2002, 2007-2008, 2011, 2017-2021 Free
+Copyright @copyright{} 2000--2002, 2007--2008, 2011, 2017--2022 Free
Software Foundation, Inc.
@uref{http://fsf.org/}
diff --git a/doc/gdbm.3 b/doc/gdbm.3
index 612795c..16aabd1 100644
--- a/doc/gdbm.3
+++ b/doc/gdbm.3
@@ -1,5 +1,5 @@
.\" This file is part of GDBM.
-.\" Copyright (C) 2011-2021 Free Software Foundation, Inc.
+.\" Copyright (C) 2011-2022 Free Software Foundation, Inc.
.\"
.\" GDBM is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
diff --git a/doc/gdbm.texi b/doc/gdbm.texi
index a738c85..1d136bb 100644
--- a/doc/gdbm.texi
+++ b/doc/gdbm.texi
@@ -43,7 +43,7 @@ Published by the Free Software Foundation,
51 Franklin Street, Fifth Floor
Boston, MA 02110-1301, USA
-Copyright @copyright{} 1989-1999, 2007-2021 Free Software Foundation,
+Copyright @copyright{} 1989--1999, 2007--2022 Free Software Foundation,
Inc.
Permission is granted to copy, distribute and/or modify this document
@@ -2083,20 +2083,19 @@ success. The global variable @code{gdbm_errno} will be set upon failure.
The valid options are:
-@table @asis
-@kwindex GDBM_CACHESIZE
-@kwindex GDBM_SETCACHESIZE
-@item GDBM_SETCACHESIZE
-@itemx GDBM_CACHESIZE
-@kwindex GDBM_CACHE_AUTO
+@defvr {Option} GDBM_SETCACHESIZE
+@defvrx {Option} GDBM_CACHESIZE
Set the size of the internal bucket cache. The @var{value} should
point to a @code{size_t} holding the desired cache size, or the
-constant @code{GDBM_CACHE_AUTO}, to set the best cache size
+constant @code{GDBM_CACHE_AUTO}, to adjust the cache size
automatically.
-By default, a newly open database is configured to adapt the cache
-size to the number of index buckets in the database file. This
-provides for the best performance.
+By default, a newly open database is configured to dynamically
+accommodate the cache size to the number of index buckets in the
+database file. This provides for the best performance.
+
+If another @var{value} is set, it is adjusted to the nearest larger
+power of two.
Use this option if you wish to limit the memory usage at the expense
of performance. If you chose to do so, please bear in mind that cache
@@ -2110,41 +2109,84 @@ gdbm_bucket_count (dbf, &bn);
ret = gdbm_setopt (dbf, GDBM_SETCACHESIZE, &bn, sizeof (bn));
@end example
-To set the best cache size, use the constant @code{GDBM_CACHE_AUTO}:
+To request the automatically adjustable cache size, use the constant
+@code{GDBM_CACHE_AUTO}:
@example
size_t bn = GDBM_CACHE_AUTO;
ret = gdbm_setopt (dbf, GDBM_SETCACHESIZE, &bn, sizeof (bn));
@end example
+@end defvr
+
+@defvr {Option} GDBM_GETCACHESIZE
+Return the actual size of the internal bucket cache. The @var{value}
+should point to a @code{size_t} variable, where the size will be
+stored.
+@end defvr
+
+@defvr {Option} GDBM_SETCACHEAUTO
+Controls whether the cache size will be adjusted automatically as
+needed. The @var{value} should point to an integer: @code{TRUE} to
+enable automatic cache adjustment and @code{FALSE} to disable it.
+
+The following two calls are equivalent:
+
+@example
+int t = TRUE;
+gdbm_setopt (dbf, GDBM_SETCACHEAUTO, &t, sizeof (t));
+
+size_t n = GDBM_CACHE_AUTO;
+gdbm_setopt (dbf, GDBM_SETCACHESIZE, &n, sizeof (n));
+@end example
+@end defvr
-@kwindex GDBM_GETCACHESIZE
-@item GDBM_GETCACHESIZE
-Return the size of the internal bucket cache. The @var{value} should
-point to a @code{size_t} variable, where the size will be stored.
+@defvr {Option} GDBM_GETCACHEAUTO
+Return the state of the automatic cache size adjustment. The
+@var{value} should point to an integer which, upon successful return,
+will have the value @code{TRUE} if the automatic cache size adjustment
+is enabled and @code{FALSE} otherwise.
+@end defvr
-@kwindex GDBM_GETFLAGS
-@item GDBM_GETFLAGS
+@defvr {Option} GDBM_GETFLAGS
Return the flags describing the state of the database. The @var{value} should
point to an @code{int} variable where to store the flags. On success,
its value will be similar to the flags used when opening the database
(@pxref{Open, gdbm_open}), except that it will reflect the current state
(which may have been altered by another calls to @code{gdbm_setopt}).
+@end defvr
-@kwindex GDBM_FASTMODE
-@item GDBM_FASTMODE
+@defvr {Option} GDBM_GETDBFORMAT
+Return the database format. The @var{value} should point to an
+@code{int} variable. Upon successful return, it will be set to
+@samp{0} if the database is in standard format and @code{GDBM_NUMSYNC}
+if it is in extended format. @xref{Database format}.
+@end defvr
+
+@defvr {Option} GDBM_GETDIRDEPTH
+Returns the @dfn{directory depth}: the number of initial (most significant)
+bits in hash value that are interpreted as index to the directory. The
+actual directory size can be computed as @code{1 << @var{value}}.
+
+The @var{value} argument should point to an @code{int}.
+@end defvr
+
+@defvr {Option} GDBM_GETBUCKETSIZE
+Returns the @dfn{bucket capacity}: maximum number of keys per bucket
+(@code{int}).
+@end defvr
+
+@defvr {Option} GDBM_FASTMODE
Enable or disable the @dfn{fast writes mode}, i.e.@: writes without
subsequent synchronization. The @var{value} should point
to an integer: @code{TRUE} to enable fast mode, and @code{FALSE} to
disable it.
This option is retained for compatibility with previous versions of
-@command{GDBM}. Its effect is the reverse of @code{GDBM_SETSYNCMODE}
-(see below).
+@command{GDBM}. Its effect is the reverse of @code{GDBM_SETSYNCMODE}.
+@end defvr
-@kwindex GDBM_SETSYNCMODE
-@kwindex GDBM_SYNCMODE
-@item GDBM_SETSYNCMODE
-@itemx GDBM_SYNCMODE
+@defvr {Option} GDBM_SETSYNCMODE
+@defvrx {Option} GDBM_SYNCMODE
Turn on or off file system synchronization operations. This
setting defaults to off. The @var{value} should point
to an integer: @code{TRUE} to turn synchronization on, and @code{FALSE} to
@@ -2156,16 +2198,15 @@ as calling @code{GDBM_FASTMODE} with @code{FALSE}.
The @code{GDBM_SYNCMODE} option is provided for compatibility with
earlier versions.
+@end defvr
-@kwindex GDBM_GETSYNCMODE
-@item GDBM_GETSYNCMODE
+@defvr {Option} GDBM_GETSYNCMODE
Return the current synchronization status. The @var{value} should
point to an @code{int} where the status will be stored.
+@end defvr
-@kwindex GDBM_SETCENTFREE
-@kwindex GDBM_CENTFREE
-@item GDBM_SETCENTFREE
-@itemx GDBM_CENTFREE
+@defvr {Option} GDBM_SETCENTFREE
+@defvrx {Option} GDBM_CENTFREE
@emph{NOTICE: This feature is still under study.}
Set central free block pool to either on or off. The default is off,
@@ -2177,11 +2218,10 @@ turn central block pool on, and @code{FALSE} to turn it off.
The @code{GDBM_CENTFREE} option is provided for compatibility with
earlier versions.
+@end defvr
-@kwindex GDBM_SETCOALESCEBLKS
-@kwindex GDBM_COALESCEBLKS
-@item GDBM_SETCOALESCEBLKS
-@itemx GDBM_COALESCEBLKS
+@defvr {Option} GDBM_SETCOALESCEBLKS
+@defvrx {Option} GDBM_COALESCEBLKS
@emph{NOTICE: This feature is still under study.}
Set free block merging to either on or off. The default is off, which
@@ -2191,38 +2231,38 @@ a @acronym{CPU} expensive process with time, though, especially if
used in conjunction with GDBM_CENTFREE. The @var{value} should point
to an integer: @code{TRUE} to turn free block merging on, and @code{FALSE} to
turn it off.
+@end defvr
-@kwindex GDBM_GETCOALESCEBLKS
-@item GDBM_GETCOALESCEBLKS
+@defvr {Option} GDBM_GETCOALESCEBLKS
Return the current status of free block merging. The @var{value} should
point to an @code{int} where the status will be stored.
+@end defvr
-@kwindex GDBM_SETMAXMAPSIZE
-@item GDBM_SETMAXMAPSIZE
+@defvr {Option} GDBM_SETMAXMAPSIZE
Sets maximum size of a memory mapped region. The @var{value} should
point to a value of type @code{size_t}, @code{unsigned long} or
@code{unsigned}. The actual value is rounded to the nearest page
boundary (the page size is obtained from
@code{sysconf(_SC_PAGESIZE)}).
+@end defvr
-@kwindex GDBM_GETMAXMAPSIZE
-@item GDBM_GETMAXMAPSIZE
+@defvr {Option} GDBM_GETMAXMAPSIZE
Return the maximum size of a memory mapped region. The @var{value} should
point to a value of type @code{size_t} where to return the data.
+@end defvr
-@kwindex GDBM_SETMMAP
-@item GDBM_SETMMAP
+@defvr {Option} GDBM_SETMMAP
Enable or disable memory mapping mode. The @var{value} should point
to an integer: @code{TRUE} to enable memory mapping or @code{FALSE} to
disable it.
+@end defvr
-@kwindex GDBM_GETMMAP
-@item GDBM_GETMMAP
+@defvr {Option} GDBM_GETMMAP
Check whether memory mapping is enabled. The @var{value} should point
to an integer where to return the status.
+@end defvr
-@kwindex GDBM_GETDBNAME
-@item GDBM_GETDBNAME
+@defvr {Option} GDBM_GETDBNAME
Return the name of the database disk file. The @var{value} should
point to a variable of type @code{char**}. A pointer to the newly
allocated copy of the file name will be placed there. The caller is
@@ -2243,12 +2283,11 @@ else
free (name);
@}
@end example
+@end defvr
-@kwindex GDBM_GETBLOCKSIZE
-@item GDBM_GETBLOCKSIZE
+@defvr {Option} GDBM_GETBLOCKSIZE
Return the block size in bytes. The @var{value} should point to @code{int}.
-
-@end table
+@end defvr
@node Locking
@chapter File Locking
diff --git a/doc/gdbm_dump.1 b/doc/gdbm_dump.1
index a06ee2e..0111e7b 100644
--- a/doc/gdbm_dump.1
+++ b/doc/gdbm_dump.1
@@ -1,5 +1,5 @@
.\" This file is part of GDBM.
-.\" Copyright (C) 2013-2021 Free Software Foundation, Inc.
+.\" Copyright (C) 2013-2022 Free Software Foundation, Inc.
.\"
.\" GDBM is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
diff --git a/doc/gdbm_load.1 b/doc/gdbm_load.1
index 62fabf6..c4153d0 100644
--- a/doc/gdbm_load.1
+++ b/doc/gdbm_load.1
@@ -1,5 +1,5 @@
.\" This file is part of GDBM. -*- nroff -*-
-.\" Copyright (C) 2011-2021 Free Software Foundation, Inc.
+.\" Copyright (C) 2011-2022 Free Software Foundation, Inc.
.\"
.\" GDBM is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
diff --git a/doc/gdbmtool.1 b/doc/gdbmtool.1
index 4d1dfcb..8ac4fcf 100644
--- a/doc/gdbmtool.1
+++ b/doc/gdbmtool.1
@@ -1,5 +1,5 @@
.\" This file is part of GDBM. -*- nroff -*-
-.\" Copyright (C) 2013-2021 Free Software Foundation, Inc.
+.\" Copyright (C) 2013-2022 Free Software Foundation, Inc.
.\"
.\" GDBM is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
diff --git a/fuzz/build_seed.sh b/fuzz/build_seed.sh
index 5e92924..b6793e6 100644
--- a/fuzz/build_seed.sh
+++ b/fuzz/build_seed.sh
@@ -1,6 +1,6 @@
#!/bin/sh
# This file is part of GDBM.
-# Copyright (C) 2021 Free Software Foundation, Inc.
+# Copyright (C) 2021-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/fuzz/gdbm_fuzzer.c b/fuzz/gdbm_fuzzer.c
index 1dde503..35344ad 100644
--- a/fuzz/gdbm_fuzzer.c
+++ b/fuzz/gdbm_fuzzer.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2021 Free Software Foundation, Inc.
+ Copyright (C) 2021-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/fuzz/gdbm_fuzzer.rc b/fuzz/gdbm_fuzzer.rc
index 781aa75..9bced00 100644
--- a/fuzz/gdbm_fuzzer.rc
+++ b/fuzz/gdbm_fuzzer.rc
@@ -1,5 +1,5 @@
# Run commands for gdbm_fuzzer
-# Copyright (C) 2021 Free Software Foundation, Inc.
+# Copyright (C) 2021-2022 Free Software Foundation, Inc.
# License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
# This is free software: you are free to change and redistribute it.
# There is NO WARRANTY, to the extent permitted by law.
diff --git a/po/Makevars b/po/Makevars
index a777c65..029fa12 100644
--- a/po/Makevars
+++ b/po/Makevars
@@ -1,5 +1,5 @@
# Gettext variables for GDBM
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/po/POTFILES.in b/po/POTFILES.in
index b81a972..82fce18 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,5 +1,5 @@
# List of GDBM source files which contain translatable strings.
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -15,18 +15,22 @@
# along with GDBM. If not, see <http://www.gnu.org/licenses/>.
src/bucket.c
-src/datconv.c
src/falloc.c
src/findkey.c
-src/gdbm_dump.c
-src/gdbm_load.c
src/gdbmerrno.c
src/gdbmstore.c
-src/gdbmtool.c
-src/gdbmshell.c
-src/gram.y
-src/lex.l
-src/parseopt.c
src/recover.c
src/update.c
-src/util.c
+
+tools/datconv.c
+tools/gdbm_dump.c
+tools/gdbm_load.c
+tools/gdbmshell.c
+tools/gdbmtool.c
+tools/gram.y
+tools/input-file.c
+tools/lex.l
+tools/parseopt.c
+tools/util.c
+tools/var.c
+
diff --git a/src/.gitignore b/src/.gitignore
index bc1099e..8de76c3 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1,14 +1 @@
-.deps
-.libs
-.gdbinit
-Makefile
-Makefile.in
gdbm.h
-*.lo
-libgdbm.la
-gdbmtool
-gdbm_dump
-gdbm_load
-gram.[ch]
-gram.output
-lex.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 74103ee..830272f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- Makefile -*-
-# Copyright (C) 2007-2021 Free Software Foundation, Inc.
+# Copyright (C) 2007-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -14,24 +14,17 @@
# You should have received a copy of the GNU General Public License
# along with GDBM. If not, see <http://www.gnu.org/licenses/>.
-# Flags
-AM_CPPFLAGS=-DIN_GDBM -DLOCALEDIR=\"$(localedir)\"
-
# Headers
nodist_include_HEADERS = gdbm.h
noinst_HEADERS = \
gdbmconst.h\
gdbmdefs.h\
gettext.h\
- gram.h\
proto.h\
systems.h
-EXTRA_DIST = gdbm.h.in gdbm.magic gram.y lex.l
-BUILT_SOURCES = gdbm.h gram.h gram.c lex.c
-
-gram.c gram.h: gram.y
-lex.c: lex.l
+EXTRA_DIST = gdbm.h.in gdbm.magic
+BUILT_SOURCES = gdbm.h
# The libraries
VI_CURRENT = 6
@@ -42,7 +35,6 @@ lib_LTLIBRARIES = libgdbm.la
libgdbm_la_LIBADD = @LTLIBINTL@
libgdbm_la_SOURCES = \
- cachetree.c\
gdbmclose.c\
gdbmcount.c\
gdbmdelete.c\
@@ -79,52 +71,3 @@ endif
libgdbm_la_LDFLAGS = -version-info $(VI_CURRENT):$(VI_REVISION):$(VI_AGE)
-noinst_LIBRARIES = libgdbmapp.a
-
-libgdbmapp_a_SOURCES =\
- err.c\
- mem.c\
- gdbmapp.h\
- parseopt.c\
- progname.c\
- datconv.c\
- gram.c\
- input-argv.c\
- input-file.c\
- input-null.c\
- input-std.c\
- lex.c\
- gdbmshell.c\
- var.c\
- util.c
-
-if GDBM_COND_READLINE
- libgdbmapp_a_SOURCES += input-rl.c
-endif
-
-# Programs
-bin_PROGRAMS = gdbmtool gdbm_load gdbm_dump
-
-gdbmtool_LDADD = \
- ./libgdbmapp.a\
- ./libgdbm.la\
- @READLINE_LIBS@
-
-gdbmtool_SOURCES = \
- gdbmtool.h\
- gdbmtool.c
-
-AM_YFLAGS = -dv $(YFLAGS_DEBUG)
-AM_LFLAGS = $(LFLAGS_DEBUG)
-
-.l.c:
- $(AM_V_GEN)$(FLEX) -o $@ $(AM_LFLAGS) $<
-.y.c:
- $(AM_V_GEN)$(BISON) -o $@ $(AM_YFLAGS) $<
-
-if COND_GDBMTOOL_DEBUG
- AM_CPPFLAGS += -DGDBMTOOL_DEBUG=1
-endif
-
-gdbm_load_LDADD = ./libgdbmapp.a ./libgdbm.la
-gdbm_dump_LDADD = ./libgdbmapp.a ./libgdbm.la
diff --git a/src/avail.c b/src/avail.c
index c361d5a..8f8669e 100644
--- a/src/avail.c
+++ b/src/avail.c
@@ -1,7 +1,7 @@
/* avail.c - avail block and stack handling functions. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2021 Free Software Foundation, Inc.
+ Copyright (C) 2021-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/base64.c b/src/base64.c
index 17c2307..15648b4 100644
--- a/src/base64.c
+++ b/src/base64.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/bucket.c b/src/bucket.c
index 4a5a04c..0abec58 100644
--- a/src/bucket.c
+++ b/src/bucket.c
@@ -1,7 +1,7 @@
/* bucket.c - The routines for playing with hash buckets. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,9 +18,10 @@
#include "autoconf.h"
#include "gdbmdefs.h"
+#include <stdint.h>
#include <limits.h>
-#define GDBM_MAX_DIR_SIZE INT_MAX
+#define GDBM_MAX_DIR_SIZE INT32_MAX
#define GDBM_MAX_DIR_HALF (GDBM_MAX_DIR_SIZE / 2)
/* Initializing a new hash buckets sets all bucket entries to -1 hash value. */
@@ -40,18 +41,51 @@ _gdbm_new_bucket (GDBM_FILE dbf, hash_bucket *bucket, int bits)
for (index = 0; index < dbf->header->bucket_elems; index++)
bucket->h_table[index].hash_value = -1;
}
+
+/* Bucket cache table functions */
-static void
-set_cache_entry (GDBM_FILE dbf, cache_elem *elem)
+/* Hash an off_t word into an index of width NBITS. */
+static size_t
+adrhash (off_t adr, size_t nbits)
{
- dbf->cache_entry = elem;
- dbf->bucket = dbf->cache_entry->ca_bucket;
+ adr ^= adr >> (GDBM_HASH_BITS + 1 - nbits);
+ return ((265443576910ul * adr) & 0xffffffff) >> (GDBM_HASH_BITS + 1 - nbits);
}
+/*
+ * Return a pointer to the cache table slot for bucket address ADR.
+ * Never returns NULL.
+ */
+static cache_elem **
+cache_tab_lookup_slot (GDBM_FILE dbf, off_t adr)
+{
+ cache_elem **cache = dbf->cache;
+ size_t h = adrhash (adr, dbf->cache_bits);
+
+ if (cache[h])
+ {
+ if (cache[h]->ca_adr != adr)
+ {
+ cache_elem *prev = cache[h], *p = prev->ca_coll;
+ while (p)
+ {
+ if (p->ca_adr == adr)
+ break;
+ prev = p;
+ p = prev->ca_coll;
+ }
+ return &prev->ca_coll;
+ }
+ }
+ return &cache[h];
+}
/* LRU list management */
-/* Link ELEM after REF in DBF cache. If REF is NULL, link at head */
+/*
+ * Link ELEM after REF in DBF cache. If REF is NULL, link at head and
+ * set DBF->bucket to point to the ca_bucket of ELEM.
+ */
static void
lru_link_elem (GDBM_FILE dbf, cache_elem *elem, cache_elem *ref)
{
@@ -64,6 +98,7 @@ lru_link_elem (GDBM_FILE dbf, cache_elem *elem, cache_elem *ref)
else
dbf->cache_lru = elem;
dbf->cache_mru = elem;
+ dbf->bucket = dbf->cache_mru->ca_bucket;
}
else
{
@@ -79,7 +114,10 @@ lru_link_elem (GDBM_FILE dbf, cache_elem *elem, cache_elem *ref)
}
}
-/* Unlink ELEM from the list of cache elements in DBF. */
+/*
+ * Unlink ELEM from the list of cache elements in DBF.
+ * If cache_mru gets updated, update DBF->bucket accordingly.
+ */
static void
lru_unlink_elem (GDBM_FILE dbf, cache_elem *elem)
{
@@ -88,7 +126,10 @@ lru_unlink_elem (GDBM_FILE dbf, cache_elem *elem)
if ((x = elem->ca_prev))
x->ca_next = elem->ca_next;
else
- dbf->cache_mru = elem->ca_next;
+ {
+ dbf->cache_mru = elem->ca_next;
+ dbf->bucket = dbf->cache_mru ? dbf->cache_mru->ca_bucket : NULL;
+ }
if ((x = elem->ca_next))
x->ca_prev = elem->ca_prev;
else
@@ -126,11 +167,8 @@ cache_elem_new (GDBM_FILE dbf, off_t adr)
elem->ca_data.hash_val = -1;
elem->ca_data.elem_loc = -1;
- elem->ca_prev = elem->ca_next = NULL;
+ elem->ca_prev = elem->ca_next = elem->ca_coll = NULL;
elem->ca_hits = 0;
- elem->ca_node = NULL;
-
- dbf->cache_num++;
return elem;
}
@@ -139,11 +177,25 @@ cache_elem_new (GDBM_FILE dbf, off_t adr)
static void
cache_elem_free (GDBM_FILE dbf, cache_elem *elem)
{
- _gdbm_cache_tree_delete (dbf->cache_tree, elem->ca_node);
+ size_t h = adrhash (elem->ca_adr, dbf->cache_bits);
+ cache_elem **pp;
+
lru_unlink_elem (dbf, elem);
+
elem->ca_next = dbf->cache_avail;
dbf->cache_avail = elem;
dbf->cache_num--;
+
+ pp = &dbf->cache[h];
+ while (*pp)
+ {
+ if (*pp == elem)
+ {
+ *pp = (*pp)->ca_coll;
+ break;
+ }
+ pp = &(*pp)->ca_coll;
+ }
}
/* Free the least recently used cache entry. */
@@ -159,76 +211,159 @@ cache_lru_free (GDBM_FILE dbf)
cache_elem_free (dbf, last);
return 0;
}
-
+
+/*
+ * Round up V to the next highest power of 2 and compute log2 of
+ * it using De Brujin sequences.
+ * See http://supertech.csail.mit.edu/papers/debruijn.pdf
+ */
+static unsigned
+log2i (unsigned v)
+{
+ static const int dbp[32] =
+ {
+ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+ 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
+ };
+
+ v--;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ v++;
+ return dbp[(uint32_t)(v * 0x077CB531U) >> 27];
+}
+
+static int
+cache_tab_resize (GDBM_FILE dbf, int bits)
+{
+ size_t size = 1 << bits;
+
+ if (!dbf->cache || size != dbf->cache_size)
+ {
+ size_t n = size * sizeof (dbf->cache[0]);
+ cache_elem **p, *elem;
+
+ /* Flush existing cache */
+ if (_gdbm_cache_flush (dbf))
+ return -1;
+
+ /* Reallocate it */
+ p = realloc (dbf->cache, n);
+ if (!p)
+ {
+ GDBM_SET_ERRNO (dbf, GDBM_MALLOC_ERROR, FALSE);
+ return -1;
+ }
+ dbf->cache = p;
+ dbf->cache_size = size;
+ dbf->cache_bits = bits;
+
+ memset (dbf->cache, 0, n);
+
+ /* Rehash and free surplus elements */
+ for (elem = dbf->cache_lru; elem; )
+ {
+ cache_elem *prev = elem->ca_prev;
+ elem->ca_coll = NULL;
+ if (size < dbf->cache_num)
+ {
+ cache_elem_free (dbf, elem);
+ }
+ else
+ {
+ p = cache_tab_lookup_slot (dbf, elem->ca_adr);
+ if (*p)
+ abort ();// shouldn't happen
+ *p = elem;
+ }
+ elem = prev;
+ }
+ }
+ return 0;
+}
+
+enum
+ {
+ cache_found,
+ cache_new,
+ cache_failure
+ };
+
static int
cache_lookup (GDBM_FILE dbf, off_t adr, cache_elem *ref, cache_elem **ret_elem)
{
int rc;
- cache_node *node;
- cache_elem *elem;
- int retrying = 0;
+ cache_elem **elp, *elem;
dbf->cache_access_count++;
- retry:
- rc = _gdbm_cache_tree_lookup (dbf->cache_tree, adr, &node);
- switch (rc)
+
+ elp = cache_tab_lookup_slot (dbf, adr);
+
+ if (*elp != NULL)
{
- case node_found:
- elem = node->elem;
+ elem = *elp;
elem->ca_hits++;
dbf->cache_hits++;
lru_unlink_elem (dbf, elem);
- break;
-
- case node_new:
- elem = cache_elem_new (dbf, adr);
- if (!elem)
- {
- _gdbm_cache_tree_delete (dbf->cache_tree, node);
- return node_failure;
- }
- elem->ca_node = node;
- node->elem = elem;
-
- if (dbf->cache_size != GDBM_CACHE_AUTO
- && dbf->cache_num > dbf->cache_size
- && cache_lru_free (dbf))
+ rc = cache_found;
+ }
+ else if ((elem = cache_elem_new (dbf, adr)) == NULL)
+ return cache_failure;
+ else
+ {
+ rc = cache_new;
+
+ if (dbf->cache_num == dbf->cache_size)
{
- cache_elem_free (dbf, elem);
- return node_failure;
+ if (dbf->cache_auto && dbf->cache_bits < dbf->header->dir_bits &&
+ cache_tab_resize (dbf, dbf->cache_bits + 1) == 0)
+ {
+ /* Table has been reallocated, recompute the slot. */
+ elp = cache_tab_lookup_slot (dbf, adr);
+ }
+ else if (cache_lru_free (dbf))
+ {
+ rc = cache_failure;
+ }
}
- break;
- case node_failure:
- if (!retrying)
+ if (rc == cache_new)
{
- if (errno == ENOMEM)
- {
- /* Release the last recently used element and retry. */
- if (cache_lru_free (dbf))
- return node_failure;
- retrying = 1;
- goto retry;
- }
+ *elp = elem;
+ dbf->cache_num++;
}
- return node_failure;
-
- default:
- abort ();
}
+
+ /*
+ * If the obtained bucket is not changed and is going to become current,
+ * flush all changed cache elements. This ensures that changed cache
+ * elements form a contiguous sequence at the head of the cache list (see
+ * _gdbm_cache_flush).
+ */
+ if (ref == NULL && !elem->ca_changed)
+ _gdbm_cache_flush (dbf);
lru_link_elem (dbf, elem, ref);
- *ret_elem = elem;
+ if (rc != cache_failure)
+ *ret_elem = elem;
return rc;
}
-/* Find a bucket for DBF that is pointed to by the bucket directory from
- location DIR_INDEX. The bucket cache is first checked to see if it
- is already in memory. If not, a bucket may be tossed to read the new
- bucket. On success, the requested bucket becomes the "current" bucket
- and dbf->bucket points to the correct bucket. On error, the current
- bucket remains unchanged. */
-
+/*
+ * Find a bucket for DBF that is pointed to by the bucket directory from
+ * location DIR_INDEX. The bucket cache is first checked to see if it
+ * is already in memory. If not, the last recently used bucket may be
+ * tossed (if the cache is full) to read the new bucket.
+ *
+ * On success, the cached entry with the requested bucket is placed at
+ * the head of the cache list (cache_mru) and the requested bucket becomes
+ * "current".
+ *
+ * On error, the current bucket remains unchanged.
+ */
int
_gdbm_get_bucket (GDBM_FILE dbf, int dir_index)
{
@@ -249,15 +384,12 @@ _gdbm_get_bucket (GDBM_FILE dbf, int dir_index)
dbf->bucket_dir = dir_index;
bucket_adr = dbf->dir[dir_index];
- if (dbf->cache_entry && dbf->cache_entry->ca_adr == bucket_adr)
- return 0;
-
switch (cache_lookup (dbf, bucket_adr, NULL, &elem))
{
- case node_found:
+ case cache_found:
break;
- case node_new:
+ case cache_new:
/* Position the file pointer */
file_pos = gdbm_file_seek (dbf, bucket_adr, SEEK_SET);
if (file_pos != bucket_adr)
@@ -306,10 +438,9 @@ _gdbm_get_bucket (GDBM_FILE dbf, int dir_index)
break;
- case node_failure:
+ case cache_failure:
return -1;
}
- set_cache_entry (dbf, elem);
return 0;
}
@@ -343,14 +474,22 @@ _gdbm_split_bucket (GDBM_FILE dbf, int next_insert)
off_t dir_end;
new_bits = dbf->bucket->bucket_bits + 1;
- /* Allocate two new buckets */
+
+ /*
+ * Allocate two new buckets. They will be populated with the entries
+ * from the current bucket (cache_mru->bucket), so make sure that
+ * cache_mru remains unchanged until both buckets are fully formed.
+ * Newly allocated buckets must be linked right after cache_mru, so
+ * that all changed buckets form a contiguous sequence at the beginning
+ * of the cache list (this is needed by _gdbm_cache_flush).
+ */
adr_0 = _gdbm_alloc (dbf, dbf->header->bucket_size);
switch (cache_lookup (dbf, adr_0, dbf->cache_mru, &newcache[0]))
{
- case node_new:
+ case cache_new:
break;
- case node_found:
+ case cache_found:
/* should not happen */
GDBM_DEBUG (GDBM_DEBUG_ERR,
"%s: bucket found where it should not",
@@ -358,7 +497,7 @@ _gdbm_split_bucket (GDBM_FILE dbf, int next_insert)
GDBM_SET_ERRNO (dbf, GDBM_BUCKET_CACHE_CORRUPTED, TRUE);
return -1;
- case node_failure:
+ case cache_failure:
return -1;
}
_gdbm_new_bucket (dbf, newcache[0]->ca_bucket, new_bits);
@@ -366,10 +505,10 @@ _gdbm_split_bucket (GDBM_FILE dbf, int next_insert)
adr_1 = _gdbm_alloc (dbf, dbf->header->bucket_size);
switch (cache_lookup (dbf, adr_1, newcache[0], &newcache[1]))
{
- case node_new:
+ case cache_new:
break;
- case node_found:
+ case cache_found:
/* should not happen */
GDBM_DEBUG (GDBM_DEBUG_ERR,
"%s: bucket found where it should not",
@@ -377,7 +516,7 @@ _gdbm_split_bucket (GDBM_FILE dbf, int next_insert)
GDBM_SET_ERRNO (dbf, GDBM_BUCKET_CACHE_CORRUPTED, TRUE);
return -1;
- case node_failure:
+ case cache_failure:
return -1;
}
_gdbm_new_bucket (dbf, newcache[1]->ca_bucket, new_bits);
@@ -484,17 +623,15 @@ _gdbm_split_bucket (GDBM_FILE dbf, int next_insert)
/* Set changed flags. */
newcache[0]->ca_changed = TRUE;
newcache[1]->ca_changed = TRUE;
- dbf->bucket_changed = TRUE;
dbf->directory_changed = TRUE;
- dbf->second_changed = TRUE;
/* Update the cache! */
dbf->bucket_dir = _gdbm_bucket_dir (dbf, next_insert);
/* Invalidate old cache entry. */
- old_bucket.av_adr = dbf->cache_entry->ca_adr;
+ old_bucket.av_adr = dbf->cache_mru->ca_adr;
old_bucket.av_size = dbf->header->bucket_size;
- cache_elem_free (dbf, dbf->cache_entry);
+ cache_elem_free (dbf, dbf->cache_mru);
/* Set dbf->bucket to the proper bucket. */
if (dbf->dir[dbf->bucket_dir] != adr_0)
@@ -508,9 +645,9 @@ _gdbm_split_bucket (GDBM_FILE dbf, int next_insert)
newcache[1]->ca_bucket->bucket_avail,
&newcache[1]->ca_bucket->av_count,
dbf->coalesce_blocks);
+
lru_unlink_elem (dbf, newcache[0]);
lru_link_elem (dbf, newcache[0], NULL);
- set_cache_entry (dbf, newcache[0]);
}
/* Get rid of old directories. */
@@ -554,33 +691,36 @@ _gdbm_write_bucket (GDBM_FILE dbf, cache_elem *ca_entry)
return 0;
}
-/* Cache manipulation functions. */
+/* Cache manipulation interface functions. */
+
+#define INIT_CACHE_BITS 9
/* Initialize the bucket cache. */
int
_gdbm_cache_init (GDBM_FILE dbf, size_t size)
{
- if (size == dbf->cache_size)
- return 0;
-
- if (size != GDBM_CACHE_AUTO)
+ int bits;
+ int cache_auto;
+
+ if (size == GDBM_CACHE_AUTO)
{
- while (size < dbf->cache_num)
- {
- /* Flush the least recently used element */
- cache_elem *elem = dbf->cache_lru;
- if (elem->ca_changed)
- {
- if (_gdbm_write_bucket (dbf, elem))
- return -1;
- }
- cache_elem_free (dbf, elem);
- }
+ cache_auto = TRUE;
+ bits = dbf->cache ? dbf->cache_bits : INIT_CACHE_BITS;
+ }
+ else if (size > SIZE_T_MAX / sizeof (dbf->cache[0]))
+ {
+ GDBM_SET_ERRNO (dbf, GDBM_OPT_BADVAL, FALSE);
+ return -1;
+ }
+ else
+ {
+ cache_auto = FALSE;
+ bits = log2i (size < 4 ? 4 : size);
}
-
- dbf->cache_size = size;
- return 0;
+ dbf->cache_auto = cache_auto;
+
+ return cache_tab_resize (dbf, bits);
}
/* Free the bucket cache */
@@ -591,7 +731,8 @@ _gdbm_cache_free (GDBM_FILE dbf)
while (dbf->cache_lru)
cache_elem_free (dbf, dbf->cache_lru);
- _gdbm_cache_tree_destroy (dbf->cache_tree);
+ free (dbf->cache);
+ dbf->cache = NULL;
while ((elem = dbf->cache_avail) != NULL)
{
dbf->cache_avail = elem->ca_next;
@@ -600,84 +741,23 @@ _gdbm_cache_free (GDBM_FILE dbf)
}
}
-/* Flush cache content to disk. */
+/*
+ * Flush cache content to disk.
+ * All cache elements with the changed buckets form a contiguous sequence
+ * at the head of the cache list (starting with cache_mru).
+ */
int
_gdbm_cache_flush (GDBM_FILE dbf)
{
cache_elem *elem;
- for (elem = dbf->cache_lru; elem; elem = elem->ca_prev)
+ for (elem = dbf->cache_mru; elem && elem->ca_changed; elem = elem->ca_next)
{
- if (elem->ca_changed)
- {
- if (_gdbm_write_bucket (dbf, elem))
- return -1;
- }
+ if (_gdbm_write_bucket (dbf, elem))
+ return -1;
}
return 0;
}
-
-int
-_gdbm_fetch_data (GDBM_FILE dbf, off_t off, size_t size, void *buf)
-{
- off_t bucket_adr;
- off_t file_pos;
- int rc;
- cache_elem *elem;
- char *dst = buf;
- bucket_adr = (off / dbf->header->bucket_size)
- * dbf->header->bucket_size;
- off -= bucket_adr;
- while (size)
- {
- size_t nbytes;
-
- switch (cache_lookup (dbf, bucket_adr, dbf->cache_mru, &elem))
- {
- case node_found:
- break;
-
- case node_new:
- /* Position the file pointer */
- file_pos = gdbm_file_seek (dbf, bucket_adr, SEEK_SET);
- if (file_pos != bucket_adr)
- {
- GDBM_SET_ERRNO (dbf, GDBM_FILE_SEEK_ERROR, TRUE);
- cache_elem_free (dbf, elem);
- _gdbm_fatal (dbf, _("lseek error"));
- return -1;
- }
-
- /* Read the bucket. */
- rc = _gdbm_full_read (dbf, elem->ca_bucket,
- dbf->header->bucket_size);
- if (rc)
- {
- GDBM_DEBUG (GDBM_DEBUG_ERR,
- "%s: error reading data bucket: %s",
- dbf->name, gdbm_db_strerror (dbf));
- dbf->need_recovery = TRUE;
- cache_elem_free (dbf, elem);
- _gdbm_fatal (dbf, gdbm_db_strerror (dbf));
- return -1;
- }
- break;
-
- case node_failure:
- return -1;
- }
-
- nbytes = dbf->header->bucket_size - off;
- if (nbytes > size)
- nbytes = size;
- memcpy (dst, (char*) elem->ca_bucket + off, nbytes);
- dst += nbytes;
- size -= nbytes;
- bucket_adr++;
- off = 0;
- }
- return 0;
-}
void
gdbm_get_cache_stats (GDBM_FILE dbf,
diff --git a/src/cachetree.c b/src/cachetree.c
deleted file mode 100644
index de5a5c1..0000000
--- a/src/cachetree.c
+++ /dev/null
@@ -1,484 +0,0 @@
-/* cachetree.c - Implementation of the red-black tree for cache lookups. */
-
-/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2019-2021 Free Software Foundation, Inc.
-
- GDBM is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
-
- GDBM 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
-
-#include "autoconf.h"
-#include "gdbmdefs.h"
-
-enum cache_node_color { RED, BLACK };
-
-struct cache_tree
-{
- cache_node *root; /* Root of the tree */
- cache_node *avail; /* List of available nodes, linked by parent field */
-};
-
-/* Allocate and return a new node. Pick the head item from the avail
- list and update the avail pointer. If the list is empty, malloc
- a new node.
- All members in the returned node are filled with 0.
-*/
-static cache_node *
-rbt_node_alloc (cache_tree *tree)
-{
- cache_node *n;
-
- n = tree->avail;
- if (n)
- tree->avail = n->parent;
- else
- {
- n = malloc (sizeof (*n));
- if (!n)
- return NULL;
- }
- memset (n, 0, sizeof (*n));
- return n;
-}
-
-/* Return the node N to the avail list in TREE. */
-static void
-rbt_node_dealloc (cache_tree *tree, cache_node *n)
-{
- n->parent = tree->avail;
- tree->avail = n;
-}
-
-/* Red-black tree properties:
- 1. Each node is either red or black.
- 2. The root node is black.
- 3. All leaves are black and contain no data.
- 4. Every red node has two children, and both are black.
- IOW, the parent of every red node is black.
- 5. All paths from any given node to its leaf nodes contain the same
- number of black nodes.
- */
-
-/* Auxiliary functions for accessing nodes. */
-
-/* Return the grandparent node of N.
- Prerequisite: N may not be root.
-*/
-static inline cache_node *
-grandparent (cache_node *n)
-{
- return n->parent->parent;
-}
-
-/* Return the sibling node of N.
- Prerequisite: N may not be root.
-*/
-static inline cache_node *
-sibling (cache_node *n)
-{
- return (n == n->parent->left) ? n->parent->right : n->parent->left;
-}
-
-/* Return the uncle node of N.
- Prerequisite: N must be at least 2 nodes away from root.
-*/
-static inline cache_node *
-uncle (cache_node *n)
-{
- return sibling (n->parent);
-}
-
-/* Returns the color of the node N.
- Empty leaves are represented by NULL, therefore NULL is assumed to
- be black (see property 3).
-*/
-static inline enum cache_node_color
-node_color (cache_node *n)
-{
- return n == NULL ? BLACK : n->color;
-}
-
-/* Replace the OLDN with NEWN.
- Does not modify OLDN. */
-static inline void
-replace_node (cache_tree *tree, cache_node *oldn, cache_node *newn)
-{
- if (oldn->parent == NULL)
- tree->root = newn;
- else if (oldn == oldn->parent->left)
- oldn->parent->left = newn;
- else
- oldn->parent->right = newn;
-
- if (newn != NULL)
- newn->parent = oldn->parent;
-}
-
-/* Rotate the TREE left over the node N. */
-static inline void
-rotate_left (cache_tree *tree, cache_node *n)
-{
- cache_node *right = n->right;
- replace_node (tree, n, right);
- n->right = right->left;
- if (right->left != NULL)
- right->left->parent = n;
- right->left = n;
- n->parent = right;
-}
-
-/* Rotate the TREE right over the node N. */
-static inline void
-rotate_right (cache_tree *tree, cache_node *n)
-{
- cache_node *left = n->left;
- replace_node (tree, n, left);
- n->left = left->right;
- if (left->right != NULL)
- left->right->parent = n;
- left->right = n;
- n->parent = left;
-}
-
-/* Node deletion */
-static inline void
-rbt_delete_fixup (cache_tree *tree, cache_node *n)
-{
- while (1)
- {
- if (n->parent == NULL)
- {
- /* If N has become the root node, deletion resulted in removing
- one black node (prior root) from every path, so all properties
- still hold.
- */
- return;
- }
- else
- {
- /* If N has a red sibling, change the colors of the parent and
- sibling and rotate about the parent. Thus, the sibling becomes
- grandparent and we can proceed to the next case.
- */
- if (node_color (sibling (n)) == RED)
- {
- n->parent->color = RED;
- sibling (n)->color = BLACK;
- if (n == n->parent->left)
- rotate_left (tree, n->parent);
- else
- rotate_right (tree, n->parent);
- }
-
- /* If the parent, sibling and nephews are all black, paint the
- sibling red. This means one black node was removed from all
- paths passing through the parent, so we recurse to the beginning
- of the loop with parent as the argument to restore the properties.
- This is the only branch that loops.
- */
- if (node_color (n->parent) == BLACK
- && node_color (sibling (n)) == BLACK
- && node_color (sibling (n)->left) == BLACK
- && node_color (sibling (n)->right) == BLACK)
- {
- sibling (n)->color = RED;
- n = n->parent;
- continue;
- }
- else
- {
- /* If the sibling and nephews are black but the parent is red,
- swap the colors of the sibling and parent. The properties
- are then restored.
- */
- if (node_color (n->parent) == RED
- && node_color (sibling (n)) == BLACK
- && node_color (sibling (n)->left) == BLACK
- && node_color (sibling (n)->right) == BLACK)
- {
- sibling (n)->color = RED;
- n->parent->color = BLACK;
- }
- else
- {
- /* N is the left child of its parent, its sibling is black,
- and the sibling's right child is black. Swap the colors
- of the sibling and its left sibling and rotate right
- over the sibling.
- */
- if (n == n->parent->left
- && node_color (sibling (n)) == BLACK
- && node_color (sibling (n)->left) == RED
- && node_color (sibling (n)->right) == BLACK)
- {
- sibling (n)->color = RED;
- sibling (n)->left->color = BLACK;
- rotate_right (tree, sibling (n));
- }
- else if (n == n->parent->right
- && node_color (sibling (n)) == BLACK
- && node_color (sibling (n)->right) == RED
- && node_color (sibling (n)->left) == BLACK)
- {
- /* The mirror case is handled similarly. */
- sibling (n)->color = RED;
- sibling (n)->right->color = BLACK;
- rotate_left (tree, sibling (n));
- }
- /* N is the left child of its parent, its sibling is black
- and the sibling's right child is red. Swap the colors
- of the parent and sibling, paint the sibling's right
- child black and rotate left at the parent. Similarly
- for the mirror case. This achieves the following:
-
- . A black node is added to all paths passing through N;
- . A black node is removed from all paths through the
- sibling's red child.
- . The latter is painted black which restores missing
- black node in all paths through the sibling's red child.
-
- Another sibling's child becomes a child of N's parent
- during the rotation and is therefore not affected.
- */
- sibling (n)->color = node_color (n->parent);
- n->parent->color = BLACK;
- if (n == n->parent->left)
- {
- sibling (n)->right->color = BLACK;
- rotate_left (tree, n->parent);
- }
- else
- {
- sibling (n)->left->color = BLACK;
- rotate_right (tree, n->parent);
- }
- }
- }
- }
- break;
- }
-}
-
-/* Remove N from the TREE. */
-void
-_gdbm_cache_tree_delete (cache_tree *tree, cache_node *n)
-{
- cache_node *child;
-
- /* If N has both left and right children, reduce the problem to
- the node with only one child. To do so, find the in-order
- predecessor of N, copy its value (elem) to N and then delete
- the predecessor. */
- if (n->left != NULL && n->right != NULL)
- {
- cache_node *p;
- for (p = n->left; p->right; p = p->right)
- ;
- n->adr = p->adr;
- n->elem = p->elem;
- n->elem->ca_node = n;
- n = p;
- }
-
- /* N has only one child. Select it. */
- child = n->left ? n->left : n->right;
- if (node_color (n) == BLACK)
- {
- n->color = node_color (child);
- rbt_delete_fixup (tree, n);
- }
- replace_node (tree, n, child);
- if (n->parent == NULL && child != NULL) /* root should be black */
- child->color = BLACK;
-
- /* Return N to the avail pool */
- rbt_node_dealloc (tree, n);
-}
-
-/* Insertion */
-static inline void
-rbt_insert_fixup (cache_tree *tree, cache_node *n)
-{
- while (1)
- {
- if (n->parent == NULL)
- {
- /* Node was inserted at the root of the tree.
- The root node must be black (property 2). Changing its color
- to black would add one black node to every path, which means
- the property 5 would remain satisfied. So we simply paint the
- node black.
- */
- n->color = BLACK;
- }
- else if (node_color (n->parent) == BLACK)
- {
- /* The node has black parent.
- All properties are satisfied. There's no need to change anything.
- */
- return;
- }
- else if (node_color (uncle (n)) == RED)
- {
- /* The uncle node is red.
- Repaint the parent and uncle black and the grandparent red. This
- would satisfy 4. However, if the grandparent is root, this would
- violate the property 2. So we repaint the grandparent by
- re-entering the fixup loop with grandparent as the node.
- This is the only branch that loops.
- */
- n->parent->color = BLACK;
- uncle (n)->color = BLACK;
- n = grandparent (n);
- n->color = RED;
- continue;
- }
- else
- {
- /* The new node is the right child of its parent and the parent is
- the left child of the grandparent. Rotate left about the parent.
- Mirror case: The new node is the left child of its parent and the
- parent is the right child of the grandparent. Rotate right about
- the parent. This fixes the properties for the rbt_insert_5.
- */
- if (n == n->parent->right && n->parent == grandparent (n)->left)
- {
- rotate_left (tree, n->parent);
- n = n->left;
- }
- else if (n == n->parent->left && n->parent == grandparent (n)->right)
- {
- rotate_right (tree, n->parent);
- n = n->right;
- }
-
- /* The new node is the left child of its parent and the parent is the
- left child of the grandparent. Rotate right about the grandparent.
- Mirror case: The new node is the right child of its parent and the
- parent
- is the right child of the grandparent. Rotate left.
- */
- n->parent->color = BLACK;
- grandparent (n)->color = RED;
- if (n == n->parent->left && n->parent == grandparent (n)->left)
- {
- rotate_right (tree, grandparent (n));
- }
- else
- {
- rotate_left (tree, grandparent (n));
- }
- }
- break;
- }
-}
-
-/* Look up the node with the given ADR.
- If found, put it in *RETVAL and return node_found.
-
- Otherwise, create a new node and insert it at the appropriate place in
- the tree. Store the address of the newly created node in *RETVAL and
- return node_new.
-
- If a new node cannot be created (memory exhausted), return node_failure.
-*/
-int
-_gdbm_cache_tree_lookup (cache_tree *tree, off_t adr, cache_node **retval)
-{
- int res;
- cache_node *node, *parent = NULL;
-
- node = tree->root;
- while (node)
- {
- if (adr == node->adr)
- break;
- parent = node;
- if (adr < node->adr)
- node = node->left;
- else
- node = node->right;
- }
-
- if (node)
- {
- res = node_found;
- }
- else
- {
- node = rbt_node_alloc (tree);
- if (!node)
- return node_failure;
- if (!parent)
- tree->root = node;
- else if (adr < parent->adr)
- parent->left = node;
- else
- parent->right = node;
- node->adr = adr;
- node->parent = parent;
- rbt_insert_fixup (tree, node);
- res = node_new;
- }
- *retval = node;
- return res;
-}
-
-/* Interface functions */
-
-/* Create a cache tree structure for the database file DBF. */
-cache_tree *
-_gdbm_cache_tree_alloc (void)
-{
- cache_tree *t = malloc (sizeof (*t));
- if (t)
- {
- t->root = NULL;
- t->avail = NULL;
- }
- return t;
-}
-
-/* Free the memory used by the TREE. */
-void
-_gdbm_cache_tree_destroy (cache_tree *tree)
-{
- cache_node *n;
-
- /* Free the allocated tree nodes. Traverse the tree as if it were
- a simple binary tree: there's no use preserving RBT properties now.
- */
- while ((n = tree->root) != NULL)
- {
- if (!n->left)
- tree->root = n->right;
- else if (!n->right)
- tree->root = n->left;
- else
- {
- cache_node *p;
- for (p = n->left; p->right; p = p->right)
- ;
- p->right = n->right;
- tree->root = n->left;
- }
- free (n);
- }
-
- /* Free the avail list */
- while ((n = tree->avail) != NULL)
- {
- tree->avail = n->parent;
- free (n);
- }
- free (tree);
-}
diff --git a/src/debug.c b/src/debug.c
index e5395fe..6fb7fd8 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright 2016-2021 Free Software Foundation, Inc.
+ Copyright 2016-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/falloc.c b/src/falloc.c
index 890ed7b..1c3115b 100644
--- a/src/falloc.c
+++ b/src/falloc.c
@@ -1,7 +1,7 @@
/* falloc.c - The file space management routines for dbm. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -108,7 +108,7 @@ _gdbm_alloc (GDBM_FILE dbf, int num_bytes)
}
/* Free space of size NUM_BYTES in the file DBF at file address FILE_ADR. Make
- it avaliable for reuse through _gdbm_alloc. This routine changes the
+ it available for reuse through _gdbm_alloc. This routine changes the
avail structure. */
int
@@ -515,7 +515,7 @@ adjust_bucket_avail (GDBM_FILE dbf)
av_el = dbf->avail->av_table[dbf->avail->count];
_gdbm_put_av_elem (av_el, dbf->bucket->bucket_avail,
&dbf->bucket->av_count, dbf->coalesce_blocks);
- dbf->bucket_changed = TRUE;
+ _gdbm_current_bucket_changed (dbf);
}
return 0;
}
@@ -533,7 +533,7 @@ adjust_bucket_avail (GDBM_FILE dbf)
_gdbm_put_av_elem (av_el, dbf->avail->av_table,
&dbf->avail->count,
dbf->coalesce_blocks);
- dbf->bucket_changed = TRUE;
+ _gdbm_current_bucket_changed (dbf);
}
return 0;
}
diff --git a/src/findkey.c b/src/findkey.c
index ac777ed..de8cbbf 100644
--- a/src/findkey.c
+++ b/src/findkey.c
@@ -1,7 +1,7 @@
/* findkey.c - The routine that finds a key entry in the file. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -67,8 +67,8 @@ _gdbm_read_entry (GDBM_FILE dbf, int elem_loc)
data_cache_elem *data_ca;
/* Is it already in the cache? */
- if (dbf->cache_entry->ca_data.elem_loc == elem_loc)
- return dbf->cache_entry->ca_data.dptr;
+ if (dbf->cache_mru->ca_data.elem_loc == elem_loc)
+ return dbf->cache_mru->ca_data.dptr;
if (!gdbm_bucket_element_valid_p (dbf, elem_loc))
{
@@ -80,9 +80,9 @@ _gdbm_read_entry (GDBM_FILE dbf, int elem_loc)
key_size = dbf->bucket->h_table[elem_loc].key_size;
data_size = dbf->bucket->h_table[elem_loc].data_size;
dsize = key_size + data_size;
- data_ca = &dbf->cache_entry->ca_data;
+ data_ca = &dbf->cache_mru->ca_data;
- /* Make sure data_ca has sufficient space to accomodate both
+ /* Make sure data_ca has sufficient space to accommodate both
key and content. */
if (dsize <= data_ca->dsize)
{
@@ -179,17 +179,17 @@ _gdbm_findkey (GDBM_FILE dbf, datum key, char **ret_dptr, int *ret_hash_val)
return -1;
/* Is the element the last one found for this bucket? */
- if (dbf->cache_entry->ca_data.elem_loc != -1
- && new_hash_val == dbf->cache_entry->ca_data.hash_val
- && dbf->cache_entry->ca_data.key_size == key.dsize
- && dbf->cache_entry->ca_data.dptr != NULL
- && memcmp (dbf->cache_entry->ca_data.dptr, key.dptr, key.dsize) == 0)
+ if (dbf->cache_mru->ca_data.elem_loc != -1
+ && new_hash_val == dbf->cache_mru->ca_data.hash_val
+ && dbf->cache_mru->ca_data.key_size == key.dsize
+ && dbf->cache_mru->ca_data.dptr != NULL
+ && memcmp (dbf->cache_mru->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;
- return dbf->cache_entry->ca_data.elem_loc;
+ *ret_dptr = dbf->cache_mru->ca_data.dptr + key.dsize;
+ return dbf->cache_mru->ca_data.elem_loc;
}
/* It is not the cached value, search for element in the bucket. */
diff --git a/src/fullio.c b/src/fullio.c
index a15b2fd..8051883 100644
--- a/src/fullio.c
+++ b/src/fullio.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/gdbm.h.in b/src/gdbm.h.in
index 041837d..d164a81 100644
--- a/src/gdbm.h.in
+++ b/src/gdbm.h.in
@@ -1,7 +1,7 @@
/* gdbm.h - The include file for dbm users. -*- c -*- */
/* This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -64,7 +64,7 @@ extern "C" {
# define GDBM_INSERT 0 /* Never replace old data with new. */
# define GDBM_REPLACE 1 /* Always replace old data with new. */
-/* Parameters to gdbm_setopt, specifing the type of operation to perform. */
+/* Parameters to gdbm_setopt, specifying the type of operation to perform. */
# define GDBM_SETCACHESIZE 1 /* Set the cache size. */
# define GDBM_FASTMODE 2 /* Toggle fast mode. OBSOLETE. */
# define GDBM_SETSYNCMODE 3 /* Turn on or off sync operations. */
@@ -88,9 +88,16 @@ extern "C" {
# define GDBM_GETMAXMAPSIZE 14 /* Get maximum mapped memory size */
# define GDBM_GETDBNAME 15 /* Return database file name */
# define GDBM_GETBLOCKSIZE 16 /* Return block size */
-
+# define GDBM_GETDBFORMAT 17 /* Return the database format */
+# define GDBM_GETDIRDEPTH 18 /* Directory depth: number of initial (most
+ significant) bits in hash interpreted as
+ index to the directory. */
+# define GDBM_GETBUCKETSIZE 19 /* Get number of elements per bucket */
+# define GDBM_GETCACHEAUTO 20 /* Get the value of cache auto-adjustment */
+# define GDBM_SETCACHEAUTO 21 /* Set the value of cache auto-adjustment */
+
# define GDBM_CACHE_AUTO 0
-
+
typedef @GDBM_COUNT_T@ gdbm_count_t;
/* The data and key structure. */
diff --git a/src/gdbm.magic b/src/gdbm.magic
index f685481..65fcf25 100644
--- a/src/gdbm.magic
+++ b/src/gdbm.magic
@@ -1,5 +1,5 @@
# A "magic" file for file(1).
-# Copyright (C) 2016-2021 Free Software Foundation, Inc.
+# Copyright (C) 2016-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/src/gdbmclose.c b/src/gdbmclose.c
index 82bf618..5f3a757 100644
--- a/src/gdbmclose.c
+++ b/src/gdbmclose.c
@@ -1,7 +1,7 @@
/* gdbmclose.c - Close a previously opened dbm file. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/gdbmconst.h b/src/gdbmconst.h
index 29d717a..de88977 100644
--- a/src/gdbmconst.h
+++ b/src/gdbmconst.h
@@ -1,7 +1,7 @@
/* gdbmconst.h - The constants defined for use in gdbm. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/gdbmcount.c b/src/gdbmcount.c
index 3e6bb06..5e74b61 100644
--- a/src/gdbmcount.c
+++ b/src/gdbmcount.c
@@ -1,7 +1,7 @@
/* gdbmcount.c - get number of items in a gdbm file. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1993-2021 Free Software Foundation, Inc.
+ Copyright (C) 1993-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/gdbmdefs.h b/src/gdbmdefs.h
index 98f55c3..3348f9d 100644
--- a/src/gdbmdefs.h
+++ b/src/gdbmdefs.h
@@ -1,7 +1,7 @@
/* gdbmdefs.h - The include file for dbm. Defines structure and constants. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -65,7 +65,7 @@ off_t_sum_ok (off_t a, off_t b)
stack." When the active avail table is empty and the "avail stack" is
not empty, the top of the stack is popped into the active avail table. */
-/* The following structure is the element of the avaliable table. */
+/* The following structure is the element of the available table. */
typedef struct
{
int av_size; /* The size of the available block. */
@@ -179,15 +179,6 @@ typedef struct
} data_cache_elem;
typedef struct cache_elem cache_elem;
-typedef struct cache_node cache_node;
-
-struct cache_node
-{
- cache_node *left, *right, *parent;
- int color;
- off_t adr;
- cache_elem *elem;
-};
struct cache_elem
{
@@ -195,19 +186,16 @@ struct cache_elem
char ca_changed; /* Data in the bucket changed. */
data_cache_elem ca_data; /* Cached datum */
cache_elem *ca_prev, /* Previous element in LRU list. */
- *ca_next; /* Next elements in LRU list.
+ *ca_next, /* Next elements in LRU list.
If the item is in cache_avail list, only
ca_next is used. It points to the next
available element. */
+ *ca_coll; /* Next element in a collision sequence */
size_t ca_hits; /* Number of times this element was requested */
- cache_node *ca_node; /* Points back to the RBT node for this
- element. */
hash_bucket ca_bucket[1];/* Associated bucket (dbf->header->bucket_size
bytes). */
};
-typedef struct cache_tree cache_tree;
-
/* This final structure contains all main memory based information for
a gdbm file. This allows multiple gdbm files to be opened at the same
time by one program. */
@@ -243,6 +231,9 @@ struct gdbm_file_info
/* Last error was fatal, the database needs recovery */
unsigned need_recovery :1;
+ /* Automatic bucket cache size */
+ unsigned cache_auto :1;
+
/* Last GDBM error number */
gdbm_error last_error;
/* Last system error number */
@@ -275,19 +266,18 @@ struct gdbm_file_info
off_t *dir;
/* The bucket cache. */
- size_t cache_size; /* Cache capacity */
+ int cache_bits; /* Address bits used for computing bucket hash */
+ size_t cache_size; /* Cache capacity: 2^cache_bits */
size_t cache_num; /* Actual number of elements in cache */
- /* Cache elements form a binary search tree. */
- cache_tree *cache_tree;
+ /* Cache hash table. */
+ cache_elem **cache;
+
/* Cache elements are linked in a list sorted by relative access time */
cache_elem *cache_mru; /* Most recently used element - head of the list */
cache_elem *cache_lru; /* Last recently used element - tail of the list */
cache_elem *cache_avail; /* Pool of available elements (linked by prev, next)
*/
- /* Pointer to the current bucket's cache entry. */
- cache_elem *cache_entry;
-
- /* Points to the current hash bucket in the cache. */
+ /* Points to dbf->cache_mru.ca_bucket -- the current hash bucket */
hash_bucket *bucket;
/* The directory entry used to get the current hash bucket. */
@@ -301,8 +291,6 @@ struct gdbm_file_info
end of an update. */
unsigned header_changed :1;
unsigned directory_changed :1;
- unsigned bucket_changed :1;
- unsigned second_changed :1;
off_t file_size; /* Cached value of the current disk file size.
If -1, fstat will be used to retrieve it. */
diff --git a/src/gdbmdelete.c b/src/gdbmdelete.c
index 28b604e..9206658 100644
--- a/src/gdbmdelete.c
+++ b/src/gdbmdelete.c
@@ -1,7 +1,7 @@
/* gdbmdelete.c - Remove the key and its associated data from the database. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -85,12 +85,12 @@ gdbm_delete (GDBM_FILE dbf, datum key)
return -1;
/* Set the flags. */
- dbf->bucket_changed = TRUE;
+ _gdbm_current_bucket_changed (dbf);
/* Invalidate data cache for the current bucket. */
- dbf->cache_entry->ca_data.hash_val = -1;
- dbf->cache_entry->ca_data.key_size = 0;
- dbf->cache_entry->ca_data.elem_loc = -1;
+ dbf->cache_mru->ca_data.hash_val = -1;
+ dbf->cache_mru->ca_data.key_size = 0;
+ dbf->cache_mru->ca_data.elem_loc = -1;
/* Do the writes. */
return _gdbm_end_update (dbf);
diff --git a/src/gdbmdump.c b/src/gdbmdump.c
index e157dd3..7caf805 100644
--- a/src/gdbmdump.c
+++ b/src/gdbmdump.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/gdbmerrno.c b/src/gdbmerrno.c
index cfc3c1f..1bc1a6e 100644
--- a/src/gdbmerrno.c
+++ b/src/gdbmerrno.c
@@ -1,7 +1,7 @@
-/* gdbmerrno.c - convert gdbm errors into english. */
+/* gdbmerrno.c - convert gdbm errors into English. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1993-2021 Free Software Foundation, Inc.
+ Copyright (C) 1993-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/gdbmexists.c b/src/gdbmexists.c
index ea2f966..b6e1714 100644
--- a/src/gdbmexists.c
+++ b/src/gdbmexists.c
@@ -1,7 +1,7 @@
/* gdbmexists.c - Check to see if a key exists */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1993-2021 Free Software Foundation, Inc.
+ Copyright (C) 1993-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@
#include "gdbmdefs.h"
/* This is nothing more than a wrapper around _gdbm_findkey(). The
- point? It doesn't alloate any memory. */
+ point? It doesn't allocate any memory. */
int
gdbm_exists (GDBM_FILE dbf, datum key)
diff --git a/src/gdbmexp.c b/src/gdbmexp.c
index d297a35..6646bba 100644
--- a/src/gdbmexp.c
+++ b/src/gdbmexp.c
@@ -1,7 +1,7 @@
/* gdbmexp.c - Export a GDBM database. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2007-2021 Free Software Foundation, Inc.
+ Copyright (C) 2007-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/gdbmfdesc.c b/src/gdbmfdesc.c
index d86f3ce..e2a210f 100644
--- a/src/gdbmfdesc.c
+++ b/src/gdbmfdesc.c
@@ -1,7 +1,7 @@
/* gdbfdesc.c - return the file descriptor associated with the database. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1999-2021 Free Software Foundation, Inc.
+ Copyright (C) 1999-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/gdbmfetch.c b/src/gdbmfetch.c
index f567da2..b06ac3f 100644
--- a/src/gdbmfetch.c
+++ b/src/gdbmfetch.c
@@ -1,7 +1,7 @@
/* gdbmfetch.c - Find a key and return the associated data. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/gdbmimp.c b/src/gdbmimp.c
index 61bb836..be98ed7 100644
--- a/src/gdbmimp.c
+++ b/src/gdbmimp.c
@@ -1,7 +1,7 @@
/* gdbmimp.c - Import a GDBM database. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2007-2021 Free Software Foundation, Inc.
+ Copyright (C) 2007-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -42,7 +42,7 @@ gdbm_import_from_file (GDBM_FILE dbf, FILE *fp, int flag)
kbuffer = NULL;
dbuffer = NULL;
- /* Read (and discard) four lines begining with ! and ending with \n. */
+ /* Read (and discard) four lines beginning with ! and ending with \n. */
while (1)
{
if ((rret = fgetc (fp)) == -1)
diff --git a/src/gdbmload.c b/src/gdbmload.c
index 228316f..03c5263 100644
--- a/src/gdbmload.c
+++ b/src/gdbmload.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/gdbmopen.c b/src/gdbmopen.c
index 4b154be..183159c 100644
--- a/src/gdbmopen.c
+++ b/src/gdbmopen.c
@@ -1,7 +1,7 @@
/* gdbmopen.c - Open the dbm file and initialize data structures for use. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -271,10 +271,6 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
dbf->bucket = NULL;
dbf->header = NULL;
- /* Initialize cache */
- dbf->cache_tree = _gdbm_cache_tree_alloc ();
- _gdbm_cache_init (dbf, DEFAULT_CACHESIZE);
-
dbf->file_size = -1;
dbf->memory_mapping = FALSE;
@@ -640,6 +636,17 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
}
+ if (_gdbm_cache_init (dbf, DEFAULT_CACHESIZE))
+ {
+ GDBM_DEBUG (GDBM_DEBUG_ERR|GDBM_DEBUG_OPEN,
+ "%s: error initializing cache: %s",
+ dbf->name, gdbm_db_strerror (dbf));
+ if (!(flags & GDBM_CLOERROR))
+ dbf->desc = -1;
+ SAVE_ERRNO (gdbm_close (dbf));
+ return NULL;
+ }
+
#if HAVE_MMAP
if (!(flags & GDBM_NOMMAP))
{
@@ -666,8 +673,6 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
dbf->bucket_dir = 0;
dbf->header_changed = FALSE;
dbf->directory_changed = FALSE;
- dbf->bucket_changed = FALSE;
- dbf->second_changed = FALSE;
if (flags & GDBM_XVERIFY)
{
@@ -697,7 +702,7 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
not exist, create a new one. If FLAGS is GDBM_NEWDB, the user want a
new database created, regardless of whether one existed, and wants read
and write access to the new database. Any error detected will cause a
- return value of null and an approprate value will be in gdbm_errno. If
+ return value of null and an appropriate value will be in gdbm_errno. If
no errors occur, a pointer to the "gdbm file descriptor" will be
returned. */
diff --git a/src/gdbmreorg.c b/src/gdbmreorg.c
index 6199926..7be188b 100644
--- a/src/gdbmreorg.c
+++ b/src/gdbmreorg.c
@@ -1,7 +1,7 @@
/* gdbmreorg.c - Reorganize the database file. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/gdbmseq.c b/src/gdbmseq.c
index 956ba2b..52bddbd 100644
--- a/src/gdbmseq.c
+++ b/src/gdbmseq.c
@@ -1,7 +1,7 @@
/* gdbmseq.c - Routines to visit all keys. Not in sorted order. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -68,7 +68,7 @@ get_next_key (GDBM_FILE dbf, int elem_loc, datum *return_val)
/* Find the next bucket. It is possible several entries in
the bucket directory point to the same bucket. */
while (dbf->bucket_dir < GDBM_DIR_COUNT (dbf)
- && dbf->cache_entry->ca_adr == dbf->dir[dbf->bucket_dir])
+ && dbf->cache_mru->ca_adr == dbf->dir[dbf->bucket_dir])
dbf->bucket_dir++;
/* Check to see if there was a next bucket. */
diff --git a/src/gdbmsetopt.c b/src/gdbmsetopt.c
index ae66a17..068d8d1 100644
--- a/src/gdbmsetopt.c
+++ b/src/gdbmsetopt.c
@@ -1,7 +1,7 @@
/* gdbmsetopt.c - set options pertaining to a GDBM descriptor. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1993-2021 Free Software Foundation, Inc.
+ Copyright (C) 1993-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -74,6 +74,32 @@ setopt_gdbm_getcachesize (GDBM_FILE dbf, void *optval, int optlen)
return 0;
}
+static int
+setopt_gdbm_setcacheauto (GDBM_FILE dbf, void *optval, int optlen)
+{
+ int n;
+
+ if ((n = getbool (optval, optlen)) == -1)
+ {
+ GDBM_SET_ERRNO (dbf, GDBM_OPT_BADVAL, FALSE);
+ return -1;
+ }
+ dbf->cache_auto = n;
+ return 0;
+}
+
+static int
+setopt_gdbm_getcacheauto (GDBM_FILE dbf, void *optval, int optlen)
+{
+ if (!optval || optlen != sizeof (int))
+ {
+ GDBM_SET_ERRNO (dbf, GDBM_OPT_BADVAL, FALSE);
+ return -1;
+ }
+ *(int*) optval = !!dbf->cache_auto;
+ return 0;
+}
+
/* Obsolete form of GDBM_SETSYNCMODE. */
static int
setopt_gdbm_fastmode (GDBM_FILE dbf, void *optval, int optlen)
@@ -254,14 +280,24 @@ setopt_gdbm_getflags (GDBM_FILE dbf, void *optval, int optlen)
else
{
int flags = dbf->read_write;
+
if (!dbf->fast_write)
flags |= GDBM_SYNC;
+
if (!dbf->file_locking)
flags |= GDBM_NOLOCK;
+
if (!dbf->memory_mapping)
flags |= GDBM_NOMMAP;
else if (dbf->mmap_preread)
flags |= GDBM_PREREAD;
+
+ if (dbf->cloexec)
+ flags |= GDBM_CLOEXEC;
+
+ if (dbf->header->header_magic == GDBM_NUMSYNC_MAGIC)
+ flags |= GDBM_NUMSYNC;
+
*(int*) optval = flags;
}
return 0;
@@ -300,6 +336,54 @@ setopt_gdbm_getblocksize (GDBM_FILE dbf, void *optval, int optlen)
GDBM_SET_ERRNO (dbf, GDBM_OPT_BADVAL, FALSE);
return -1;
}
+
+static int
+setopt_gdbm_getdbformat (GDBM_FILE dbf, void *optval, int optlen)
+{
+ if (optval && optlen == sizeof (int))
+ {
+ switch (dbf->header->header_magic)
+ {
+ case GDBM_OMAGIC:
+ case GDBM_MAGIC:
+ *(int*)optval = 0;
+ break;
+
+ case GDBM_NUMSYNC_MAGIC:
+ *(int*)optval = GDBM_NUMSYNC;
+ }
+ return 0;
+ }
+
+ GDBM_SET_ERRNO (dbf, GDBM_OPT_BADVAL, FALSE);
+ return -1;
+}
+
+static int
+setopt_gdbm_getdirdepth (GDBM_FILE dbf, void *optval, int optlen)
+{
+ if (optval && optlen == sizeof (int))
+ {
+ *(int*) optval = dbf->header->dir_bits;
+ return 0;
+ }
+
+ GDBM_SET_ERRNO (dbf, GDBM_OPT_BADVAL, FALSE);
+ return -1;
+}
+
+static int
+setopt_gdbm_getbucketsize (GDBM_FILE dbf, void *optval, int optlen)
+{
+ if (optval && optlen == sizeof (int))
+ {
+ *(int*) optval = dbf->header->bucket_elems;
+ return 0;
+ }
+
+ GDBM_SET_ERRNO (dbf, GDBM_OPT_BADVAL, FALSE);
+ return -1;
+}
typedef int (*setopt_handler) (GDBM_FILE, void *, int);
@@ -322,6 +406,11 @@ static setopt_handler setopt_handler_tab[] = {
[GDBM_GETFLAGS] = setopt_gdbm_getflags,
[GDBM_GETDBNAME] = setopt_gdbm_getdbname,
[GDBM_GETBLOCKSIZE] = setopt_gdbm_getblocksize,
+ [GDBM_GETDBFORMAT] = setopt_gdbm_getdbformat,
+ [GDBM_GETDIRDEPTH] = setopt_gdbm_getdirdepth,
+ [GDBM_GETBUCKETSIZE] = setopt_gdbm_getbucketsize,
+ [GDBM_GETCACHEAUTO] = setopt_gdbm_getcacheauto,
+ [GDBM_SETCACHEAUTO] = setopt_gdbm_setcacheauto,
};
int
diff --git a/src/gdbmstore.c b/src/gdbmstore.c
index 21c0913..7491ffc 100644
--- a/src/gdbmstore.c
+++ b/src/gdbmstore.c
@@ -1,7 +1,7 @@
/* gdbmstore.c - Add a new key/data pair to the database. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -190,8 +190,7 @@ gdbm_store (GDBM_FILE dbf, datum key, datum content, int flags)
}
/* Current bucket has changed. */
- dbf->cache_entry->ca_changed = TRUE;
- dbf->bucket_changed = TRUE;
+ _gdbm_current_bucket_changed (dbf);
/* Write everything that is needed to the disk. */
return _gdbm_end_update (dbf);
diff --git a/src/gdbmsync.c b/src/gdbmsync.c
index ed20ef7..f035cb1 100644
--- a/src/gdbmsync.c
+++ b/src/gdbmsync.c
@@ -1,7 +1,7 @@
/* gdbmsync.c - Sync the disk with the in memory state. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/gettext.h b/src/gettext.h
index 28c181f..d705fd5 100644
--- a/src/gettext.h
+++ b/src/gettext.h
@@ -1,5 +1,5 @@
/* Convenience header for conditional use of GNU <libintl.h>.
- Copyright (C) 1995-2021 Free Software Foundation, Inc.
+ Copyright (C) 1995-2022 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published
diff --git a/src/hash.c b/src/hash.c
index 97402f7..99c9636 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -1,7 +1,7 @@
/* hash.c - The gdbm hash function. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/lock.c b/src/lock.c
index 23711aa..423d130 100644
--- a/src/lock.c
+++ b/src/lock.c
@@ -1,7 +1,7 @@
/* lock.c - Implement basic file locking for GDBM. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2008-2021 Free Software Foundation, Inc.
+ Copyright (C) 2008-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/mmap.c b/src/mmap.c
index 778cf46..59f79e5 100644
--- a/src/mmap.c
+++ b/src/mmap.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM.
- Copyright (C) 2007-2021 Free Software Foundation, Inc.
+ Copyright (C) 2007-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -42,7 +42,7 @@
/* Translate current offset in the mapped region into the absolute position */
# define _GDBM_MMAPPED_POS(dbf) ((dbf)->mapped_off + (dbf)->mapped_pos)
-/* Return true if the absolute offset OFF lies within the currentlty mmapped
+/* Return true if the absolute offset OFF lies within the currently mmapped
region */
# define _GDBM_IN_MAPPED_REGION_P(dbf, off) \
((off) >= (dbf)->mapped_off \
@@ -127,7 +127,7 @@ _gdbm_internal_remap (GDBM_FILE dbf, size_t size)
If the file is opened with write permissions, FLAG controls how
it is expanded. The value _REMAP_DEFAULT truncates SIZE to the
actual file size. The value _REMAP_EXTEND extends the file, if
- necessary, to accomodate max(SIZE,dbf->header->next_block) bytes.
+ necessary, to accommodate max(SIZE,dbf->header->next_block) bytes.
Finally, the value _REMAP_END instructs the function to use
max(SIZE, file_size) as the upper bound of the mapped region.
diff --git a/src/proto.h b/src/proto.h
index a5d6d10..40a396a 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -1,7 +1,7 @@
/* proto.h - The prototypes for the dbm routines. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +20,6 @@
/* From bucket.c */
void _gdbm_new_bucket (GDBM_FILE, hash_bucket *, int);
int _gdbm_get_bucket (GDBM_FILE, int);
-int _gdbm_fetch_data (GDBM_FILE dbf, off_t off, size_t size, void *buf);
int _gdbm_split_bucket (GDBM_FILE, int);
int _gdbm_write_bucket (GDBM_FILE, cache_elem *);
@@ -28,6 +27,13 @@ int _gdbm_cache_init (GDBM_FILE, size_t);
void _gdbm_cache_free (GDBM_FILE dbf);
int _gdbm_cache_flush (GDBM_FILE dbf);
+/* Mark current bucket as changed. */
+static inline void
+_gdbm_current_bucket_changed (GDBM_FILE dbf)
+{
+ dbf->cache_mru->ca_changed = TRUE;
+}
+
/* Return true if the directory entry at DIR_INDEX can be considered
valid. This means that DIR_INDEX is in the valid range for addressing
the dir array, and the offset stored in dir[DIR_INDEX] points past
@@ -103,10 +109,6 @@ int _gdbm_dump (GDBM_FILE dbf, FILE *fp);
/* From recover.c */
int _gdbm_next_bucket_dir (GDBM_FILE dbf, int bucket_dir);
-/* cachetree.c */
-cache_tree *_gdbm_cache_tree_alloc (void);
-void _gdbm_cache_tree_destroy (cache_tree *tree);
-void _gdbm_cache_tree_delete (cache_tree *tree, struct cache_node *n);
/* avail.c */
int gdbm_avail_block_validate (GDBM_FILE dbf, avail_block *avblk, size_t size);
@@ -116,16 +118,6 @@ int gdbm_avail_traverse (GDBM_FILE dbf,
void *data);
-/* Return codes for _gdbm_cache_tree_lookup. */
-enum
- {
- node_found, /* Returned element was found in cache. */
- node_new, /* Returned element has been created and inserted to cache */
- node_failure /* An error occurred. */
- };
-
-int _gdbm_cache_tree_lookup (cache_tree *tree, off_t adr, cache_node **retval);
-
/* I/O functions */
static inline ssize_t
gdbm_file_read (GDBM_FILE dbf, void *buf, size_t size)
diff --git a/src/recover.c b/src/recover.c
index af775ad..9ef43d1 100644
--- a/src/recover.c
+++ b/src/recover.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2016-2021 Free Software Foundation, Inc.
+ Copyright (C) 2016-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -126,6 +126,10 @@ _gdbm_finish_transfer (GDBM_FILE dbf, GDBM_FILE new_dbf,
}
rcvr->backup_name = bkname;
}
+
+ /* Restore cache settings */
+ if (!dbf->cache_auto)
+ _gdbm_cache_init (new_dbf, dbf->cache_size);
/* Move the new file to old name. */
@@ -157,18 +161,16 @@ _gdbm_finish_transfer (GDBM_FILE dbf, GDBM_FILE new_dbf,
dbf->avail_size = new_dbf->avail_size;
dbf->xheader = new_dbf->xheader;
+ dbf->cache_bits = new_dbf->cache_bits;
dbf->cache_size = new_dbf->cache_size;
dbf->cache_num = new_dbf->cache_num;
- dbf->cache_tree = new_dbf->cache_tree;
+ dbf->cache = new_dbf->cache;
dbf->cache_mru = new_dbf->cache_mru;
dbf->cache_lru = new_dbf->cache_lru;
dbf->cache_avail = new_dbf->cache_avail;
- dbf->cache_entry = new_dbf->cache_entry;
dbf->header_changed = new_dbf->header_changed;
dbf->directory_changed = new_dbf->directory_changed;
- dbf->bucket_changed = new_dbf->bucket_changed;
- dbf->second_changed = new_dbf->second_changed;
dbf->file_size = -1;
@@ -184,7 +186,7 @@ _gdbm_finish_transfer (GDBM_FILE dbf, GDBM_FILE new_dbf,
/* Make sure the new database is all on disk. */
gdbm_file_sync (dbf);
-
+
/* Force the right stuff for a correct bucket cache. */
return _gdbm_get_bucket (dbf, 0);
}
diff --git a/src/systems.h b/src/systems.h
index d96f21f..dd2ce1c 100644
--- a/src/systems.h
+++ b/src/systems.h
@@ -1,7 +1,7 @@
-/* systems.h - Most of the system dependant code and defines are here. */
+/* systems.h - Most of the system dependent code and defines are here. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/update.c b/src/update.c
index b7d28f9..2faa116 100644
--- a/src/update.c
+++ b/src/update.c
@@ -1,7 +1,7 @@
/* update.c - The routines for updating the file to a consistent state. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -63,20 +63,8 @@ _gdbm_end_update (GDBM_FILE dbf)
off_t file_pos; /* Return value for lseek. */
int rc;
- /* Write the current bucket. */
- if (dbf->bucket_changed && (dbf->cache_entry != NULL))
- {
- if (_gdbm_write_bucket (dbf, dbf->cache_entry))
- return -1;
- dbf->bucket_changed = FALSE;
- }
-
- /* Write the other changed buckets if there are any. */
- if (dbf->second_changed)
- {
- _gdbm_cache_flush (dbf);
- dbf->second_changed = FALSE;
- }
+ /* Write the changed buckets if there are any. */
+ _gdbm_cache_flush (dbf);
/* Write the directory. */
if (dbf->directory_changed)
diff --git a/src/version.c b/src/version.c
index ff0790e..d6e7f33 100644
--- a/src/version.c
+++ b/src/version.c
@@ -1,7 +1,7 @@
/* version.c - This is file contains the version number for gdbm source. */
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/tests/.gitignore b/tests/.gitignore
index 558b2ee..f424120 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -5,6 +5,7 @@ Makefile
Makefile.in
atconfig
atlocal
+closerr
d_creat_ce
dtdel
dtdump
@@ -13,6 +14,7 @@ dtload
fdop
g_open_ce
g_reorg_ce
+gtcacheopt
gtconv
gtdel
gtdump
@@ -29,3 +31,4 @@ testsuite.dir
*.sum
*.bak
site.exp
+t_wordwrap
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 337cbed..fac6826 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -77,7 +77,9 @@ TESTSUITE_AT = \
fetch01.at\
setopt00.at\
setopt01.at\
- version.at
+ setopt02.at\
+ version.at\
+ wordwrap.at
TESTSUITE = $(srcdir)/testsuite
M4=m4
@@ -114,6 +116,7 @@ check_PROGRAMS = \
fdop\
g_open_ce\
g_reorg_ce\
+ gtcacheopt\
gtconv\
gtdel\
gtdump\
@@ -123,9 +126,10 @@ check_PROGRAMS = \
gtrecover\
gtver\
num2word\
+ t_wordwrap\
$(DBMPROGS)
-AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src $(DBMINCLUDES)
+AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src -I$(top_srcdir)/tools $(DBMINCLUDES)
noinst_HEADERS=progname.h
@@ -136,6 +140,6 @@ dtdump_LDADD = ../src/libgdbm.la ../compat/libgdbm_compat.la
dtfetch_LDADD = ../src/libgdbm.la ../compat/libgdbm_compat.la
dtdel_LDADD = ../src/libgdbm.la ../compat/libgdbm_compat.la
d_creat_ce_LDADD = ../src/libgdbm.la ../compat/libgdbm_compat.la
+t_wordwrap_LDADD = ../tools/libgdbmapp.a
SUBDIRS = gdbmtool
-
diff --git a/tests/atlocal.in b/tests/atlocal.in
index 43e5e18..b5c4bd9 100644
--- a/tests/atlocal.in
+++ b/tests/atlocal.in
@@ -1,5 +1,5 @@
# @configure_input@ -*- shell-script -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
-PATH=@abs_top_builddir@/src:$PATH
+PATH=@abs_top_builddir@/tools:$PATH
@COMPAT_OPT_TRUE@COMPAT=1
@COMPAT_OPT_FALSE@COMPAT=0
diff --git a/tests/blocksize00.at b/tests/blocksize00.at
index f1182a1..c31f1da 100644
--- a/tests/blocksize00.at
+++ b/tests/blocksize00.at
@@ -1,5 +1,5 @@
# This file is part of GDBM test suite.
-# Copyright (C) 2016-2021 Free Software Foundation, Inc.
+# Copyright (C) 2016-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/blocksize01.at b/tests/blocksize01.at
index 566c662..eca653e 100644
--- a/tests/blocksize01.at
+++ b/tests/blocksize01.at
@@ -1,5 +1,5 @@
# This file is part of GDBM test suite.
-# Copyright (C) 2016-2021 Free Software Foundation, Inc.
+# Copyright (C) 2016-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/blocksize02.at b/tests/blocksize02.at
index 92cdc75..46eb847 100644
--- a/tests/blocksize02.at
+++ b/tests/blocksize02.at
@@ -1,5 +1,5 @@
# This file is part of GDBM test suite.
-# Copyright (C) 2016-2021 Free Software Foundation, Inc.
+# Copyright (C) 2016-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/cloexec00.at b/tests/cloexec00.at
index c4b70ae..f58a072 100644
--- a/tests/cloexec00.at
+++ b/tests/cloexec00.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/cloexec01.at b/tests/cloexec01.at
index 40c6fb8..85860db 100644
--- a/tests/cloexec01.at
+++ b/tests/cloexec01.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/cloexec02.at b/tests/cloexec02.at
index b8dba49..339744b 100644
--- a/tests/cloexec02.at
+++ b/tests/cloexec02.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/cloexec03.at b/tests/cloexec03.at
index 37135b8..dbb8795 100644
--- a/tests/cloexec03.at
+++ b/tests/cloexec03.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/closerr.c b/tests/closerr.c
index c925f9d..97f7a54 100644
--- a/tests/closerr.c
+++ b/tests/closerr.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM test suite.
- Copyright (C) 2018-2021 Free Software Foundation, Inc.
+ Copyright (C) 2018-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/tests/conv.at b/tests/conv.at
index cc1cd3e..aa0676e 100644
--- a/tests/conv.at
+++ b/tests/conv.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2018-2021 Free Software Foundation, Inc.
+# Copyright (C) 2018-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/create00.at b/tests/create00.at
index d6bf2e6..0be62df 100644
--- a/tests/create00.at
+++ b/tests/create00.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/d_creat_ce.c b/tests/d_creat_ce.c
index d43f90f..3b409dd 100644
--- a/tests/d_creat_ce.c
+++ b/tests/d_creat_ce.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM test suite.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/tests/dbmcreate00.at b/tests/dbmcreate00.at
index 23eda4f..94fac2f 100644
--- a/tests/dbmcreate00.at
+++ b/tests/dbmcreate00.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/dbmcvt.at b/tests/dbmcvt.at
index 9cf7fcf..bead747 100644
--- a/tests/dbmcvt.at
+++ b/tests/dbmcvt.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/dbmdel00.at b/tests/dbmdel00.at
index bd7915b..6809346 100644
--- a/tests/dbmdel00.at
+++ b/tests/dbmdel00.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/dbmdel01.at b/tests/dbmdel01.at
index 1b75960..27b129d 100644
--- a/tests/dbmdel01.at
+++ b/tests/dbmdel01.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/dbmdel02.at b/tests/dbmdel02.at
index 8614b53..e513199 100644
--- a/tests/dbmdel02.at
+++ b/tests/dbmdel02.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/dbmfetch00.at b/tests/dbmfetch00.at
index 82a4044..0b6db6d 100644
--- a/tests/dbmfetch00.at
+++ b/tests/dbmfetch00.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/dbmfetch01.at b/tests/dbmfetch01.at
index e7b3935..a20b689 100644
--- a/tests/dbmfetch01.at
+++ b/tests/dbmfetch01.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/dbmfetch02.at b/tests/dbmfetch02.at
index 87c0c5f..faf72dc 100644
--- a/tests/dbmfetch02.at
+++ b/tests/dbmfetch02.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/dbmfetch03.at b/tests/dbmfetch03.at
index 98c7530..359d344 100644
--- a/tests/dbmfetch03.at
+++ b/tests/dbmfetch03.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/delete00.at b/tests/delete00.at
index 25c19d2..ed79b21 100644
--- a/tests/delete00.at
+++ b/tests/delete00.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/delete01.at b/tests/delete01.at
index 343742d..312d5ed 100644
--- a/tests/delete01.at
+++ b/tests/delete01.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/delete02.at b/tests/delete02.at
index bcbcd4d..1dc24aa 100644
--- a/tests/delete02.at
+++ b/tests/delete02.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/dtdel.c b/tests/dtdel.c
index e25059b..e2ac538 100644
--- a/tests/dtdel.c
+++ b/tests/dtdel.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM test suite.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/tests/dtdump.c b/tests/dtdump.c
index 7eea500..bb25348 100644
--- a/tests/dtdump.c
+++ b/tests/dtdump.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM test suite.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/tests/dtfetch.c b/tests/dtfetch.c
index 7e9c6dc..bad7df4 100644
--- a/tests/dtfetch.c
+++ b/tests/dtfetch.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM test suite.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/tests/dtload.c b/tests/dtload.c
index 83aa11e..f96b108 100644
--- a/tests/dtload.c
+++ b/tests/dtload.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM test suite.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/tests/dump00.at b/tests/dump00.at
index a5de494..781cc7b 100644
--- a/tests/dump00.at
+++ b/tests/dump00.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2018-2021 Free Software Foundation, Inc.
+# Copyright (C) 2018-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/fdop.c b/tests/fdop.c
index 0820a98..90cebeb 100644
--- a/tests/fdop.c
+++ b/tests/fdop.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM test suite.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/tests/fetch00.at b/tests/fetch00.at
index 5c64593..e13d799 100644
--- a/tests/fetch00.at
+++ b/tests/fetch00.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/fetch01.at b/tests/fetch01.at
index 2e1954d..792ee4e 100644
--- a/tests/fetch01.at
+++ b/tests/fetch01.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/g_open_ce.c b/tests/g_open_ce.c
index 62ab056..4a0cf23 100644
--- a/tests/g_open_ce.c
+++ b/tests/g_open_ce.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM test suite.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/tests/g_reorg_ce.c b/tests/g_reorg_ce.c
index d3f1349..da9fd9b 100644
--- a/tests/g_reorg_ce.c
+++ b/tests/g_reorg_ce.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM test suite.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/tests/gdbmtool/config/default.exp b/tests/gdbmtool/config/default.exp
index eab27ef..7376896 100644
--- a/tests/gdbmtool/config/default.exp
+++ b/tests/gdbmtool/config/default.exp
@@ -11,7 +11,7 @@ proc gdbmtool_start {args} {
global top_builddir
global gdbmtool_prompt
- set cmd "$top_builddir/src/gdbmtool -q $args"
+ set cmd "$top_builddir/tools/gdbmtool -q $args"
verbose "running $cmd" 1
set gdbmtool_spawn_id [remote_spawn host $cmd]
diff --git a/tests/gdbmtool00.at b/tests/gdbmtool00.at
index 19b1bfc..80511ed 100644
--- a/tests/gdbmtool00.at
+++ b/tests/gdbmtool00.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2018-2021 Free Software Foundation, Inc.
+# Copyright (C) 2018-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/gdbmtool01.at b/tests/gdbmtool01.at
index 8668b3e..3345b88 100644
--- a/tests/gdbmtool01.at
+++ b/tests/gdbmtool01.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2018-2021 Free Software Foundation, Inc.
+# Copyright (C) 2018-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/gdbmtool02.at b/tests/gdbmtool02.at
index 634bafc..d4c5652 100644
--- a/tests/gdbmtool02.at
+++ b/tests/gdbmtool02.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2018-2021 Free Software Foundation, Inc.
+# Copyright (C) 2018-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/gdbmtool03.at b/tests/gdbmtool03.at
index 60f7edc..8b8d716 100644
--- a/tests/gdbmtool03.at
+++ b/tests/gdbmtool03.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2018-2021 Free Software Foundation, Inc.
+# Copyright (C) 2018-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/gtcacheopt.c b/tests/gtcacheopt.c
new file mode 100644
index 0000000..088e6d8
--- /dev/null
+++ b/tests/gtcacheopt.c
@@ -0,0 +1,273 @@
+/*
+ NAME
+ gtcacheopt - test GDBM_GETCACHESIZE and GDBM_SETCACHESIZE options.
+
+ SYNOPSIS
+ gtcacheopt [-v]
+
+ DESCRIPTION
+ Reducing the cache size should retain most recently used elements
+ and ensure correct rehashing.
+
+ Operation:
+
+ 1) Create new database.
+ 2) Generate at least 10 full buckets,
+ 3) Check GDBM_GETCACHESIZE.
+ 4) Get cache statistics for the first 8 most recently
+ used cache elements.
+ 5) Set cache size to 8.
+ 6) Retrieve each of the bucket pointed to by stats obtained in 4.
+ 7) Verify that (6) retrieved buckets from cache.
+
+ OPTIONS
+ -v Verbosely print what's being done.
+
+ EXIT CODE
+ 0 success
+ 1 failure
+ 2 usage error
+
+ LICENSE
+ This file is part of GDBM test suite.
+ Copyright (C) 2021-2022 Free Software Foundation, Inc.
+
+ GDBM is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GDBM 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GDBM. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "autoconf.h"
+#include "gdbmdefs.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <unistd.h>
+
+char dbname[] = "a.db";
+int verbose = 0;
+
+#define NBUCKETS 10
+#define CACHE_SIZE 8
+#define DATASIZE (4*IGNORE_SIZE)
+
+static void
+test_getcachesize (GDBM_FILE dbf, size_t expected_size,
+ struct gdbm_cache_stat *pstat, size_t *pnstat)
+{
+ size_t size;
+ int cache_auto;
+
+ if (gdbm_setopt (dbf, GDBM_GETCACHESIZE, &size, sizeof (size)))
+ {
+ fprintf (stderr, "GDBM_GETCACHESIZE: %s\n", gdbm_strerror (gdbm_errno));
+ exit (1);
+ }
+
+ if (verbose)
+ printf ("size = %zu\n", size);
+
+ if (expected_size && expected_size != size)
+ {
+ fprintf (stderr, "expected_size != size (%zu != %zu)\n",
+ expected_size, size);
+ exit (1);
+ }
+
+ if (gdbm_setopt (dbf, GDBM_GETCACHEAUTO, &cache_auto, sizeof (cache_auto)))
+ {
+ fprintf (stderr, "GDBM_GETCACHESIZE: %s\n", gdbm_strerror (gdbm_errno));
+ exit (1);
+ }
+
+ if (verbose)
+ printf ("cache_auto = %d\n", cache_auto);
+
+ if (expected_size && cache_auto != 0)
+ {
+ fprintf (stderr, "cache_auto != 0\n");
+ exit (1);
+ }
+
+ if (pstat)
+ {
+ gdbm_get_cache_stats (dbf, NULL, NULL, pnstat, pstat, CACHE_SIZE);
+ }
+}
+
+static int
+dir_index (GDBM_FILE dbf, off_t adr)
+{
+ int i;
+
+ for (i = 0; i < dbf->header->dir_size; i++)
+ if (dbf->dir[i] == adr)
+ return i;
+ fprintf (stderr, "%lu: can't find bucket in directory\n", adr);
+ exit (1);
+}
+
+int
+main (int argc, char **argv)
+{
+ GDBM_FILE dbf;
+ datum key, content;
+
+ int nkeys;
+
+ char data[DATASIZE];
+
+ int i;
+
+ struct gdbm_cache_stat stat[2][CACHE_SIZE];
+ size_t nstat[2];
+
+ while ((i = getopt (argc, argv, "v")) != EOF)
+ {
+ switch (i)
+ {
+ case 'v':
+ verbose++;
+ break;
+
+ default:
+ return 2;
+ }
+ }
+
+ /*
+ * 1) Create new database.
+ */
+ if (verbose)
+ printf ("creating database\n");
+
+ dbf = gdbm_open (dbname, GDBM_MIN_BLOCK_SIZE, GDBM_NEWDB, 0644, NULL);
+ if (!dbf)
+ {
+ fprintf (stderr, "gdbm_open: %s\n", gdbm_strerror (gdbm_errno));
+ return 1;
+ }
+
+ /*
+ * 2) Generate 10 full buckets or key/value pairs are created.
+ */
+
+ /* Initialize keys. */
+ nkeys = NBUCKETS * dbf->header->bucket_elems;
+
+ /* Initialize content */
+ for (i = 0; i < DATASIZE; i++)
+ data[i] = i+1;
+ content.dsize = DATASIZE;
+ content.dptr = data;
+
+ /* Populate the database. */
+ if (verbose)
+ printf ("populating database (%d keys)\n", nkeys);
+ key.dsize = sizeof (i);
+ key.dptr = (char*) &i;
+ for (i = 0; i < nkeys; i++)
+ {
+ if (gdbm_store (dbf, key, content, 0) != 0)
+ {
+ fprintf (stderr, "%d: item not inserted: %s\n",
+ i, gdbm_db_strerror (dbf));
+ gdbm_close (dbf);
+ return 1;
+ }
+ }
+
+ /*
+ * 3) Check if the value retrieved by GDBM_GETCACHESIZE matches the
+ * expected one and
+ * 4) save cache statistics for the first CACHE_SIZE most recently used
+ * cache elements.
+ */
+ test_getcachesize (dbf, 0, stat[0], &nstat[0]);
+
+ if (verbose)
+ printf ("setting new cache size\n");
+
+ /*
+ * 5) Set new cache size.
+ */
+ i = CACHE_SIZE;
+ if (gdbm_setopt (dbf, GDBM_SETCACHESIZE, &i, sizeof (i)))
+ {
+ fprintf (stderr, "GDBM_SETCACHESIZE: %s\n", gdbm_strerror (gdbm_errno));
+ return 1;
+ }
+
+ if (verbose)
+ printf ("verifying cache (pass 1)\n");
+
+ /*
+ * 6) Retrieve each of the bucket pointed to by stats obtained in 4.
+ *
+ * To retrieve a bucket, the corresponding directory index must be known.
+ * That index is obtained using linear search in the database file directory.
+ *
+ * Buckets must be retrieved in reverse order, so that the LRU cache
+ * remains in the same order after the operation (each retrieval cyclically
+ * shifts elements in the queue).
+ */
+ test_getcachesize (dbf, CACHE_SIZE, stat[1], &nstat[1]);
+
+ for (i = CACHE_SIZE - 1; i >= 0; i--)
+ {
+ if (stat[0][i].adr != stat[1][i].adr)
+ {
+ fprintf (stderr, "%d: address mismatch\n", i);
+ return 1;
+ }
+ if (_gdbm_get_bucket (dbf, dir_index (dbf, stat[0][i].adr)))
+ {
+ fprintf (stderr, "%d: _gdbm_get_bucket: %s\n", i,
+ gdbm_db_strerror (dbf));
+ return 1;
+ }
+ }
+
+ if (verbose)
+ printf ("getting cache statistics\n");
+ test_getcachesize (dbf, CACHE_SIZE, stat[0], &nstat[0]);
+
+ gdbm_close (dbf);
+
+ /*
+ * 7) Verify that the buckets were retrieved from cache.
+ *
+ * To do so, compare addresses and hit counts in statistic buffers
+ * stat[0] and stat[1]. Each pair of elements must have the same
+ * bucket address. Hit counts must differ by 1.
+ */
+ if (verbose)
+ printf ("verifying cache (pass 2)\n");
+ for (i = 0; i < CACHE_SIZE; i++)
+ {
+ if (stat[0][i].adr != stat[1][i].adr)
+ {
+ fprintf (stderr, "%d: address mismatch\n", i);
+ return 1;
+ }
+ if (stat[0][i].hits != stat[1][i].hits + 1)
+ {
+ fprintf (stderr, "%d: hit count mismatch: %zu != %zu\n", i,
+ stat[0][i].hits, stat[1][i].hits);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+
diff --git a/tests/gtconv.c b/tests/gtconv.c
index 46ca8a7..6471f50 100644
--- a/tests/gtconv.c
+++ b/tests/gtconv.c
@@ -45,7 +45,7 @@
LICENSE
This file is part of GDBM test suite.
- Copyright (C) 2021 Free Software Foundation, Inc.
+ Copyright (C) 2021-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/tests/gtdel.c b/tests/gtdel.c
index c91255f..301e761 100644
--- a/tests/gtdel.c
+++ b/tests/gtdel.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM test suite.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/tests/gtdump.c b/tests/gtdump.c
index e0c2f8b..b2dd3c4 100644
--- a/tests/gtdump.c
+++ b/tests/gtdump.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM test suite.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/tests/gtfetch.c b/tests/gtfetch.c
index 87ddb09..28ad48c 100644
--- a/tests/gtfetch.c
+++ b/tests/gtfetch.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM test suite.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/tests/gtload.c b/tests/gtload.c
index b7df9d2..1fcafb2 100644
--- a/tests/gtload.c
+++ b/tests/gtload.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM test suite.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -96,6 +96,7 @@ main (int argc, char **argv)
int recover = 0;
gdbm_recovery rcvr;
int rcvr_flags = 0;
+ size_t cache_size = 0;
progname = canonical_progname (argv[0]);
#ifdef GDBM_DEBUG_ENABLE
@@ -135,6 +136,8 @@ main (int argc, char **argv)
delim = arg[7];
else if (strcmp (arg, "-recover") == 0)
recover = 1;
+ else if (strncmp (arg, "-cachesize=", 11) == 0)
+ cache_size = read_size (arg + 11);
else if (strcmp (arg, "-verbose") == 0)
{
verbose = 1;
@@ -213,7 +216,17 @@ main (int argc, char **argv)
gdbm_strerror (gdbm_errno));
exit (1);
}
- }
+ }
+ if (cache_size)
+ {
+ if (gdbm_setopt (dbf, GDBM_SETCACHESIZE, &cache_size,
+ sizeof (cache_size)))
+ {
+ fprintf (stderr, "GDBM_SETCACHESIZE failed: %s\n",
+ gdbm_strerror (gdbm_errno));
+ exit (1);
+ }
+ }
if (verbose)
{
diff --git a/tests/gtopt.c b/tests/gtopt.c
index 77bebce..864750f 100644
--- a/tests/gtopt.c
+++ b/tests/gtopt.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM test suite.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/tests/gtrecover.c b/tests/gtrecover.c
index 35d60df..7754052 100644
--- a/tests/gtrecover.c
+++ b/tests/gtrecover.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM test suite.
- Copyright (C) 2016-2021 Free Software Foundation, Inc.
+ Copyright (C) 2016-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/tests/gtver.c b/tests/gtver.c
index c21fe90..f673393 100644
--- a/tests/gtver.c
+++ b/tests/gtver.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM test suite.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/tests/num2word.c b/tests/num2word.c
index 0c9e7f7..e4d451b 100644
--- a/tests/num2word.c
+++ b/tests/num2word.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM test suite.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/tests/progname.h b/tests/progname.h
index 3ea8446..2a1e31e 100644
--- a/tests/progname.h
+++ b/tests/progname.h
@@ -1,5 +1,5 @@
/* This file is part of GDBM test suite.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/tests/setopt00.at b/tests/setopt00.at
index aee03e7..30fd71e 100644
--- a/tests/setopt00.at
+++ b/tests/setopt00.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/setopt01.at b/tests/setopt01.at
index b05a4c6..ee504f2 100644
--- a/tests/setopt01.at
+++ b/tests/setopt01.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/setopt02.at b/tests/setopt02.at
new file mode 100644
index 0000000..5493ccf
--- /dev/null
+++ b/tests/setopt02.at
@@ -0,0 +1,20 @@
+# This file is part of GDBM. -*- autoconf -*-
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
+#
+# GDBM is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GDBM 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
+
+AT_SETUP([GDBM_GETCACHESIZE/GDBM_SETCACHESIZE])
+AT_KEYWORDS([setopt setopt02 cachesize])
+AT_CHECK([gtcacheopt])
+AT_CLEANUP
diff --git a/tests/t_wordwrap.c b/tests/t_wordwrap.c
new file mode 100644
index 0000000..324b03d
--- /dev/null
+++ b/tests/t_wordwrap.c
@@ -0,0 +1,181 @@
+/* This file is part of GDBM test suite.
+ Copyright (C) 2021-2022 Free Software Foundation, Inc.
+
+ GDBM is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GDBM 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GDBM. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "autoconf.h"
+#include "gdbmapp.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+
+static void
+h_left_margin (WORDWRAP_FILE wf, char *arg)
+{
+ wordwrap_set_left_margin (wf, atoi (arg));
+}
+
+static void
+h_right_margin (WORDWRAP_FILE wf, char *arg)
+{
+ wordwrap_set_right_margin (wf, atoi (arg));
+}
+
+static void
+h_flush (WORDWRAP_FILE wf, char *arg)
+{
+ wordwrap_flush (wf);
+}
+
+static void
+h_file (WORDWRAP_FILE wf, char *arg)
+{
+ FILE *fp;
+ char buf[256];
+
+ fp = fopen (arg, "r");
+ if (!fp)
+ {
+ perror (arg);
+ exit (1);
+ }
+
+ while (fgets (buf, sizeof buf, fp))
+ {
+ wordwrap_write (wf, buf, strlen (buf));
+ }
+ fclose (fp);
+}
+
+static void
+h_newline (WORDWRAP_FILE wf, char *arg)
+{
+ wordwrap_putc (wf, '\n');
+}
+
+static void
+h_para (WORDWRAP_FILE wf, char *arg)
+{
+ wordwrap_para (wf);
+}
+
+
+struct wwt_option
+{
+ char *name;
+ int arg;
+ void (*handler) (WORDWRAP_FILE, char *);
+};
+
+struct wwt_option wwt_options[] = {
+ { "left", 1, h_left_margin },
+ { "right", 1, h_right_margin },
+ { "flush", 0, h_flush },
+ { "file", 1, h_file },
+ { "newline", 0, h_newline },
+ { "para", 0, h_para },
+ { NULL }
+};
+
+enum
+ {
+ WWT_ARG,
+ WWT_OPT,
+ WWT_ERR
+ };
+
+int
+wwt_getopt (WORDWRAP_FILE wf, char *arg)
+{
+ if (arg[0] == '-')
+ {
+ struct wwt_option *opt;
+ size_t len;
+
+ if (arg[1] == '-' && arg[2] == 0)
+ return WWT_ARG;
+
+ arg++;
+ len = strcspn (arg, "=");
+
+ for (opt = wwt_options; opt->name; opt++)
+ {
+ if (strlen (opt->name) == len && memcmp (opt->name, arg, len) == 0)
+ {
+ if (opt->arg && arg[len])
+ arg += len + 1;
+ else if (!opt->arg && !arg[len])
+ arg = NULL;
+ else
+ continue;
+ opt->handler (wf, arg);
+ return WWT_OPT;
+ }
+ }
+ return WWT_ERR;
+ }
+ return WWT_ARG;
+}
+
+int
+main (int argc, char **argv)
+{
+ WORDWRAP_FILE wf;
+ int escape = 0;
+
+ setlocale (LC_ALL, "");
+ if ((wf = wordwrap_fdopen (1)) == NULL)
+ {
+ perror ("wordwrap_open");
+ exit (1);
+ }
+
+ while (--argc)
+ {
+ char *arg = *++argv;
+
+ if (escape)
+ {
+ wordwrap_write (wf, arg, strlen (arg));
+ if (argc > 1)
+ wordwrap_write (wf, " ", 1);
+ escape = 0;
+ continue;
+ }
+
+ switch (wwt_getopt (wf, arg))
+ {
+ case WWT_ARG:
+ if (strcmp (arg, "--") == 0)
+ escape = 1;
+ else
+ {
+ wordwrap_write (wf, arg, strlen (arg));
+ if (argc > 1)
+ wordwrap_write (wf, " ", 1);
+ }
+ break;
+
+ case WWT_OPT:
+ break;
+
+ case WWT_ERR:
+ fprintf (stderr, "unrecognized option: %s\n", arg);
+ }
+ }
+
+ wordwrap_close (wf);
+}
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 8437851..5eba99f 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -69,6 +69,7 @@ AT_BANNER([DB options])
m4_include([setopt00.at])
m4_include([setopt01.at])
+m4_include([setopt02.at])
AT_BANNER([Cloexec])
@@ -77,6 +78,9 @@ m4_include([cloexec01.at])
m4_include([cloexec02.at])
m4_include([cloexec03.at])
+AT_BANNER([Wordwrap])
+m4_include([wordwrap.at])
+
AT_BANNER([gdbmtool])
m4_include([gdbmtool00.at])
m4_include([gdbmtool01.at])
diff --git a/tests/version.at b/tests/version.at
index 7f60330..3418977 100644
--- a/tests/version.at
+++ b/tests/version.at
@@ -1,5 +1,5 @@
# This file is part of GDBM. -*- autoconf -*-
-# Copyright (C) 2011-2021 Free Software Foundation, Inc.
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
#
# GDBM is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tests/wordwrap.at b/tests/wordwrap.at
new file mode 100644
index 0000000..94e96a5
--- /dev/null
+++ b/tests/wordwrap.at
@@ -0,0 +1,129 @@
+# This file is part of GDBM. -*- autoconf -*-
+# Copyright (C) 2021-2022 Free Software Foundation, Inc.
+#
+# GDBM is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GDBM 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
+
+AT_SETUP([wordwrap])
+
+AT_CHECK([t_wordwrap -right=10 abcdefghi],
+[0],
+[abcdefghi
+])
+
+AT_CHECK([t_wordwrap -right=10 abcdefghijklmn],
+[0],
+[abcdefghi
+jklmn
+])
+
+AT_CHECK([t_wordwrap -right=10 abcd efg hijklmn],
+[0],
+[abcd efg
+hijklmn
+])
+
+AT_CHECK([t_wordwrap -left=2 -right=10 Donec condimentum orciluctus facilisis interdum],
+[0],
+[ Donec
+ condime
+ ntum
+ orciluc
+ tus
+ facilis
+ is
+ interdu
+ m
+])
+
+AT_DATA([1.in],
+[Cras non est eleifend diam placerat aliquet. Phasellus sem dui, tincidunt eget interdum sed, auctor nec nibh. Donec condimentum orci luctus facilisis interdum. Nam sed rhoncus neque. Aliquam pellentesque ligula massa, et maximus augue commodo et. Sed et mi dolor.
+])
+
+AT_CHECK([t_wordwrap -left=10 -right=30 -file=1.in],
+[0],
+[ Cras non est
+ eleifend diam
+ placerat aliquet.
+ Phasellus sem dui,
+ tincidunt eget
+ interdum sed,
+ auctor nec nibh.
+ Donec condimentum
+ orci luctus
+ facilisis interdum.
+ Nam sed rhoncus
+ neque. Aliquam
+ pellentesque ligula
+ massa, et maximus
+ augue commodo et.
+ Sed et mi dolor.
+])
+
+AT_DATA([2.in],
+[Cras non est eleifend diam placerat aliquet. Phasellus sem dui,
+tincidunt eget interdum sed, auctor nec
+nibh.
+Donec condimentum orci luctus facilisis interdum.
+
+Nam sed rhoncus neque.
+Aliquam pellentesque ligula massa,
+et maximus augue commodo et. Sed et mi dolor.
+])
+
+AT_CHECK([t_wordwrap -left=10 -right=30 -file=2.in],
+[0],
+[ Cras non est
+ eleifend diam
+ placerat aliquet.
+ Phasellus sem dui,
+ tincidunt eget
+ interdum sed,
+ auctor nec
+ nibh.
+ Donec condimentum
+ orci luctus
+ facilisis interdum.
+
+ Nam sed rhoncus
+ neque.
+ Aliquam
+ pellentesque ligula
+ massa,
+ et maximus augue
+ commodo et. Sed et
+ mi dolor.
+])
+
+AT_CHECK([t_wordwrap -left=10 -right=64 \
+ -- '-a, --aenean' -left=30 'aenean quis posuere lacus a suscipit erat, donec sit amet pretium ligula, non ex et nisi placerat suscipit.' \
+ -left=10 \
+ -- -b \
+ -left=30 pulvinar tempor erat \
+ -left=10 \
+ -- '--porttitor, --ullamcore, --diam-velit-consecretur' \
+ -left=30 \
+ lorem ipsum uis aute irure dolor in reprehenderit in voluptate velit esse],
+[0],
+[ -a, --aenean aenean quis posuere lacus a
+ suscipit erat, donec sit amet
+ pretium ligula, non ex et nisi
+ placerat suscipit.
+ -b pulvinar tempor erat
+ --porttitor, --ullamcore, --diam-velit-consecretur
+ lorem ipsum uis aute irure dolor
+ in reprehenderit in voluptate
+ velit esse
+])
+
+AT_CLEANUP \ No newline at end of file
diff --git a/tools/.gitignore b/tools/.gitignore
new file mode 100644
index 0000000..57e8914
--- /dev/null
+++ b/tools/.gitignore
@@ -0,0 +1,6 @@
+gdbmtool
+gdbm_dump
+gdbm_load
+gram.[ch]
+gram.output
+lex.c
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 0000000..36b51e4
--- /dev/null
+++ b/tools/Makefile.am
@@ -0,0 +1,80 @@
+# This file is part of GDBM. -*- Makefile -*-
+# Copyright (C) 2007-2022 Free Software Foundation, Inc.
+#
+# GDBM is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GDBM 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GDBM. If not, see <http://www.gnu.org/licenses/>.
+
+# Flags
+AM_CPPFLAGS=\
+ -DLOCALEDIR=\"$(localedir)\"\
+ -I$(top_srcdir)/src\
+ -I$(top_builddir)/src\
+ -I$(top_srcdir)/tools
+
+noinst_LIBRARIES = libgdbmapp.a
+
+libgdbmapp_a_SOURCES =\
+ err.c\
+ mem.c\
+ gdbmapp.h\
+ parseopt.c\
+ progname.c\
+ datconv.c\
+ gram.c\
+ input-argv.c\
+ input-file.c\
+ input-null.c\
+ input-std.c\
+ lex.c\
+ gdbmshell.c\
+ var.c\
+ util.c\
+ wordwrap.c
+
+if GDBM_COND_READLINE
+ libgdbmapp_a_SOURCES += input-rl.c
+endif
+
+# Programs
+bin_PROGRAMS = gdbmtool gdbm_load gdbm_dump
+
+EXTRA_DIST = gram.y lex.l
+BUILT_SOURCES = gram.h gram.c lex.c
+noinst_HEADERS = gram.h
+
+gram.c gram.h: gram.y
+lex.c: lex.l
+
+gdbmtool_LDADD = \
+ ./libgdbmapp.a\
+ ../src/libgdbm.la\
+ @READLINE_LIBS@
+
+gdbmtool_SOURCES = \
+ gdbmtool.h\
+ gdbmtool.c
+
+AM_YFLAGS = -dv $(YFLAGS_DEBUG)
+AM_LFLAGS = $(LFLAGS_DEBUG)
+
+.l.c:
+ $(AM_V_GEN)$(FLEX) -o $@ $(AM_LFLAGS) $<
+.y.c:
+ $(AM_V_GEN)$(BISON) -o $@ $(AM_YFLAGS) $<
+
+if COND_GDBMTOOL_DEBUG
+ AM_CPPFLAGS += -DGDBMTOOL_DEBUG=1
+endif
+
+gdbm_load_LDADD = ./libgdbmapp.a ../src/libgdbm.la
+gdbm_dump_LDADD = ./libgdbmapp.a ../src/libgdbm.la
diff --git a/src/datconv.c b/tools/datconv.c
index 4d05f11..874e260 100644
--- a/src/datconv.c
+++ b/tools/datconv.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/err.c b/tools/err.c
index 19ba6ef..a2dd653 100644
--- a/src/err.c
+++ b/tools/err.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/gdbm_dump.c b/tools/gdbm_dump.c
index ada191d..a480152 100644
--- a/src/gdbm_dump.c
+++ b/tools/gdbm_dump.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/gdbm_load.c b/tools/gdbm_load.c
index 41cb820..b4691c9 100644
--- a/src/gdbm_load.c
+++ b/tools/gdbm_load.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/gdbmapp.h b/tools/gdbmapp.h
index 5c60e7b..1bccb3d 100644
--- a/src/gdbmapp.h
+++ b/tools/gdbmapp.h
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -61,4 +61,25 @@ extern char *parseopt_program_args;
#define EXIT_FATAL 1
#define EXIT_MILD 2
#define EXIT_USAGE 3
+
+/* Word-wrapping stream. */
+typedef struct wordwrap_file *WORDWRAP_FILE;
+
+WORDWRAP_FILE wordwrap_fdopen (int fd);
+int wordwrap_close (WORDWRAP_FILE wf);
+int wordwrap_flush (WORDWRAP_FILE wf);
+int wordwrap_error (WORDWRAP_FILE wf);
+int wordwrap_set_left_margin (WORDWRAP_FILE wf, unsigned left);
+int wordwrap_next_left_margin (WORDWRAP_FILE wf, unsigned left);
+int wordwrap_set_right_margin (WORDWRAP_FILE wf, unsigned right);
+int wordwrap_write (WORDWRAP_FILE wf, char const *str, size_t len);
+int wordwrap_puts (WORDWRAP_FILE wf, char const *str);
+int wordwrap_putc (WORDWRAP_FILE wf, int c);
+int wordwrap_para (WORDWRAP_FILE wf);
+int wordwrap_vprintf (WORDWRAP_FILE wf, char const *fmt, va_list ap);
+int wordwrap_printf (WORDWRAP_FILE wf, char const *fmt, ...);
+int wordwrap_at_bol (WORDWRAP_FILE wf);
+int wordwrap_at_eol (WORDWRAP_FILE wf);
+void wordwrap_word_start (WORDWRAP_FILE wf);
+void wordwrap_word_end (WORDWRAP_FILE wf);
diff --git a/src/gdbmshell.c b/tools/gdbmshell.c
index 578b7cb..22c4938 100644
--- a/src/gdbmshell.c
+++ b/tools/gdbmshell.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -36,7 +36,7 @@ static GDBM_FILE gdbm_file = NULL; /* Database to operate upon */
static datum key_data; /* Current key */
static datum return_data; /* Current data */
-/* Return values for hanlders: */
+/* Return values for handlers: */
enum
{
GDBMSHELL_OK, /* Success */
@@ -197,7 +197,7 @@ checkdb_begin (struct command_param *param GDBM_ARG_UNUSED,
static size_t
bucket_print_lines (hash_bucket *bucket)
{
- return 6 + gdbm_file->header->bucket_elems + 3 + bucket->av_count;
+ return 10 + gdbm_file->header->bucket_elems + 3 + bucket->av_count;
}
static void
@@ -215,21 +215,64 @@ format_key_start (FILE *fp, bucket_element *elt)
}
}
+static inline int
+bucket_refcount (void)
+{
+ return 1 << (gdbm_file->header->dir_bits - gdbm_file->bucket->bucket_bits);
+}
+
+static inline int
+bucket_dir_start (void)
+{
+ int d = gdbm_file->header->dir_bits - gdbm_file->bucket->bucket_bits;
+ return (gdbm_file->bucket_dir >> d) << d;
+}
+
+static inline int
+bucket_dir_sibling (void)
+{
+ int d = gdbm_file->header->dir_bits - gdbm_file->bucket->bucket_bits;
+ return ((gdbm_file->bucket_dir >> d) ^ 1) << d;
+}
+
/* Debug procedure to print the contents of the current hash bucket. */
static void
-print_bucket (FILE *fp, hash_bucket *bucket, const char *mesg, ...)
+print_bucket (FILE *fp)
{
int index;
- va_list ap;
+ int hash_prefix;
+ off_t adr = gdbm_file->dir[gdbm_file->bucket_dir];
+ hash_bucket *bucket = gdbm_file->bucket;
+ int start = bucket_dir_start ();
+ int dircount = bucket_refcount ();
+
+ hash_prefix = start << (GDBM_HASH_BITS - gdbm_file->header->dir_bits);
fprintf (fp, "******* ");
- va_start(ap, mesg);
- vfprintf (fp, mesg, ap);
- va_end (ap);
+ fprintf (fp, _("Bucket #%d"), gdbm_file->bucket_dir);
fprintf (fp, " **********\n\n");
fprintf (fp,
- _("bits = %d\ncount= %d\nHash Table:\n"),
- bucket->bucket_bits, bucket->count);
+ _("address = %lu\n"
+ "depth = %d\n"
+ "hash prefix = %08x\n"
+ "references = %u"),
+ (unsigned long) adr,
+ bucket->bucket_bits,
+ hash_prefix,
+ dircount);
+ if (dircount > 1)
+ {
+ fprintf (fp, " (%d-%d)", start, start + dircount - 1);
+ }
+ fprintf (fp, "\n");
+
+ fprintf (fp,
+ _("count = %d\n"
+ "load factor = %3d\n"),
+ bucket->count,
+ bucket->count * 100 / gdbm_file->header->bucket_elems);
+
+ fprintf (fp, "%s", _("Hash Table:\n"));
fprintf (fp,
_(" # hash value key size data size data adr home key start\n"));
for (index = 0; index < gdbm_file->header->bucket_elems; index++)
@@ -249,7 +292,7 @@ print_bucket (FILE *fp, hash_bucket *bucket, const char *mesg, ...)
fprintf (fp, "\n");
}
- fprintf (fp, _("\nAvail count = %1d\n"), bucket->av_count);
+ fprintf (fp, _("\nAvail count = %d\n"), bucket->av_count);
fprintf (fp, _("Address size\n"));
for (index = 0; index < bucket->av_count; index++)
fprintf (fp, "%11lu%9d\n",
@@ -330,7 +373,7 @@ _gdbm_print_bucket_cache (FILE *fp, GDBM_FILE dbf)
fprintf (fp,
_("Bucket Cache (size %zu/%zu):\n Index: Address Changed Data_Hash \n"),
dbf->cache_num, dbf->cache_size);
- for (elem = dbf->cache_entry, i = 0; elem; elem = elem->ca_next, i++)
+ for (elem = dbf->cache_mru, i = 0; elem; elem = elem->ca_next, i++)
{
fprintf (fp, " %5d: %15lu %7s %x\n",
i,
@@ -618,7 +661,7 @@ err_printer (void *data GDBM_ARG_UNUSED, char const *fmt, ...)
fprintf (stderr, "\n");
}
-/* recover sumamry verbose backup max-failed-keys=N max-failed-buckets=N max-failures=N */
+/* recover summary verbose backup max-failed-keys=N max-failed-buckets=N max-failures=N */
static int
recover_handler (struct command_param *param, struct command_environ *cenv)
{
@@ -768,17 +811,7 @@ print_current_bucket_handler (struct command_param *param,
if (!gdbm_file->bucket)
fprintf (cenv->fp, _("no current bucket\n"));
else
- {
- if (param->argc)
- print_bucket (cenv->fp, gdbm_file->bucket, _("Bucket #%s"),
- PARAM_STRING (param, 0));
- else
- print_bucket (cenv->fp, gdbm_file->bucket, "%s", _("Current bucket"));
- fprintf (cenv->fp, _("\n current directory entry = %d.\n"),
- gdbm_file->bucket_dir);
- fprintf (cenv->fp, _(" current bucket address = %lu.\n"),
- (unsigned long) gdbm_file->cache_entry->ca_adr);
- }
+ print_bucket (cenv->fp);
return GDBMSHELL_OK;
}
@@ -813,29 +846,86 @@ print_bucket_begin (struct command_param *param,
size_t *exp_count)
{
int rc;
- int temp;
-
+ int n = -1;
+
if ((rc = checkdb ()) != GDBMSHELL_OK)
return rc;
+
+ if (param->argc == 1)
+ {
+ if (getnum (&n, PARAM_STRING (param, 0), NULL))
+ return GDBMSHELL_SYNTAX;
+
+ if (n >= GDBM_DIR_COUNT (gdbm_file))
+ {
+ terror (_("bucket number out of range (0..%lu)"),
+ GDBM_DIR_COUNT (gdbm_file));
+ return GDBMSHELL_SYNTAX;
+ }
+ }
+ else if (!gdbm_file->bucket)
+ n = 0;
+
+ if (n != -1)
+ {
+ if (_gdbm_get_bucket (gdbm_file, n))
+ {
+ dberror (_("%s failed"), "_gdbm_get_bucket");
+ return GDBMSHELL_GDBM_ERR;
+ }
+ }
- if (getnum (&temp, PARAM_STRING (param, 0), NULL))
- return GDBMSHELL_SYNTAX;
+ if (exp_count)
+ *exp_count = bucket_print_lines (gdbm_file->bucket) + 3;
+ return GDBMSHELL_OK;
+}
- if (temp >= GDBM_DIR_COUNT (gdbm_file))
+static int
+print_sibling_bucket_begin (struct command_param *param,
+ struct command_environ *cenv GDBM_ARG_UNUSED,
+ size_t *exp_count)
+{
+ int rc, n0, n, bucket_bits;
+
+ if ((rc = checkdb ()) != GDBMSHELL_OK)
+ return rc;
+ if (!gdbm_file->bucket)
{
- terror (_("bucket number out of range (0..%lu)"),
- GDBM_DIR_COUNT (gdbm_file));
- return GDBMSHELL_SYNTAX;
+ fprintf (stderr, _("no current bucket\n"));
+ return GDBMSHELL_ERR;
}
- if (_gdbm_get_bucket (gdbm_file, temp))
+
+ n0 = gdbm_file->bucket_dir;
+ bucket_bits = gdbm_file->bucket->bucket_bits;
+ n = bucket_dir_sibling ();
+
+ if (n > GDBM_DIR_COUNT (gdbm_file))
+ {
+ fprintf (stderr, _("no sibling\n"));
+ return GDBMSHELL_ERR;
+ }
+
+ if (_gdbm_get_bucket (gdbm_file, n))
{
dberror (_("%s failed"), "_gdbm_get_bucket");
return GDBMSHELL_GDBM_ERR;
}
+
+ if (bucket_bits != gdbm_file->bucket->bucket_bits)
+ {
+ fprintf (stderr, _("no sibling\n"));
+ if (_gdbm_get_bucket (gdbm_file, n0))
+ {
+ dberror (_("%s failed"), "_gdbm_get_bucket");
+ return GDBMSHELL_GDBM_ERR;
+ }
+ return GDBMSHELL_ERR;
+ }
+
if (exp_count)
*exp_count = bucket_print_lines (gdbm_file->bucket) + 3;
return GDBMSHELL_OK;
-}
+}
/* dir - print hash directory */
static int
@@ -870,15 +960,21 @@ print_dir_handler (struct command_param *param GDBM_ARG_UNUSED,
struct command_environ *cenv)
{
int i;
-
+
fprintf (cenv->fp, _("Hash table directory.\n"));
- fprintf (cenv->fp, _(" Size = %d. Bits = %d, Buckets = %zu.\n\n"),
- gdbm_file->header->dir_size, gdbm_file->header->dir_bits,
+ fprintf (cenv->fp, _(" Size = %d. Capacity = %lu. Bits = %d, Buckets = %zu.\n\n"),
+ gdbm_file->header->dir_size,
+ GDBM_DIR_COUNT (gdbm_file),
+ gdbm_file->header->dir_bits,
bucket_count ());
-
+
+ fprintf (cenv->fp, "#%11s %8s %s\n",
+ _("Index"), _("Hash Pfx"), _("Bucket address"));
for (i = 0; i < GDBM_DIR_COUNT (gdbm_file); i++)
- fprintf (cenv->fp, " %10d: %12lu\n",
- i, (unsigned long) gdbm_file->dir[i]);
+ fprintf (cenv->fp, " %10d: %08x %12lu\n",
+ i,
+ i << (GDBM_HASH_BITS - gdbm_file->header->dir_bits),
+ (unsigned long) gdbm_file->dir[i]);
return GDBMSHELL_OK;
}
@@ -942,28 +1038,28 @@ print_header_handler (struct command_param *param GDBM_ARG_UNUSED,
}
fprintf (fp, _("\nFile Header: \n\n"));
- fprintf (fp, _(" type = %s\n"), type);
- fprintf (fp, _(" table = %lu\n"),
+ fprintf (fp, _(" type = %s\n"), type);
+ fprintf (fp, _(" directory start = %lu\n"),
(unsigned long) gdbm_file->header->dir);
- fprintf (fp, _(" table size = %d\n"), gdbm_file->header->dir_size);
- fprintf (fp, _(" table bits = %d\n"), gdbm_file->header->dir_bits);
- fprintf (fp, _(" block size = %d\n"), gdbm_file->header->block_size);
- fprintf (fp, _(" bucket elems = %d\n"), gdbm_file->header->bucket_elems);
- fprintf (fp, _(" bucket size = %d\n"), gdbm_file->header->bucket_size);
- fprintf (fp, _(" header magic = %x\n"), gdbm_file->header->header_magic);
- fprintf (fp, _(" next block = %lu\n"),
+ fprintf (fp, _(" directory size = %d\n"), gdbm_file->header->dir_size);
+ fprintf (fp, _(" directory depth = %d\n"), gdbm_file->header->dir_bits);
+ fprintf (fp, _(" block size = %d\n"), gdbm_file->header->block_size);
+ fprintf (fp, _(" bucket elems = %d\n"), gdbm_file->header->bucket_elems);
+ fprintf (fp, _(" bucket size = %d\n"), gdbm_file->header->bucket_size);
+ fprintf (fp, _(" header magic = %x\n"), gdbm_file->header->header_magic);
+ fprintf (fp, _(" next block = %lu\n"),
(unsigned long) gdbm_file->header->next_block);
- fprintf (fp, _(" avail size = %d\n"), gdbm_file->avail->size);
- fprintf (fp, _(" avail count = %d\n"), gdbm_file->avail->count);
- fprintf (fp, _(" avail nx blk = %lu\n"),
+ fprintf (fp, _(" avail size = %d\n"), gdbm_file->avail->size);
+ fprintf (fp, _(" avail count = %d\n"), gdbm_file->avail->count);
+ fprintf (fp, _(" avail next block= %lu\n"),
(unsigned long) gdbm_file->avail->next_block);
if (gdbm_file->xheader)
{
fprintf (fp, _("\nExtended Header: \n\n"));
- fprintf (fp, _(" version = %d\n"), gdbm_file->xheader->version);
- fprintf (fp, _(" numsync = %u\n"), gdbm_file->xheader->numsync);
+ fprintf (fp, _(" version = %d\n"), gdbm_file->xheader->version);
+ fprintf (fp, _(" numsync = %u\n"), gdbm_file->xheader->numsync);
}
return GDBMSHELL_OK;
@@ -1287,25 +1383,96 @@ list_begin (struct command_param *param GDBM_ARG_UNUSED,
if ((rc = checkdb ()) == GDBMSHELL_OK)
{
- if (exp_count)
+ if (param->argc)
{
- gdbm_count_t count;
+ if (strcmp (PARAM_STRING (param, 0), "bucket"))
+ {
+ fprintf (stderr, _("unrecognized parameter: %s\n"),
+ PARAM_STRING (param, 0));
+ return GDBMSHELL_ERR;
+ }
- if (gdbm_count (gdbm_file, &count))
- *exp_count = 0;
- else if (count > SIZE_T_MAX)
- *exp_count = SIZE_T_MAX;
- else
- *exp_count = count;
+ if (!gdbm_file->bucket)
+ {
+ fprintf (stderr, "%s", _("select bucket first\n"));
+ return GDBMSHELL_ERR;
+ }
+
+ if (exp_count)
+ {
+ int n = 0, i;
+
+ for (i = 0; i < gdbm_file->bucket->count; i++)
+ {
+ if (gdbm_file->bucket->h_table[i].hash_value != -1)
+ n++;
+ }
+ *exp_count = n;
+ }
+ }
+ else
+ {
+ if (exp_count)
+ {
+ gdbm_count_t count;
+
+ if (gdbm_count (gdbm_file, &count))
+ *exp_count = 0;
+ else if (count > SIZE_T_MAX)
+ *exp_count = SIZE_T_MAX;
+ else
+ *exp_count = count;
+ }
}
}
+
+ return rc;
+}
+
+static int
+list_bucket_keys (struct command_environ *cenv)
+{
+ int rc = GDBMSHELL_OK;
+ int i;
+ hash_bucket *bucket = gdbm_file->bucket;
+
+ for (i = 0; i < bucket->count; i++)
+ {
+ if (bucket->h_table[i].hash_value != -1)
+ {
+ datum key, content;
+
+ key.dptr = _gdbm_read_entry (gdbm_file, i);
+ if (!key.dptr)
+ {
+ dberror (_("error reading entry %d"),i);
+ rc = GDBMSHELL_GDBM_ERR;
+ }
+ key.dsize = bucket->h_table[i].key_size;
+ content = gdbm_fetch (gdbm_file, key);
+ if (!content.dptr)
+ {
+ dberror ("%s", "gdbm_fetch");
+ terror ("%s", _("the key was:"));
+ datum_format (stderr, &key, dsdef[DS_KEY]);
+ rc = GDBMSHELL_GDBM_ERR;
+ }
+ else
+ {
+ datum_format (cenv->fp, &key, dsdef[DS_KEY]);
+ fputc (' ', cenv->fp);
+ datum_format (cenv->fp, &content, dsdef[DS_CONTENT]);
+ fputc ('\n', cenv->fp);
+ }
+ free (content.dptr);
+ }
+ }
return rc;
}
static int
-list_handler (struct command_param *param GDBM_ARG_UNUSED,
- struct command_environ *cenv)
+list_all_keys (struct command_environ *cenv)
{
datum key;
datum data;
@@ -1348,6 +1515,16 @@ list_handler (struct command_param *param GDBM_ARG_UNUSED,
}
return rc;
}
+
+static int
+list_handler (struct command_param *param GDBM_ARG_UNUSED,
+ struct command_environ *cenv)
+{
+ if (param->argc)
+ return list_bucket_keys (cenv);
+ else
+ return list_all_keys (cenv);
+}
/* quit - quit the program */
static int
@@ -1408,7 +1585,7 @@ import_handler (struct command_param *param,
int rc = GDBMSHELL_OK;
char *file_name;
- for (i = 0; i < param->argc; i++)
+ for (i = 1; i < param->argc; i++)
{
if (strcmp (PARAM_STRING (param, i), "replace") == 0)
flag = GDBM_REPLACE;
@@ -1460,7 +1637,6 @@ import_handler (struct command_param *param,
return GDBMSHELL_GDBM_ERR;
}
- free (file_name);
if (gdbm_setopt (gdbm_file, GDBM_GETDBNAME, &file_name, sizeof (file_name)))
{
dberror ("%s", "GDBM_GETDBNAME");
@@ -1595,6 +1771,7 @@ shell_handler (struct command_param *param,
if (pid == 0)
{
execv (argv[0], argv);
+ perror (argv[0]);
_exit (127);
}
@@ -1838,6 +2015,10 @@ static struct command command_tab[] = {
},
{
.name = "list",
+ .args = {
+ { "[bucket]", GDBM_ARG_STRING },
+ { NULL },
+ },
.doc = N_("list"),
.tok = T_CMD,
.begin = list_begin,
@@ -1921,7 +2102,7 @@ static struct command command_tab[] = {
{
.name = "bucket",
.args = {
- { N_("NUMBER"), GDBM_ARG_STRING },
+ { N_("[NUMBER]"), GDBM_ARG_STRING },
{ NULL }
},
.doc = N_("print a bucket"),
@@ -1941,6 +2122,15 @@ static struct command command_tab[] = {
.repeat = REPEAT_NEVER,
},
{
+ .name = "sibling",
+ .doc = N_("print sibling bucket"),
+ .tok = T_CMD,
+ .begin = print_sibling_bucket_begin,
+ .handler = print_current_bucket_handler,
+ .variadic = FALSE,
+ .repeat = REPEAT_NEVER,
+ },
+ {
.name = "dir",
.doc = N_("print hash directory"),
.tok = T_CMD,
@@ -2225,34 +2415,34 @@ help_handler (struct command_param *param GDBM_ARG_UNUSED,
struct command_environ *cenv)
{
struct command *cmd;
- FILE *fp = cenv->fp;
+ WORDWRAP_FILE wf;
+
+ fflush (cenv->fp);
+ wf = wordwrap_fdopen (fileno (cenv->fp));
for (cmd = command_tab; cmd->name; cmd++)
{
int i;
int n;
- int optoff;
-
- n = fprintf (fp, " %s", cmd->name);
- optoff = n;
-
+
+ wordwrap_set_left_margin (wf, 1);
+ wordwrap_set_right_margin (wf, 0);
+ n = strlen (cmd->name);
+ wordwrap_write (wf, cmd->name, n);
+
+ wordwrap_set_left_margin (wf, n + 2);
for (i = 0; i < NARGS && cmd->args[i].name; i++)
{
- if (n >= CMDCOLS)
- {
- fputc ('\n', fp);
- n = fprintf (fp, "%*.*s", optoff, optoff, "");
- }
- n += fprintf (fp, " %s", gettext (cmd->args[i].name));
+ wordwrap_printf (wf, " %s", gettext (cmd->args[i].name));
}
- if (n < CMDCOLS)
- fprintf (fp, "%*.s", CMDCOLS-n, "");
- else
- fprintf (fp, "\n%*.*s", CMDCOLS, CMDCOLS, "");
- fprintf (fp, " %s", gettext (cmd->doc));
- fputc ('\n', fp);
+ wordwrap_set_right_margin (wf, 0);
+ wordwrap_set_left_margin (wf, CMDCOLS);
+
+ wordwrap_printf (wf, " %s", gettext (cmd->doc));
+ wordwrap_flush (wf);
}
+ wordwrap_close (wf);
return 0;
}
@@ -2739,31 +2929,18 @@ timing_stop (struct timing *t)
t->sys = timeval_sub (r.ru_stime, t->sys);
}
-int
-run_command (struct command *cmd, struct gdbmarglist *arglist)
+static int
+argsprep (struct command *cmd, struct gdbmarglist *arglist,
+ struct command_param *param)
{
int i;
- struct gdbmarg *arg;
- char *pager = NULL;
+ struct gdbmarg *arg = arglist ? arglist->head : NULL;
char argbuf[128];
- size_t expected_lines, *expected_lines_ptr;
- FILE *pagfp = NULL;
- struct command_param param = HANDLER_PARAM_INITIALIZER;
- struct command_environ cenv = COMMAND_ENVIRON_INITIALIZER;
- int rc = 0;
- struct timing tm;
-
- variable_get ("pager", VART_STRING, (void**) &pager);
- arg = arglist ? arglist->head : NULL;
-
for (i = 0; cmd->args[i].name && arg; i++, arg = arg->next)
{
- if (param_push_arg (&param, arg, &cmd->args[i]))
- {
- param_free (&param);
- return 1;
- }
+ if (param_push_arg (param, arg, &cmd->args[i]))
+ return 1;
}
for (; cmd->args[i].name; i++)
@@ -2778,23 +2955,21 @@ run_command (struct command *cmd, struct gdbmarglist *arglist)
if (!interactive ())
{
terror (_("%s: not enough arguments"), cmd->name);
- param_free (&param);
return 1;
}
printf ("%s? ", argname);
fflush (stdout);
if (fgets (argbuf, sizeof argbuf, stdin) == NULL)
{
- terror (_("unexpected eof"));
- exit (EXIT_USAGE);
+ terror ("%s", _("unexpected eof"));
+ return 1;
}
trimnl (argbuf);
t = gdbmarg_string (estrdup (argbuf), &yylloc);
- if (param_push_arg (&param, t, &cmd->args[i]))
+ if (param_push_arg (param, t, &cmd->args[i]))
{
- param_free (&param);
gdbmarg_free (t);
return 1;
}
@@ -2803,87 +2978,123 @@ run_command (struct command *cmd, struct gdbmarglist *arglist)
if (arg && !cmd->variadic)
{
terror (_("%s: too many arguments"), cmd->name);
- param_free (&param);
return 1;
}
- /* Prepare for calling the handler */
- param_term (&param);
- param.vararg = arg;
- pagfp = NULL;
+ param_term (param);
+ param->vararg = arg;
- if (variable_is_true ("trace"))
+ return 0;
+}
+
+int
+run_command (struct command *cmd, struct gdbmarglist *arglist)
+{
+ int i;
+ char *pager = NULL;
+ size_t expected_lines, *expected_lines_ptr;
+ FILE *pagfp = NULL;
+ struct command_param param = HANDLER_PARAM_INITIALIZER;
+ struct command_environ cenv = COMMAND_ENVIRON_INITIALIZER;
+ int rc = 0;
+ struct timing tm;
+
+ if (argsprep (cmd, arglist, &param))
+ rc = GDBMSHELL_ERR;
+ else
{
- fprintf (stderr, "+ %s", cmd->name);
- for (i = 0; i < param.argc; i++)
- {
- format_arg (param.argv[i], &cmd->args[i], stderr);
- }
+ variable_get ("pager", VART_STRING, (void**) &pager);
- if (param.vararg)
+ /* Prepare for calling the handler */
+ pagfp = NULL;
+
+ if (variable_is_true ("trace"))
{
- struct gdbmarg *arg;
- for (arg = param.vararg; arg; arg = arg->next)
- format_arg (arg, NULL, stderr);
+ fprintf (stderr, "+ %s", cmd->name);
+ for (i = 0; i < param.argc; i++)
+ {
+ format_arg (param.argv[i], &cmd->args[i], stderr);
+ }
+
+ if (param.vararg)
+ {
+ struct gdbmarg *arg;
+ for (arg = param.vararg; arg; arg = arg->next)
+ format_arg (arg, NULL, stderr);
+ }
+ fputc ('\n', stderr);
}
- fputc ('\n', stderr);
- }
-
- expected_lines = 0;
- expected_lines_ptr = (interactive () && pager) ? &expected_lines : NULL;
- rc = 0;
- if (!(cmd->begin && (rc = cmd->begin (&param, &cenv, expected_lines_ptr)) != 0))
- {
- if (pager && expected_lines > get_screen_lines ())
+
+ expected_lines = 0;
+ expected_lines_ptr = (interactive () && pager) ? &expected_lines : NULL;
+ rc = 0;
+ if (!(cmd->begin &&
+ (rc = cmd->begin (&param, &cenv, expected_lines_ptr)) != 0))
{
- pagfp = popen (pager, "w");
- if (pagfp)
- cenv.fp = pagfp;
+ if (pager && expected_lines > get_screen_lines ())
+ {
+ pagfp = popen (pager, "w");
+ if (pagfp)
+ cenv.fp = pagfp;
+ else
+ {
+ terror (_("cannot run pager `%s': %s"), pager,
+ strerror (errno));
+ pager = NULL;
+ cenv.fp = stdout;
+ }
+ }
else
+ cenv.fp = stdout;
+
+ timing_start (&tm);
+ rc = cmd->handler (&param, &cenv);
+ timing_stop (&tm);
+ if (cmd->end)
+ cmd->end (cenv.data);
+ else if (cenv.data)
+ free (cenv.data);
+
+ if (variable_is_true ("timing"))
{
- terror (_("cannot run pager `%s': %s"), pager,
- strerror (errno));
- pager = NULL;
- cenv.fp = stdout;
- }
+ fprintf (cenv.fp, "[%s r=%lu.%06lu u=%lu.%06lu s=%lu.%06lu]\n",
+ cmd->name,
+ tm.real.tv_sec, tm.real.tv_usec,
+ tm.user.tv_sec, tm.user.tv_usec,
+ tm.sys.tv_sec, tm.sys.tv_usec);
+ }
+
+ if (pagfp)
+ pclose (pagfp);
}
- else
- cenv.fp = stdout;
+ }
- timing_start (&tm);
- rc = cmd->handler (&param, &cenv);
- timing_stop (&tm);
- if (cmd->end)
- cmd->end (cenv.data);
- else if (cenv.data)
- free (cenv.data);
+ param_free (&param);
- if (variable_is_true ("timing"))
+ switch (rc)
+ {
+ case GDBMSHELL_OK:
+ last_cmd = cmd;
+ if (arglist->head != last_args.head)
{
- fprintf (cenv.fp, "[%s r=%lu.%06lu u=%lu.%06lu s=%lu.%06lu]\n",
- cmd->name,
- tm.real.tv_sec, tm.real.tv_usec,
- tm.user.tv_sec, tm.user.tv_usec,
- tm.sys.tv_sec, tm.sys.tv_usec);
+ gdbmarglist_free (&last_args);
+ last_args = *arglist;
}
-
- if (pagfp)
- pclose (pagfp);
- }
+ rc = 0;
+ break;
- param_free (&param);
-
- last_cmd = cmd;
- if (arglist->head != last_args.head)
- {
- gdbmarglist_free (&last_args);
- last_args = *arglist;
- }
+ case GDBMSHELL_GDBM_ERR:
+ gdbmarglist_free (arglist);
+ if (variable_has_errno ("errorexit", gdbm_errno))
+ rc = 1;
+ else
+ rc = 0;
+ break;
- if (rc == GDBMSHELL_GDBM_ERR && variable_has_errno ("errorexit", gdbm_errno))
- rc = 1;
- else
- rc = 0;
+ default:
+ gdbmarglist_free (arglist);
+ rc = 0;
+ }
return rc;
}
diff --git a/src/gdbmtool.c b/tools/gdbmtool.c
index 512dd88..7e793b4 100644
--- a/src/gdbmtool.c
+++ b/tools/gdbmtool.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -222,8 +222,12 @@ gdbmtool_init (void *data, instream_t *pinstr)
break;
default:
- terror (_("unknown option %c; try `%s -h' for more info"),
- optopt, progname);
+ if (optopt == 0)
+ terror (_("unknown option %s; try `%s -h' for more info"),
+ argv[optind-1], progname);
+ else
+ terror (_("unknown option %c; try `%s -h' for more info"),
+ optopt, progname);
exit (EXIT_USAGE);
}
diff --git a/src/gdbmtool.h b/tools/gdbmtool.h
index 7462f8e..748a210 100644
--- a/src/gdbmtool.h
+++ b/tools/gdbmtool.h
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -68,37 +68,9 @@ typedef struct locus gdbm_yyltype_t;
} \
while (0)
-#define YY_LOCATION_PRINT(File, Loc) \
- do \
- { \
- if ((Loc).beg.col == 0) \
- fprintf (File, "%s:%u", \
- (Loc).beg.file, \
- (Loc).beg.line); \
- else if (strcmp ((Loc).beg.file, (Loc).end.file)) \
- fprintf (File, "%s:%u.%u-%s:%u.%u", \
- (Loc).beg.file, \
- (Loc).beg.line, (Loc).beg.col, \
- (Loc).end.file, \
- (Loc).end.line, (Loc).end.col); \
- else if ((Loc).beg.line != (Loc).end.line) \
- fprintf (File, "%s:%u.%u-%u.%u", \
- (Loc).beg.file, \
- (Loc).beg.line, (Loc).beg.col, \
- (Loc).end.line, (Loc).end.col); \
- else if ((Loc).beg.col != (Loc).end.col) \
- fprintf (File, "%s:%u.%u-%u", \
- (Loc).beg.file, \
- (Loc).beg.line, (Loc).beg.col, \
- (Loc).end.col); \
- else \
- fprintf (File, "%s:%u.%u", \
- (Loc).beg.file, \
- (Loc).beg.line, \
- (Loc).beg.col); \
- } \
- while (0)
+#define YY_LOCATION_PRINT(File, Loc) locus_print (File, &(Loc))
+void locus_print (FILE *fp, struct locus const *loc);
void vlerror (struct locus *loc, const char *fmt, va_list ap);
void lerror (struct locus *loc, const char *fmt, ...)
GDBM_PRINTFLIKE (2, 3);
diff --git a/src/gdbmtool.supp b/tools/gdbmtool.supp
index 247be73..247be73 100644
--- a/src/gdbmtool.supp
+++ b/tools/gdbmtool.supp
diff --git a/src/gram.y b/tools/gram.y
index 561de89..6b09152 100644
--- a/src/gram.y
+++ b/tools/gram.y
@@ -1,6 +1,6 @@
%{
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -62,6 +62,15 @@ struct dsegm *dsdef[DS_MAX];
struct command *cmd;
}
+%destructor { gdbmarglist_free (&$$); } <arglist>
+%destructor { gdbmarg_free ($$); } <arg>
+%destructor { kvlist_free ($$.head); } <kvlist>
+%destructor { kvlist_free ($$); } <kvpair>
+%destructor { slist_free ($$.head); } <slist>
+%destructor { free ($$); } <string>
+%destructor { dsegm_list_free ($$); } <dsegm>
+%destructor { dsegm_list_free ($$.head); } <dsegmlist>
+
%%
input : /* empty */
diff --git a/src/input-argv.c b/tools/input-argv.c
index acb6544..0142de3 100644
--- a/src/input-argv.c
+++ b/tools/input-argv.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2018-2021 Free Software Foundation, Inc.
+ Copyright (C) 2018-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/input-file.c b/tools/input-file.c
index 0c83555..a386e19 100644
--- a/src/input-file.c
+++ b/tools/input-file.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2018-2021 Free Software Foundation, Inc.
+ Copyright (C) 2018-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/input-null.c b/tools/input-null.c
index 7bc95ce..22a547b 100644
--- a/src/input-null.c
+++ b/tools/input-null.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2018-2021 Free Software Foundation, Inc.
+ Copyright (C) 2018-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/input-rl.c b/tools/input-rl.c
index 6d91bd5..3565079 100644
--- a/src/input-rl.c
+++ b/tools/input-rl.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2016-2021 Free Software Foundation, Inc.
+ Copyright (C) 2016-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/input-std.c b/tools/input-std.c
index ca3059c..5e60e0d 100644
--- a/src/input-std.c
+++ b/tools/input-std.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2016-2021 Free Software Foundation, Inc.
+ Copyright (C) 2016-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/lex.l b/tools/lex.l
index b2d6539..fb1e49e 100644
--- a/src/lex.l
+++ b/tools/lex.l
@@ -1,6 +1,6 @@
%{
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -64,9 +64,40 @@ advance_line (void)
void string_begin (void);
void string_add (const char *s, int l);
void string_addc (int c);
-char *string_end (void);
+char *string_end (int empty_null);
int unescape (int c);
+struct file_name
+{
+ struct file_name *next;
+ char str[1];
+};
+
+static struct file_name *file_head;
+
+static void
+file_names_free (void)
+{
+ while (file_head)
+ {
+ struct file_name *next = file_head->next;
+ free (file_head);
+ file_head = next;
+ }
+}
+
+char *
+file_name_alloc (char const *s)
+{
+ struct file_name *f = emalloc (sizeof (*f) + strlen (s));
+ strcpy (f->str, s);
+ f->next = file_head;
+ if (!file_head)
+ atexit (file_names_free);
+ file_head = f;
+ return f->str;
+}
+
int
interactive (void)
{
@@ -123,7 +154,7 @@ input_context_push (instream_t input)
cp = ecalloc (1, sizeof (*cp));
cp->locus = yylloc;
- cp->point.file = estrdup (instream_name (input));
+ cp->point.file = file_name_alloc (instream_name (input));
cp->point.line = 1;
cp->point.col = 0;
@@ -149,8 +180,6 @@ input_context_pop (void)
if (!context_tos)
return 1;
instream_close (context_tos->input);
- free (context_tos->point.file);
- memset (&yylloc, 0, sizeof (yylloc));
cp = context_tos->parent;
free (context_tos);
context_tos = cp;
@@ -312,7 +341,7 @@ pad { return T_PAD; }
<STR,MLSTR>{
[^\\\"\n]*\" { if (yyleng > 1)
string_add (yytext, yyleng - 1);
- yylval.string = string_end ();
+ yylval.string = string_end (FALSE);
BEGIN (CMD);
return T_WORD; }
[^\\\"\n]*\\\n { advance_line ();
@@ -347,8 +376,8 @@ pad { return T_PAD; }
BEGIN (INITIAL);
advance_line ();
yyless (0);
- yylval.string = string_end ();
- return T_WORD;
+ if ((yylval.string = string_end (TRUE)) != NULL)
+ return T_WORD;
}
. string_addc (yytext[0]);
}
@@ -446,28 +475,38 @@ string_addc (int c)
strseg_attach (seg);
}
+/*
+ * Compose the collected string segments into a nul-terminated string.
+ * Return the allocated string.
+ * If EMPTY_NULL is TRUE and the resulting string length is 0, return
+ * NULL instead.
+ */
char *
-string_end (void)
+string_end (int empty_null)
{
- int len = 1;
+ int len = 0;
struct strseg *seg;
char *ret, *p;
for (seg = strseg_head; seg; seg = seg->next)
len += seg->len;
- ret = emalloc (len);
- p = ret;
- for (seg = strseg_head; seg; )
+ if (len == 0 && empty_null)
+ ret = NULL;
+ else
{
- struct strseg *next = seg->next;
- memcpy (p, seg->ptr, seg->len);
- p += seg->len;
- free (seg);
- seg = next;
+ ret = emalloc (len + 1);
+ p = ret;
+ for (seg = strseg_head; seg; )
+ {
+ struct strseg *next = seg->next;
+ memcpy (p, seg->ptr, seg->len);
+ p += seg->len;
+ free (seg);
+ seg = next;
+ }
+ *p = 0;
}
- *p = 0;
-
strseg_head = strseg_tail = NULL;
return ret;
@@ -499,6 +538,39 @@ escape (int c)
}
return 0;
}
+
+void
+locus_print (FILE *fp, struct locus const *loc)
+{
+ if (loc->beg.file)
+ {
+ if (loc->beg.col == 0)
+ fprintf (fp, "%s:%u",
+ loc->beg.file,
+ loc->beg.line);
+ else if (strcmp (loc->beg.file, loc->end.file))
+ fprintf (fp, "%s:%u.%u-%s:%u.%u",
+ loc->beg.file,
+ loc->beg.line, loc->beg.col,
+ loc->end.file,
+ loc->end.line, loc->end.col);
+ else if (loc->beg.line != loc->end.line)
+ fprintf (fp, "%s:%u.%u-%u.%u",
+ loc->beg.file,
+ loc->beg.line, loc->beg.col,
+ loc->end.line, loc->end.col);
+ else if (loc->beg.col != loc->end.col)
+ fprintf (fp, "%s:%u.%u-%u",
+ loc->beg.file,
+ loc->beg.line, loc->beg.col,
+ loc->end.col);
+ else
+ fprintf (fp, "%s:%u.%u",
+ loc->beg.file,
+ loc->beg.line,
+ loc->beg.col);
+ }
+}
void
vlerror (struct locus *loc, const char *fmt, va_list ap)
@@ -679,4 +751,4 @@ make_prompt (void)
return ret;
}
-
+
diff --git a/src/mem.c b/tools/mem.c
index 8b2da75..ac3f4c6 100644
--- a/src/mem.c
+++ b/tools/mem.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/parseopt.c b/tools/parseopt.c
index efa12c8..2d646ff 100644
--- a/src/parseopt.c
+++ b/tools/parseopt.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -189,8 +189,8 @@ add_options (struct gdbm_option *options)
#endif
}
-int
-parseopt_first (int pc, char **pv, struct gdbm_option *opts)
+void
+parseopt_free (void)
{
free (option_tab);
option_tab = NULL;
@@ -202,6 +202,12 @@ parseopt_first (int pc, char **pv, struct gdbm_option *opts)
long_options = NULL;
long_option_count = long_option_max = 0;
#endif
+}
+
+int
+parseopt_first (int pc, char **pv, struct gdbm_option *opts)
+{
+ parseopt_free ();
add_options (opts);
add_options (parseopt_default_options);
opterr = 0;
@@ -210,50 +216,159 @@ parseopt_first (int pc, char **pv, struct gdbm_option *opts)
return parseopt_next ();
}
-#define LMARGIN 2
-#define DESCRCOLUMN 30
-#define RMARGIN 79
-#define GROUPCOLUMN 2
-#define USAGECOLUMN 13
-
-static void
-indent (size_t start, size_t col)
+static unsigned short_opt_col = 2;
+static unsigned long_opt_col = 6;
+static unsigned doc_opt_col = 2; /* FIXME: Not used: there are no doc
+ options in this implementation */
+static unsigned header_col = 1;
+static unsigned opt_doc_col = 29;
+static unsigned usage_indent = 12;
+static unsigned rmargin = 79;
+
+static unsigned dup_args = 0;
+static unsigned dup_args_note = 1;
+
+enum usage_var_type
+ {
+ usage_var_column,
+ usage_var_bool
+ };
+
+struct usage_var_def
{
- for (; start < col; start++)
- putchar (' ');
-}
+ char *name;
+ unsigned *valptr;
+ enum usage_var_type type;
+};
+
+static struct usage_var_def usage_var[] = {
+ { "short-opt-col", &short_opt_col, usage_var_column },
+ { "header-col", &header_col, usage_var_column },
+ { "opt-doc-col", &opt_doc_col, usage_var_column },
+ { "usage-indent", &usage_indent, usage_var_column },
+ { "rmargin", &rmargin, usage_var_column },
+ { "dup-args", &dup_args, usage_var_bool },
+ { "dup-args-note", &dup_args_note, usage_var_bool },
+ { "long-opt-col", &long_opt_col, usage_var_column },
+ { "doc-opt-col", &doc_opt_col, usage_var_column },
+ { NULL }
+};
static void
-print_option_descr (const char *descr, size_t lmargin, size_t rmargin)
+set_usage_var (char const *text, char **end)
{
- if (!(descr && descr[0]))
- return;
- descr = gettext (descr);
- while (*descr)
+ struct usage_var_def *p;
+ int boolval = 1;
+ char const *prog_name = parseopt_program_name ? parseopt_program_name : progname;
+ size_t len = strcspn (text, ",=");
+ char *endp;
+
+ if (len > 3 && memcmp (text, "no-", 3) == 0)
{
- size_t s = 0;
- size_t i;
- size_t width = rmargin - lmargin;
-
- for (i = 0; ; i++)
+ text += 3;
+ len -= 3;
+ boolval = 0;
+ }
+
+ for (p = usage_var; p->name; p++)
+ {
+ if (strlen (p->name) == len && memcmp (p->name, text, len) == 0)
+ break;
+ }
+
+ endp = (char*) text + len;
+ if (p)
+ {
+ if (p->type == usage_var_bool)
{
- if (descr[i] == 0 || descr[i] == ' ' || descr[i] == '\t')
+ if (*endp == '=')
{
- if (i > width)
- break;
- s = i;
- if (descr[i] == 0)
- break;
+ if (prog_name)
+ fprintf (stderr, "%s: ", prog_name);
+ fprintf (stderr,
+ _("error in ARGP_HELP_FMT: improper usage of [no-]%s\n"),
+ p->name);
+ endp = strchr (text + len, ',');
}
+ else
+ *p->valptr = boolval;
}
- fwrite (descr, 1, s, stdout);
- fputc ('\n', stdout);
- descr += s;
- if (*descr)
+ else if (*endp == '=')
{
- indent (0, lmargin);
- descr++;
+ unsigned long val;
+
+ errno = 0;
+ val = strtoul (text + len + 1, &endp, 10);
+ if (errno || (*endp && *endp != ','))
+ {
+ if (prog_name)
+ fprintf (stderr, "%s: ", prog_name);
+ fprintf (stderr,
+ _("error in ARGP_HELP_FMT: bad value for %s"),
+ p->name);
+ if (endp)
+ {
+ fprintf (stderr, _(" (near %s)"), endp);
+ }
+ fputc ('\n', stderr);
+ }
+ else if (val > UINT_MAX)
+ {
+ if (prog_name)
+ fprintf (stderr, "%s: ", prog_name);
+ fprintf (stderr,
+ _("error in ARGP_HELP_FMT: %s value is out of range\n"),
+ p->name);
+ }
+ else
+ *p->valptr = val;
}
+ else
+ {
+ if (prog_name)
+ fprintf (stderr, "%s: ", prog_name);
+ fprintf (stderr,
+ _("%s: ARGP_HELP_FMT parameter requires a value\n"),
+ p->name);
+ }
+ }
+ else
+ {
+ if (prog_name)
+ fprintf (stderr, "%s: ", prog_name);
+ fprintf (stderr,
+ _("%s: Unknown ARGP_HELP_FMT parameter\n"),
+ text);
+ }
+ *end = endp;
+}
+
+static void
+init_usage_vars (void)
+{
+ char *fmt, *p;
+
+ fmt = getenv ("ARGP_HELP_FMT");
+ if (!fmt || !*fmt)
+ return;
+
+ while (1)
+ {
+ set_usage_var (fmt, &p);
+ if (*p == 0)
+ break;
+ else if (*p == ',')
+ p++;
+ else
+ {
+ char const *prog_name = parseopt_program_name ? parseopt_program_name : progname;
+ if (prog_name)
+ fprintf (stderr, "%s: ", prog_name);
+ fprintf (stderr, _("ARGP_HELP_FMT: missing delimiter near %s\n"),
+ p);
+ break;
+ }
+ fmt = p;
}
}
@@ -263,8 +378,20 @@ void (*parseopt_help_hook) (FILE *stream);
static int argsused;
+static int
+print_arg (WORDWRAP_FILE wf, struct gdbm_option *opt, int delim)
+{
+ if (opt->opt_arg)
+ {
+ argsused = 1;
+ return wordwrap_printf (wf, "%c%s", delim,
+ opt->opt_arg[0] ? gettext (opt->opt_arg) : "");
+ }
+ return 0;
+}
+
size_t
-print_option (size_t num)
+print_option (WORDWRAP_FILE wf, size_t num)
{
struct gdbm_option *opt = option_tab + num;
size_t next, i;
@@ -273,9 +400,15 @@ print_option (size_t num)
if (IS_GROUP_HEADER (opt))
{
- indent (0, GROUPCOLUMN);
- print_option_descr (opt->opt_descr, GROUPCOLUMN, RMARGIN);
- putchar ('\n');
+ wordwrap_set_left_margin (wf, header_col);
+ wordwrap_set_right_margin (wf, rmargin);
+ if (opt->opt_descr[0])
+ {
+ wordwrap_putc (wf, '\n');
+ wordwrap_puts (wf, gettext (opt->opt_descr));
+ wordwrap_putc (wf, '\n');
+ }
+ wordwrap_putc (wf, '\n');
return num + 1;
}
@@ -287,55 +420,55 @@ print_option (size_t num)
if (opt->opt_flags & PARSEOPT_HIDDEN)
return next;
+ wordwrap_set_left_margin (wf, short_opt_col);
w = 0;
for (i = num; i < next; i++)
{
if (IS_VALID_SHORT_OPTION (&option_tab[i]))
{
- if (w == 0)
- {
- indent (0, LMARGIN);
- w = LMARGIN;
- }
- else
- w += printf (", ");
- w += printf ("-%c", option_tab[i].opt_short);
+ if (w)
+ wordwrap_write (wf, ", ", 2);
+ wordwrap_printf (wf, "-%c", option_tab[i].opt_short);
delim = ' ';
+ if (dup_args)
+ print_arg (wf, opt, delim);
+ w = 1;
}
}
+
#ifdef HAVE_GETOPT_LONG
for (i = num; i < next; i++)
{
if (IS_VALID_LONG_OPTION (&option_tab[i]))
{
- if (w == 0)
- {
- indent (0, LMARGIN);
- w = LMARGIN;
- }
- else
- w += printf (", ");
- w += printf ("--%s", option_tab[i].opt_long);
- delim = '=';
+ if (w)
+ wordwrap_write (wf, ", ", 2);
+ wordwrap_set_left_margin (wf, long_opt_col);
+ w = 0;
+ break;
}
}
-#else
- if (!w)
- return next;
-#endif
- if (opt->opt_arg)
- {
- argsused = 1;
- w += printf ("%c%s", delim, gettext (opt->opt_arg));
- }
- if (w >= DESCRCOLUMN)
+ for (; i < next; i++)
{
- putchar ('\n');
- w = 0;
+ if (IS_VALID_LONG_OPTION (&option_tab[i]))
+ {
+ if (w)
+ wordwrap_write (wf, ", ", 2);
+ wordwrap_printf (wf, "--%s", option_tab[i].opt_long);
+ delim = '=';
+ if (dup_args)
+ print_arg (wf, opt, delim);
+ w = 1;
+ }
}
- indent (w, DESCRCOLUMN);
- print_option_descr (opt->opt_descr, DESCRCOLUMN, RMARGIN);
-
+#endif
+ if (!dup_args)
+ print_arg (wf, opt, delim);
+
+ wordwrap_set_left_margin (wf, opt_doc_col);
+ if (opt->opt_descr[0])
+ wordwrap_puts (wf, gettext (opt->opt_descr));
+
return next;
}
@@ -343,40 +476,54 @@ void
parseopt_print_help (void)
{
unsigned i;
-
+ WORDWRAP_FILE wf;
+
argsused = 0;
- printf ("%s %s [%s]... %s\n", _("Usage:"),
- parseopt_program_name ? parseopt_program_name : progname,
- _("OPTION"),
- gettext (parseopt_program_args));
- print_option_descr (parseopt_program_doc, 0, RMARGIN);
- putchar ('\n');
+ init_usage_vars ();
+ wf = wordwrap_fdopen (1);
+
+ wordwrap_printf (wf, "%s %s [%s]... %s\n", _("Usage:"),
+ parseopt_program_name ? parseopt_program_name : progname,
+ _("OPTION"),
+ (parseopt_program_args && parseopt_program_args[0])
+ ? gettext (parseopt_program_args) : "");
+
+ wordwrap_set_right_margin (wf, rmargin);
+ if (parseopt_program_doc && parseopt_program_doc[0])
+ wordwrap_puts (wf, gettext (parseopt_program_doc));
+ wordwrap_para (wf);
+
sort_all_options ();
for (i = 0; i < option_count; )
{
- i = print_option (i);
+ i = print_option (wf, i);
}
- putchar ('\n');
+ wordwrap_para (wf);
+
#ifdef HAVE_GETOPT_LONG
- if (argsused)
+ if (argsused && dup_args_note)
{
- print_option_descr (N_("Mandatory or optional arguments to long options are also mandatory or optional for any corresponding short options."), 0, RMARGIN);
- putchar ('\n');
+ wordwrap_set_left_margin (wf, 0);
+ wordwrap_set_right_margin (wf, rmargin);
+ wordwrap_puts (wf, _("Mandatory or optional arguments to long options are also mandatory or optional for any corresponding short options."));
+ wordwrap_para (wf);
}
#endif
if (parseopt_help_hook)
- parseopt_help_hook (stdout);
+ parseopt_help_hook (stdout);//FIXME
+ wordwrap_set_left_margin (wf, 0);
+ wordwrap_set_right_margin (wf, rmargin);
/* TRANSLATORS: The placeholder indicates the bug-reporting address
for this package. Please add _another line_ saying
"Report translation bugs to <...>\n" with the address for translation
bugs (typically your translation team's web or email address). */
- printf (_("Report bugs to %s.\n"), program_bug_address);
+ wordwrap_printf (wf, _("Report bugs to %s.\n"), program_bug_address);
#ifdef PACKAGE_URL
- printf (_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
+ wordwrap_printf (wf, _("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
#endif
}
@@ -404,34 +551,21 @@ cmpidx_long (const void *a, const void *b)
void
print_usage (void)
{
+ WORDWRAP_FILE wf;
unsigned i;
- unsigned n;
- char buf[RMARGIN+1];
unsigned *idxbuf;
unsigned nidx;
-
-#define FLUSH \
- do \
- { \
- buf[n] = 0; \
- printf ("%s\n", buf); \
- n = USAGECOLUMN; \
- memset (buf, ' ', n); \
- } \
- while (0)
-#define ADDC(c) \
- do \
- { \
- if (n == RMARGIN) FLUSH; \
- buf[n++] = c; \
- } \
- while (0)
+ init_usage_vars ();
+
idxbuf = ecalloc (option_count, sizeof (idxbuf[0]));
- n = snprintf (buf, sizeof buf, "%s %s ", _("Usage:"),
- parseopt_program_name ? parseopt_program_name : progname);
-
+ wf = wordwrap_fdopen (1);
+ wordwrap_set_right_margin (wf, rmargin);
+ wordwrap_printf (wf, "%s %s ", _("Usage:"),
+ parseopt_program_name ? parseopt_program_name : progname);
+ wordwrap_next_left_margin (wf, usage_indent);
+
/* Print a list of short options without arguments. */
for (i = nidx = 0; i < option_count; i++)
if (IS_VALID_SHORT_OPTION (&option_tab[i]) && !option_tab[i].opt_arg)
@@ -441,13 +575,12 @@ print_usage (void)
{
qsort (idxbuf, nidx, sizeof (idxbuf[0]), cmpidx_short);
- ADDC ('[');
- ADDC ('-');
+ wordwrap_puts (wf, "[-");
for (i = 0; i < nidx; i++)
{
- ADDC (option_tab[idxbuf[i]].opt_short);
+ wordwrap_putc (wf, option_tab[idxbuf[i]].opt_short);
}
- ADDC (']');
+ wordwrap_putc (wf, ']');
}
/* Print a list of short options with arguments. */
@@ -465,17 +598,14 @@ print_usage (void)
{
struct gdbm_option *opt = option_tab + idxbuf[i];
const char *arg = gettext (opt->opt_arg);
- size_t len = 5 + strlen (arg) + 1;
-
- if (n + len > RMARGIN) FLUSH;
- buf[n++] = ' ';
- buf[n++] = '[';
- buf[n++] = '-';
- buf[n++] = opt->opt_short;
- buf[n++] = ' ';
- strcpy (&buf[n], arg);
- n += strlen (arg);
- buf[n++] = ']';
+
+ wordwrap_word_start (wf);
+ wordwrap_puts (wf, " [-");
+ wordwrap_putc (wf, opt->opt_short);
+ wordwrap_putc (wf, ' ');
+ wordwrap_puts (wf, arg);
+ wordwrap_putc (wf, ']');
+ wordwrap_word_end (wf);
}
}
@@ -495,26 +625,21 @@ print_usage (void)
{
struct gdbm_option *opt = option_tab + idxbuf[i];
const char *arg = opt->opt_arg ? gettext (opt->opt_arg) : NULL;
- size_t len = 5 + strlen (opt->opt_long)
- + (arg ? 1 + strlen (arg) : 0);
- if (n + len > RMARGIN) FLUSH;
- buf[n++] = ' ';
- buf[n++] = '[';
- buf[n++] = '-';
- buf[n++] = '-';
- strcpy (&buf[n], opt->opt_long);
- n += strlen (opt->opt_long);
+
+ wordwrap_word_start (wf);
+ wordwrap_write (wf, " [--", 4);
+ wordwrap_puts (wf, opt->opt_long);
if (opt->opt_arg)
{
- buf[n++] = '=';
- strcpy (&buf[n], arg);
- n += strlen (arg);
+ wordwrap_putc (wf, '=');
+ wordwrap_write (wf, arg, strlen (arg));
}
- buf[n++] = ']';
+ wordwrap_putc (wf, ']');
+ wordwrap_word_end (wf);
}
}
#endif
- FLUSH;
+ wordwrap_close (wf);
free (idxbuf);
}
@@ -539,7 +664,7 @@ print_version_only (void)
/* TRANSLATORS: Translate "(C)" to the copyright symbol
(C-in-a-circle), if this symbol is available in the user's
locale. Otherwise, do not translate "(C)"; leave it as-is. */
- printf (version_etc_copyright, _("(C)"), "2011-2019");
+ printf (version_etc_copyright, _("(C)"), "2011-2022");
putchar ('\n');
puts (license_text);
putchar ('\n');
@@ -570,7 +695,7 @@ handle_option (int c)
}
int
-parseopt_next ()
+parseopt_next (void)
{
int rc;
@@ -583,5 +708,9 @@ parseopt_next ()
#endif
}
while (handle_option (rc));
+
+ if (rc == EOF || rc == '?')
+ parseopt_free ();
+
return rc;
}
diff --git a/src/progname.c b/tools/progname.c
index 63bbd15..235e713 100644
--- a/src/progname.c
+++ b/tools/progname.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/util.c b/tools/util.c
index 509524a..f652fa7 100644
--- a/src/util.c
+++ b/tools/util.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/src/var.c b/tools/var.c
index 7b8f3f6..ccec5b9 100644
--- a/src/var.c
+++ b/tools/var.c
@@ -1,5 +1,5 @@
/* This file is part of GDBM, the GNU data base manager.
- Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ Copyright (C) 1990-2022 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -41,6 +41,7 @@ struct variable
void *data;
int (*sethook) (struct variable *, union value *);
int (*typeconv) (struct variable *, int, void **);
+ void (*freehook) (void *);
};
static int open_sethook (struct variable *, union value *);
@@ -53,6 +54,7 @@ static int coalesce_sethook (struct variable *var, union value *v);
static int cachesize_sethook (struct variable *var, union value *v);
static int errormask_sethook (struct variable *var, union value *v);
static int errormask_typeconv (struct variable *var, int type, void **retptr);
+static void errormask_freehook (void *);
static int errorexit_sethook (struct variable *var, union value *v);
static struct variable vartab[] = {
@@ -180,13 +182,15 @@ static struct variable vartab[] = {
.name = "errorexit",
.type = VART_STRING,
.sethook = errorexit_sethook,
- .typeconv = errormask_typeconv
+ .typeconv = errormask_typeconv,
+ .freehook = errormask_freehook
},
{
.name = "errormask",
.type = VART_STRING,
.sethook = errormask_sethook,
- .typeconv = errormask_typeconv
+ .typeconv = errormask_typeconv,
+ .freehook = errormask_freehook
},
{
.name = "timing",
@@ -510,6 +514,11 @@ variables_free (void)
if (vp->type == VART_STRING && (vp->flags & VARF_SET))
free (vp->v.string);
vp->v.string = NULL;
+ if (vp->freehook && vp->data)
+ {
+ vp->freehook (vp->data);
+ vp->data = NULL;
+ }
vp->flags &= ~VARF_SET;
}
}
@@ -809,6 +818,12 @@ errormask_typeconv (struct variable *var, int type, void **retptr)
return VAR_ERR_BADTYPE;
}
+static void
+errormask_freehook (void *data)
+{
+ free (data);
+}
+
static int
errorexit_sethook (struct variable *var, union value *v)
{
diff --git a/tools/wordwrap.c b/tools/wordwrap.c
new file mode 100644
index 0000000..526ab04
--- /dev/null
+++ b/tools/wordwrap.c
@@ -0,0 +1,635 @@
+/* This file is part of GDBM, the GNU data base manager.
+ Copyright (C) 2011-2022 Free Software Foundation, Inc.
+
+ GDBM is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GDBM 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "autoconf.h"
+#include "gdbmapp.h"
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <wctype.h>
+#include <wchar.h>
+#include <errno.h>
+#include <limits.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+
+#define UNSET ((unsigned)-1)
+#define ISSET(c) (c != UNSET)
+#define DEFAULT_RIGHT_MARGIN 80
+
+struct wordwrap_file
+{
+ int fd; /* Output file descriptor. */
+ unsigned left_margin; /* Left margin. */
+ unsigned right_margin; /* Right margin. */
+ char *buffer; /* Output buffer. */
+ size_t bufsize; /* Size of buffer in bytes. */
+ unsigned offset; /* Offset of the writing point in the buffer */
+ unsigned column; /* Number of screen column, i.e. the (multibyte)
+ character corresponding to the offset. */
+ unsigned last_ws; /* Offset of the beginning of the last whitespace
+ sequence written to the buffer. */
+ unsigned ws_run; /* Number of characters in the whitespace sequence. */
+ unsigned word_start; /* Start of a sequence that should be treated as a
+ single word. */
+ unsigned next_left_margin; /* Left margin to be set after next flush. */
+
+ int indent; /* If 1, reindent next line. */
+ int unibyte; /* 0: Normal operation.
+ 1: multibyte functions disabled for this line. */
+ int err; /* Last errno value associated with this file. */
+};
+
+/*
+ * Reset the file for the next input line.
+ */
+static void
+wordwrap_line_init (WORDWRAP_FILE wf)
+{
+ wf->offset = wf->column = wf->left_margin;
+ wf->last_ws = UNSET;
+ wf->ws_run = 0;
+ wf->unibyte = 0;
+}
+
+/*
+ * Detect the value of the right margin. Use TIOCGWINSZ ioctl, the COLUMNS
+ * environment variable, or the default value, in that order.
+ */
+static unsigned
+detect_right_margin (WORDWRAP_FILE wf)
+{
+ struct winsize ws;
+ unsigned r = 0;
+
+ ws.ws_col = ws.ws_row = 0;
+ if ((ioctl (wf->fd, TIOCGWINSZ, (char *) &ws) < 0) || ws.ws_col == 0)
+ {
+ char *p = getenv ("COLUMNS");
+ if (p)
+ {
+ unsigned long n;
+ char *ep;
+ errno = 0;
+ n = strtoul (p, &ep, 10);
+ if (!(errno || *ep || n > UINT_MAX))
+ r = n;
+ }
+ else
+ r = DEFAULT_RIGHT_MARGIN;
+ }
+ else
+ r = ws.ws_col;
+ return r;
+}
+
+/*
+ * Create a wordwrap file operating on file descriptor FD.
+ * In the contrast to the libc fdopen, the descriptor is dup'ed.
+ * Left margin is set to 0, right margin is auto detected.
+ */
+WORDWRAP_FILE
+wordwrap_fdopen (int fd)
+{
+ struct wordwrap_file *wf;
+ int ec;
+
+ if ((wf = calloc (1, sizeof (*wf))) == NULL)
+ return NULL;
+ if ((wf->fd = dup (fd)) == -1)
+ {
+ ec = errno;
+ free (wf);
+ errno = ec;
+ return NULL;
+ }
+
+ wf->last_ws = UNSET;
+ wf->word_start = UNSET;
+ wf->next_left_margin = UNSET;
+
+ wordwrap_set_right_margin (wf, 0);
+
+ return wf;
+}
+
+/*
+ * Close the descriptor associated with the wordwrap file, and deallocate
+ * the memory.
+ */
+int
+wordwrap_close (WORDWRAP_FILE wf)
+{
+ int rc;
+
+ rc = wordwrap_flush (wf);
+ close (wf->fd);
+ free (wf->buffer);
+ free (wf);
+
+ return rc;
+}
+
+/*
+ * Return true if wordwrap file is at the beginning of line.
+ */
+int
+wordwrap_at_bol (WORDWRAP_FILE wf)
+{
+ return wf->column == wf->left_margin;
+}
+
+/*
+ * Return true if wordwrap file is at the end of line.
+ */
+int
+wordwrap_at_eol (WORDWRAP_FILE wf)
+{
+ return wf->column == wf->right_margin;
+}
+
+/*
+ * Write SIZE bytes from the buffer to the file.
+ * Return the number of bytes written.
+ * Set the file error indicator on error.
+ */
+static ssize_t
+full_write (WORDWRAP_FILE wf, size_t size)
+{
+ ssize_t total = 0;
+
+ while (total < size)
+ {
+ ssize_t n = write (wf->fd, wf->buffer + total, size - total);
+ if (n == -1)
+ {
+ wf->err = errno;
+ break;
+ }
+ if (n == 0)
+ {
+ wf->err = ENOSPC;
+ break;
+ }
+ total += n;
+ }
+ return total;
+}
+
+/*
+ * A fail-safe version of mbrtowc. If the call to mbrtowc, fails,
+ * switches the stream to the unibyte mode.
+ */
+static inline size_t
+safe_mbrtowc (WORDWRAP_FILE wf, wchar_t *wc, const char *s, mbstate_t *ps)
+{
+ if (!wf->unibyte)
+ {
+ size_t n = mbrtowc (wc, s, MB_CUR_MAX, ps);
+ if (n == (size_t) -1 || n == (size_t) -2)
+ wf->unibyte = 1;
+ else
+ return n;
+ }
+ *wc = *(unsigned char *)s;
+ return 1;
+}
+
+/*
+ * Return length of the whitespace prefix in STR.
+ */
+static size_t
+wsprefix (WORDWRAP_FILE wf, char const *str, size_t size)
+{
+ size_t i;
+ mbstate_t mbs;
+ wchar_t wc;
+
+ memset (&mbs, 0, sizeof (mbs));
+ for (i = 0; i < size; )
+ {
+ size_t n = safe_mbrtowc (wf, &wc, &str[i], &mbs);
+
+ if (!iswblank (wc))
+ break;
+
+ i += n;
+ }
+
+ return i;
+}
+
+/*
+ * Rescan N bytes from the current buffer from the current offset.
+ * Update offset, column, and whitespace segment counters.
+ */
+static void
+wordwrap_rescan (WORDWRAP_FILE wf, size_t n)
+{
+ mbstate_t mbs;
+ wchar_t wc;
+
+ wordwrap_line_init (wf);
+
+ memset (&mbs, 0, sizeof (mbs));
+ while (wf->offset < n)
+ {
+ size_t n = safe_mbrtowc (wf, &wc, &wf->buffer[wf->offset], &mbs);
+
+ if (iswblank (wc))
+ {
+ if (ISSET (wf->last_ws) && wf->last_ws + wf->ws_run == wf->offset)
+ wf->ws_run++;
+ else
+ {
+ wf->last_ws = wf->offset;
+ wf->ws_run = 1;
+ }
+ }
+
+ wf->offset += n;
+ wf->column++;
+ }
+}
+
+/*
+ * Flush SIZE bytes from the current buffer to the FD.
+ * Reinitialize WF for the next line.
+ */
+static int
+flush_line (WORDWRAP_FILE wf, size_t size)
+{
+ ssize_t n;
+ size_t len;
+ char c;
+
+ if (ISSET (wf->last_ws) && size == wf->last_ws + wf->ws_run)
+ len = wf->last_ws;
+ else
+ len = size;
+
+ if (len >= wf->left_margin && wf->offset > wf->left_margin)
+ {
+ n = full_write (wf, len);
+ if (n == -1)
+ return -1;
+
+ if (n < len)
+ {
+ //FIXME: this breaks column and ws tracking
+ abort ();
+ }
+ }
+
+ c = '\n';
+ write (wf->fd, &c, 1);
+
+ if (ISSET (wf->next_left_margin))
+ {
+ wf->left_margin = wf->next_left_margin;
+ wf->next_left_margin = UNSET;
+ }
+
+ n = wf->offset - size;
+ if (n > 0)
+ {
+ size_t wsn;
+
+ wsn = wsprefix (wf, wf->buffer + size, n);
+
+ size += wsn;
+ n -= wsn;
+
+ if (n)
+ memmove (wf->buffer + wf->left_margin, wf->buffer + size, n);
+ }
+
+ if (wf->indent)
+ {
+ memset (wf->buffer, ' ', wf->left_margin);
+ wf->indent = 0;
+ }
+ wordwrap_rescan (wf, wf->left_margin + n);
+
+ return 0;
+}
+
+/*
+ * Flush the wordwrap file buffer.
+ */
+int
+wordwrap_flush (WORDWRAP_FILE wf)
+{
+ if (wf->offset > wf->left_margin)
+ return flush_line (wf, wf->offset);
+ return 0;
+}
+
+/*
+ * Return error indicator (last errno value).
+ */
+int
+wordwrap_error (WORDWRAP_FILE wf)
+{
+ return wf->err;
+}
+
+/*
+ * Set left margin value.
+ */
+int
+wordwrap_set_left_margin (WORDWRAP_FILE wf, unsigned left)
+{
+ int bol;
+
+ if (left == wf->left_margin)
+ return 0;
+ else if (left >= wf->right_margin)
+ {
+ wf->err = errno = EINVAL;
+ return -1;
+ }
+
+ bol = wordwrap_at_bol (wf);
+ wf->left_margin = left;
+ wf->indent = 1;
+ if (left < wf->offset)
+ {
+ if (!bol)
+ flush_line (wf, wf->offset);//FIXME: remove trailing ws
+ }
+ else
+ {
+ if (left > wf->offset)
+ memset (wf->buffer + wf->offset, ' ', wf->left_margin - wf->offset);
+ }
+ wordwrap_line_init (wf);
+
+ return 0;
+}
+
+/*
+ * Set delayed left margin value. The new value will take effect after the
+ * current line is flushed.
+ */
+int
+wordwrap_next_left_margin (WORDWRAP_FILE wf, unsigned left)
+{
+ if (left == wf->left_margin)
+ return 0;
+ else if (left >= wf->right_margin)
+ {
+ wf->err = errno = EINVAL;
+ return -1;
+ }
+ wf->next_left_margin = left;
+ wf->indent = 1;
+ return 0;
+}
+
+/*
+ * Set right margin for the file.
+ */
+int
+wordwrap_set_right_margin (WORDWRAP_FILE wf, unsigned right)
+{
+ if (right == 0)
+ right = detect_right_margin (wf);
+
+ if (right == wf->right_margin)
+ return 0;
+ else if (right <= wf->left_margin)
+ {
+ wf->err = errno = EINVAL;
+ return -1;
+ }
+ else
+ {
+ char *p;
+ size_t size;
+
+ if (right < wf->offset)
+ {
+ if (wordwrap_flush (wf))
+ return -1;
+ }
+
+ size = MB_CUR_MAX * (right + 1);
+ p = realloc (wf->buffer, size);
+ if (!p)
+ {
+ wf->err = errno;
+ return -1;
+ }
+
+ wf->buffer = p;
+ wf->bufsize = size;
+ wf->right_margin = right;
+ }
+
+ return 0;
+}
+
+/*
+ * Mark current output position as the word start. The normal whitespace
+ * splitting is disabled, until wordwrap_word_end is called or the current
+ * buffer is flushed, whichever happens first.
+ * The functions wordwrap_word_start () / wordwrap_word_end () mark the
+ * sequence of characters that should not be split on whitespace, such as,
+ * e.g. option name with argument in help output ("-f FILE").
+ */
+void
+wordwrap_word_start (WORDWRAP_FILE wf)
+{
+ wf->word_start = wf->offset;
+}
+
+/*
+ * Disable word marker.
+ */
+void
+wordwrap_word_end (WORDWRAP_FILE wf)
+{
+ wf->word_start = UNSET;
+}
+
+/*
+ * Write LEN bytes from the string STR to the wordwrap file.
+ */
+int
+wordwrap_write (WORDWRAP_FILE wf, char const *str, size_t len)
+{
+ size_t i;
+ wchar_t wc;
+ mbstate_t mbs;
+
+ memset (&mbs, 0, sizeof (mbs));
+ for (i = 0; i < len; )
+ {
+ size_t n = safe_mbrtowc (wf, &wc, &str[i], &mbs);
+
+ if (wf->column + 1 == wf->right_margin || wc == '\n')
+ {
+ size_t len;
+
+ if (ISSET (wf->word_start))
+ {
+ len = wf->word_start;
+ wf->word_start = UNSET;
+ }
+ else if (!iswspace (wc) && ISSET (wf->last_ws))
+ len = wf->last_ws;
+ else
+ len = wf->offset;
+
+ flush_line (wf, len);
+ if (wc == '\n')
+ {
+ i += n;
+ continue;
+ }
+ }
+
+ if (iswblank (wc))
+ {
+ if (wf->offset == wf->left_margin)
+ {
+ /* Skip leading whitespace */
+ i += n;
+ continue;
+ }
+ else if (ISSET (wf->last_ws) && wf->last_ws + wf->ws_run == wf->offset)
+ wf->ws_run++;
+ else
+ {
+ wf->last_ws = wf->offset;
+ wf->ws_run = 1;
+ }
+ }
+
+ memcpy (wf->buffer + wf->offset, str + i, n);
+
+ wf->offset += n;
+ wf->column++;
+
+ i += n;
+ }
+ return 0;
+}
+
+/*
+ * Write a nul-terminated string STR to the file (terminating \0 not
+ * included).
+ */
+int
+wordwrap_puts (WORDWRAP_FILE wf, char const *str)
+{
+ return wordwrap_write (wf, str, strlen (str));
+}
+
+/*
+ * Write a single character to the file.
+ */
+int
+wordwrap_putc (WORDWRAP_FILE wf, int c)
+{
+ char ch = c;
+ return wordwrap_write (wf, &ch, 1);
+}
+
+/*
+ * Insert a paragraph (empty line).
+ */
+int
+wordwrap_para (WORDWRAP_FILE wf)
+{
+ return wordwrap_write (wf, "\n\n", 2);
+}
+
+/*
+ * Format AP according to FMT and write the formatted output to file.
+ */
+int
+wordwrap_vprintf (WORDWRAP_FILE wf, char const *fmt, va_list ap)
+{
+ size_t buflen = 64;
+ char *buf;
+ ssize_t n;
+ int rc;
+
+ buf = malloc (buflen);
+ if (!buf)
+ {
+ wf->err = errno;
+ return -1;
+ }
+
+ for (;;)
+ {
+ va_list aq;
+
+ va_copy (aq, ap);
+ n = vsnprintf (buf, buflen, fmt, aq);
+ va_end (aq);
+
+ if (n < 0 || n >= buflen || !memchr(buf, '\0', n + 1))
+ {
+ char *p;
+
+ if ((size_t) -1 / 3 * 2 <= buflen)
+ {
+ wf->err = ENOMEM;
+ free (buf);
+ return -1;
+ }
+
+ buflen += (buflen + 1) / 2;
+ p = realloc (buf, buflen);
+ if (!p)
+ {
+ wf->err = errno;
+ free (buf);
+ return -1;
+ }
+ buf = p;
+ }
+ else
+ break;
+ }
+
+ rc = wordwrap_write (wf, buf, n);
+ free (buf);
+ return rc;
+}
+
+/*
+ * Format argument list according to FMT and write the formatted output
+ * to file.
+ */
+int
+wordwrap_printf (WORDWRAP_FILE wf, char const *fmt, ...)
+{
+ va_list ap;
+ int rc;
+
+ va_start (ap, fmt);
+ rc = wordwrap_vprintf (wf, fmt, ap);
+ va_end (ap);
+ return rc;
+}
+
+
+

Return to:

Send suggestions and report system problems to the System administrator.