[med-svn] [kmer-tools] 02/07: Imported Upstream version 0~20150520+2004

Afif Elghraoui afif-guest at moszumanska.debian.org
Fri May 22 09:26:54 UTC 2015


This is an automated email from the git hooks/post-receive script.

afif-guest pushed a commit to branch master
in repository kmer-tools.

commit af8304a09c24472c7c175965a74a6cb93596e104
Author: Afif Elghraoui <afif at ghraoui.name>
Date:   Thu May 21 19:39:56 2015 -0700

    Imported Upstream version 0~20150520+2004
---
 README.atac                          |  100 +
 README.compiling                     |   34 +-
 README.meryl                         |  156 ++
 atac-driver/atac.pl                  |   40 +-
 configure.sh                         |    4 +-
 libkmer/Make.include                 |    6 +-
 libkmer/percentCovered.C             |   66 -
 libseq/fastaFile.C                   |    4 +-
 libseq/fastqFile.C                   |    2 +
 libutil/intervalList.H               |    2 +-
 libutil/kazlib/Make.include          |   27 -
 libutil/kazlib/blast.pl              |   33 -
 libutil/kazlib/dict.c                | 1238 ----------
 libutil/kazlib/dict.h                |  142 --
 libutil/kazlib/docs/CHANGES          |  290 ---
 libutil/kazlib/docs/MUST_READ        |   25 -
 libutil/kazlib/docs/README           |   66 -
 libutil/kazlib/docs/docs.ist         |    4 -
 libutil/kazlib/docs/docs.ltx         | 4155 ----------------------------------
 libutil/kazlib/drivers/dict-main.c   |  300 ---
 libutil/kazlib/drivers/except-main.c |   57 -
 libutil/kazlib/drivers/hash-main.c   |  187 --
 libutil/kazlib/drivers/list-main.c   |  152 --
 libutil/kazlib/drivers/sfx-main.c    |   41 -
 libutil/kazlib/except.c              |  347 ---
 libutil/kazlib/except.h              |  147 --
 libutil/kazlib/hash.c                |  837 -------
 libutil/kazlib/hash.h                |  238 --
 libutil/kazlib/list.c                |  766 -------
 libutil/kazlib/list.h                |  152 --
 libutil/kazlib/sfx.c                 | 1138 ----------
 libutil/kazlib/sfx.h                 |   46 -
 meryl/Make.include                   |   19 +-
 meryl/asmMerQC.C                     |  396 ----
 {libkmer => meryl}/kmer-mask.C       |    0
 meryl/m-heap.H                       |  152 --
 meryl/m.C                            |  118 -
 meryl/mapMers-depth.C                |  216 +-
 meryl/maskMers.C                     |    7 +
 meryl/testPositionBias.C             |  117 -
 40 files changed, 465 insertions(+), 11362 deletions(-)

diff --git a/README.atac b/README.atac
new file mode 100644
index 0000000..0156bfa
--- /dev/null
+++ b/README.atac
@@ -0,0 +1,100 @@
+atac - assembly-to-assembly comparasion, comparative mapping between
+       two genome assemblies (same species), or between two different
+       genomes (cross species).
+
+Described in the publication: 
+
+S. Istrail, et al. "Whole-genome shotgun assembly and comparison of
+human genome assemblies" PNAS, Feb 2004; 101: 1916-1921 
+
+Copyright (C) 2002, and GNU GPL,       PE Corporation (NY) through the Celera Genomics Group
+Copyright (C) 2003-2004, and GNU GPL,  Applied Biosystems
+Copyright (C) 2004-2015, and GNU GPL,  Brian Walenz
+
+=======================================================================
+
+Content:
+
+I.   What is atac?
+II.  Command line usage
+III. Input/Output
+IV.  Affiliated tools
+V.   Terms of use
+VI.  Support
+
+
+I.   What is atac?
+
+atac computes a one-to-one pairwise alignment of large DNA sequences.  It first
+finds the unique k-mers in each sequence, chains them to larger blocks, and
+fills in spaces between blocks.  It was written primarily to transfer annotations
+between different assemblies of the human genome.
+
+The output is a set of ungapped 'matches', and a set of gapped 'runs' formed from
+the matches.  Each match or run associates one sequence with the other sequence.
+The association is 'unique', in that there is no other (sizeable) associations
+for either sequence.  Thus, large repeats and duplications are not present in
+the output - they appear as unmapped regions.
+
+Though the output is always pairwise, atac can cache intermediate results to speed
+a comparisons of multiple sequences.
+
+
+II. Command line usage
+
+A simple invocation:
+
+atac.pl \
+  -dir      ecoli-k-vs-o \
+  -meryldir atac-sequences \
+  -id1 K -seq2 /data/references/ecolik12.fasta \
+  -id2 O -seq1 /data/references/ecolio157.fasta
+
+Run with no options for a list of parameters.
+
+See http://kmer.sourceforge.net/wiki/index.php/Getting_Started_with_ATAC for more.
+
+
+III. Input/Output
+
+Input is two multi-FASTA files.  The files must be uncompressed.
+
+Output is in two self-documenting text files, reported at the end of the run:
+
+  Finished!  Output is:
+    matches and runs -- /work/ecoli-k-vs-o/KvsO.atac
+    clumps           -- /work/ecoli-k-vs-o/KvsO.*clump*.atac
+
+
+IV. Affiliated tools
+
+N/A
+
+
+V. Terms of use
+
+This program 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 of the License, or (at your
+option) any later version.
+
+This program 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 (LICENSE.txt) a copy of the GNU General
+Public License along with this program; if not, you can obtain one from
+http://www.gnu.org/licenses/gpl.txt or by writing to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+VI. Support 
+
+Brian Walenz (brianwalenz at users.sourceforge.net)
+
+Please check the parent project's Sourceforge page at
+http://kmer.sourceforge.net for details and updates.
+
+
+Last updated: May 11, 2015
diff --git a/README.compiling b/README.compiling
index f8acebb..1112da8 100644
--- a/README.compiling
+++ b/README.compiling
@@ -10,9 +10,6 @@ There!  That wasn't tough at all, was it!?
 The software is compiled in place, and installed into a directory named
 after the OS/architecture, for example, Linux-amd64.
 
-ESTmapper and A2Amapper are NOT installed by this process; see section 3
-below.
-
 ----------------------------------------
 Detailed Instructions:
 
@@ -33,20 +30,21 @@ python and gmake.
 Python (http://www.python.org/) is a freely available programming
 language.  It is frequently installed by many OS installations.
 
+It is only needed by ATAC/A2Amapper.  If python is not installed,
+ATAC/A2Amapper will not be built.
+
 Version 2.4+ is recommended.
 Version 2.3 has seen limited testing and seems to work.
 Version 2.2 might work, but is unsupported.
 
-Python is only needed by ATAC/A2Amapper.  If python is not installed,
-ATAC/A2Amapper will not be built.
-
 0.2)  gmake.
 
 The GNU make program (gmake) is used to build the software.  The BSD
 make will not work.
 
-Version 3.81 is strongly recommended.
-Version 3.80 works, but needs to be patched.  See build/patches/README.
+gmake v 3.81 or higher is REQUIRED.  This shouldn't be a problem, as that
+was released in April 2006.  It _was_ a problem when most of this software
+was written.
 
 ----------
 1)  Configuration
@@ -74,26 +72,20 @@ in an unusual location, edit the script.
 
 % gmake
 
-gmake v 3.81 or higher is REQUIRED.
+If gmake crashes or returns
 
-If this crashes or returns
         gmake: *** No rule to make target `.all', needed by `all'.  Stop.
-then you unfortunately need to update your gmake to version 3.81.
+
+then you need to update your gmake to at least version 3.81.
 
 ----------
 3)  Installation
 
-'gmake install' will copy all the executables into an OS/architecture
-specific 'bin' directory, for example, into FreeBSD-amd64/bin or
-Linux-i686/bin.  ESTmapper and ATAC/A2Amapper are NOT installed by this
-process.
-
-To install ESTmapper, 'cd ESTmapper && sh install.sh location'.  This
-will copy the ESTmapper binaries to 'location/bin' and 'location/lib'.
+% gmake install
 
-To install ATAC/A2Amapper, 'cd atac-driver && sh install.sh location'.
-This will copy the ATAC/A2Amapper binaries to 'location/bin' and
-'location/lib'.
+will copy all executables, libraries and header files into an
+OS/architecture specific directory.  Binaries, for example, will be in
+FreeBSD-amd64/bin or Linux-i686/bin.
 
 ----------
 4)  Other build targets
diff --git a/README.meryl b/README.meryl
new file mode 100644
index 0000000..64d8e0d
--- /dev/null
+++ b/README.meryl
@@ -0,0 +1,156 @@
+meryl - in- and out-of-core kmer counting and utilities.
+
+Copyright (C) 2002, and GNU GPL,       PE Corporation (NY) through the Celera Genomics Group
+Copyright (C) 2003-2004, and GNU GPL,  Applied Biosystems
+Copyright (C) 2004-2015, and GNU GPL,  Brian Walenz
+
+=======================================================================
+
+Content:
+
+I.   What is meryl?
+II.  Command line usage
+III. Input/Output
+IV.  Affiliated tools
+V.   Terms of use
+VI.  Support
+
+
+I.   What is meryl?
+
+meryl computes the kmer content of genomic sequences.  Kmer content is
+represented as a list of kmers and the number of times each occurs in the
+input sequences.  The kmer can be restricted to only the forward kmer, only
+the reverse kmer, or the canonical kmer (lexicographically smaller of the forward and reverse
+kmer at each location).  Meryl can report the histogram of counts,
+the list of kmers and their counts, or can perform mathematical and set operations
+on the processed data files.
+
+The meryl process can run in one large memory batch, in many small memory batches, or under SGE
+control, all with or without using multiple CPU cores.
+
+The maximum kmer size is effectively unlimited, but set at compile time.  Larger kmers use more
+memory, and are inefficient for counting smaller kmers, and since most applications have involved
+kmers less than 32 bases, the default compile time limit is 32 bases.
+
+The output of meryl is two binary files, called a meryl database, which can be
+quickly dumped to provide a histogram of counts, or the actual counts.
+A C++ library is supplied for direct access to the files.
+
+The meryl program can perform many mathematical and set operations on
+multiple database files: min, minexist, max, add, sub,abs, and, nand, or,
+xor, lessthan, lessthanorequal, greaterthan, greatherthanorequal, and equal.
+
+The ATAC pipeline uses meryl to find the unique kmers in two sequences ('lessthanorequal 1')
+then computes the 'and' of them to find the unique kmers that exist in
+both sequences.
+
+
+II. Command line usage
+
+A simple invocation:
+
+meryl -B -C -m 22 -s /data/references/ecolik12.fasta -o ecoli-22mers
+
+The above command will build (-B) a kmer database (-o ecoli-22mers)
+of the canonical (-C) 22-mers (-m 22) in the FASTA file ecolik12.fasta.
+The two output files are ecoli-22mers.mcidx and ecoli-22mers.mcdat.
+
+meryl -Dh -s ecoli-22mers > ecoli-22mers.fasta
+
+The above command will dump a histogram of the kmers in the 'ecoli-22mers'
+database.  The histogram has four columns:
+
+  kmer-count  number-of-kmers  fraction-distinct  fraction-total
+  [example]
+
+The first line tells us that there are X kmers that occur exactly once, that
+these sequences make up XX% of lthe kmer composition, and that these sequences
+account for YY% of all the kmers in the input.
+
+meryl -M and -s seq1 -s seq2 -o both
+
+The above command will report the kmers that are present in both meryl databases
+'seq1' and 'seq1', writing them to a new meryl database 'both'.
+
+Run with no options for a list of parameters.
+
+See http://kmer.sourceforge.net/wiki/index.php/Getting_Started_with_Meryl for more.
+
+
+III. Input/Output
+
+For counting kmers, input is exactly one multi-FASTA or FASTQ file.  The
+file must be uncompressed.
+
+For processing databases, an input database is supplied by the prefix of the two
+files:  the prefix of 'ecoli-ms22.mcidx' and 'ecoli-ms22.mcdat' is 'ecoli-ms22'.
+
+Output is a 'meryl database' consisting of two binary files, '*.mcidx' and '*.mcdat'.
+
+Output of the histogram command is a single text file to stdout.
+
+Output of the threshold dump is a multi-FASTA file, with the name of the sequence
+set to the count, and the sequence set to the kmer.
+
+
+IV. Affiliated tools
+
+Several additional kmer counting and analysis programs are included in the meryl package.
+
+simple         - The obvious array based kmer counter.  It will allocate 4 bytes per
+                 kmer; k=16 will need 16 GB to run.
+
+                 NEEDS UPDATE
+
+mapMers        - Report stats of mapping kmers to sequences.  Three modes of opeeration:
+                  -stats     repotrs mean, min and max for each sequence, along with a
+                             log2 histogram of the counts
+                  -regions   reports regions with kmer coverage
+                  -details   reports for each kmer in the sequence, the forward and reverse
+                             count in the database
+
+mapMers-depth  - Reports, for each sequence ordinal 's' and position 'p':
+                  -count     the count (c) of the single kmer that starts at position (p).
+                             Format: 's p c'
+                  -depth     the number (n) of kmers that span position (p).  Format: 's p n'
+                  -stats     the min (m), max (M), ave (a) count of all mers that span
+                             position (p).  Format: 's p m M a t n'
+                             (also reports total count (t) and number of kmers (n))
+
+kmer-mask      - Mask and filter set of sequences (presumed to be reads) by kmer content.
+                 Masking can be done to retain novel sequence not in the database, or to retain
+                 confirmed sequence present in the database.  Filtering will segregate sequences
+                 fully, partially or not masked.
+
+existDB        - (installed by libkmer) Management of existDB files.
+positionDB     - (installed by libkmer) Management of posDB files.
+
+
+V. Terms of use
+
+This program 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 of the License, or (at your
+option) any later version.
+
+This program 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 (LICENSE.txt) a copy of the GNU General
+Public License along with this program; if not, you can obtain one from
+http://www.gnu.org/licenses/gpl.txt or by writing to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+VI. Support 
+
+Brian Walenz (brianwalenz at users.sourceforge.net)
+
+Please check the parent project's Sourceforge page at
+http://kmer.sourceforge.net for details and updates.
+
+
+Last updated: May 13, 2015
diff --git a/atac-driver/atac.pl b/atac-driver/atac.pl
index 8368b01..7386fe3 100755
--- a/atac-driver/atac.pl
+++ b/atac-driver/atac.pl
@@ -318,14 +318,46 @@ sub findSources {
     die "File '$seq1' doesn't exist for alias $id1.\n" if (! -e $seq1);
     die "File '$seq2' doesn't exist for alias $id2.\n" if (! -e $seq2);
     
-    system("ln -s $seq1 $MERYLdir/$id1.fasta") if (! -e "$MERYLdir/$id1.fasta");
-    system("ln -s $seq2 $MERYLdir/$id2.fasta") if (! -e "$MERYLdir/$id2.fasta");
+    #system("ln -s $seq1 $MERYLdir/$id1.fasta") if (! -e "$MERYLdir/$id1.fasta");
+    #system("ln -s $seq2 $MERYLdir/$id2.fasta") if (! -e "$MERYLdir/$id2.fasta");
 
-    system("ln -s ${seq1}idx $MERYLdir/$id1.fastaidx") if (! -e "$MERYLdir/$id1.fastaidx") && (-e "${seq1}idx");
-    system("ln -s ${seq2}idx $MERYLdir/$id2.fastaidx") if (! -e "$MERYLdir/$id2.fastaidx") && (-e "${seq2}idx");
+    #system("ln -s ${seq1}idx $MERYLdir/$id1.fastaidx") if (! -e "$MERYLdir/$id1.fastaidx") && (-e "${seq1}idx");
+    #system("ln -s ${seq2}idx $MERYLdir/$id2.fastaidx") if (! -e "$MERYLdir/$id2.fastaidx") && (-e "${seq2}idx");
+
+    removeNewLines($seq1, "$MERYLdir/$id1.fasta");
+    removeNewLines($seq2, "$MERYLdir/$id2.fasta");
+}
+
+
+
+sub removeNewLines ($$) {
+    my $in = shift @_;
+    my $ot = shift @_;
+
+    return  if (-e "$ot");
+
+    print STDERR "Rewriting '$in' to '$ot', removing newlines.\n";
+
+    open(F, "< $in") or die "Failed to open '$in' for reading: $!\n";
+    open(O, "> $ot") or die "Failed to open '$ot' for writing: $!\n";
+
+    $_ = <F>;  print O $_;
+
+    while (<F>) {
+        if (m/^>/) {
+            print O "\n";
+        } else {
+            chomp;
+        }
+
+        print O $_;
+    }
+    close(O);
+    close(F);
 }
 
 
+
 #  Check that meryl is finished for each of the inputs
 #
 sub countMers {
diff --git a/configure.sh b/configure.sh
index b27fd8a..95a0bf0 100755
--- a/configure.sh
+++ b/configure.sh
@@ -367,8 +367,8 @@ PERL              := /usr/bin/perl
 .O                := .o
 CLD               := \${CC}
 CXXLD             := \${CXX}
-CCDEP		  := gcc -MM -MG
-CXXDEP	          := g++ -MM -MG
+CCDEP             := \${CC} -MM -MG
+CXXDEP	          := \${CXX} -MM -MG
 CLIBS             += -lm -lbz2
 CXXLIBS           += -lm -lbz2
 PYTHON            := $PYTHON
diff --git a/libkmer/Make.include b/libkmer/Make.include
index 36ee1c5..7e678d9 100644
--- a/libkmer/Make.include
+++ b/libkmer/Make.include
@@ -20,16 +20,14 @@ src := $/existDB-create-from-fasta.C \
        $/positionDB.C \
        $/positionDB.H
 
-$/.CXX_SRCS   := $(filter %.C,${src}) $/driver-existDB.C $/driver-posDB.C $/percentCovered.C $/kmer-mask.C
+$/.CXX_SRCS   := $(filter %.C,${src}) $/driver-existDB.C $/driver-posDB.C
 $/.CXX_INCS   := $(filter %.H,${src})
-$/.CXX_EXES   := $/existDB $/positionDB $/percentCovered $/kmer-mask
+$/.CXX_EXES   := $/existDB $/positionDB
 $/.CXX_LIBS   := $/libkmer.a
 $/.CLEAN      := $/*.o
 
 $/libkmer.a:      $(filter %.o,${src:.C=.o})
 $/existDB:        $/driver-existDB.o $/libkmer.a ${LIBMERYL/}libmeryl.a ${LIBSEQ/}libseq.a ${LIBBIO/}libbio.a ${LIBUTL/}libutil.a 
 $/positionDB:     $/driver-posDB.o   $/libkmer.a ${LIBMERYL/}libmeryl.a ${LIBSEQ/}libseq.a ${LIBBIO/}libbio.a ${LIBUTL/}libutil.a 
-$/percentCovered: $/percentCovered.o $/libkmer.a ${LIBMERYL/}libmeryl.a ${LIBSEQ/}libseq.a ${LIBBIO/}libbio.a ${LIBUTL/}libutil.a 
-$/kmer-mask:      $/kmer-mask.o      $/libkmer.a ${LIBMERYL/}libmeryl.a ${LIBSEQ/}libseq.a ${LIBBIO/}libbio.a ${LIBUTL/}libutil.a 
 
 $(eval $/%.d $/%.o:    CXXFLAGS+= -I${LIBMERYL/} -I${LIBBIO/} -I${LIBSEQ/} -I${LIBUTL/})
diff --git a/libkmer/percentCovered.C b/libkmer/percentCovered.C
deleted file mode 100644
index 947ff30..0000000
--- a/libkmer/percentCovered.C
+++ /dev/null
@@ -1,66 +0,0 @@
-#include "util++.H"
-#include "bio++.H"
-#include "existDB.H"
-
-#include "seqCache.H"
-#include "seqStream.H"
-#include "merStream.H"
-
-int
-main(int argc, char **argv) {
-  char  *merFile   = 0L;
-  char  *queryFile = 0L;
-
-  int arg=1;
-  while (arg < argc) {
-    if        (strcmp(argv[arg], "-m") == 0) {
-      merFile = argv[++arg];
-    } else if (strcmp(argv[arg], "-q") == 0) {
-      queryFile = argv[++arg];
-    } else {
-      fprintf(stderr, "Unknown arg '%s'\n", argv[arg]);
-    }
-    arg++;
-  }
-
-  existDB      *E = new existDB(merFile, 22, existDBnoFlags, 0, ~uint32ZERO);
-  seqCache     *Q = new seqCache(queryFile);
-  seqInCore    *S = Q->getSequenceInCore();
-
-  intervalList<uint64>  IL;
-  speedCounter          SC(" %8f frags (%8.5f frags/sec)\r", 1, 1000, true);
-
-  while (S) {
-    merStream     *MS = new merStream(new kMerBuilder(22),
-                                      new seqStream(S->sequence(), S->sequenceLength()),
-                                      true, true);
-
-    IL.clear();
-
-    while (MS->nextMer()) {
-      if (E->exists(MS->theFMer())) {
-        IL.add(MS->thePositionInSequence(), 22);
-      }
-    }
-
-    IL.merge();
-
-    if (IL.sumOfLengths() > 0) {
-      fprintf(stdout, "%5.2f\n",
-              100.0 * IL.sumOfLengths() / (double)S->sequenceLength());
-    }
-
-    delete MS;
-    delete S;
-
-    SC.tick();
-
-    S = Q->getSequenceInCore();
-  }
-
-  delete Q;
-  delete E;
-
-  return(0);
-}
-
diff --git a/libseq/fastaFile.C b/libseq/fastaFile.C
index a55bf38..b2cfaaa 100644
--- a/libseq/fastaFile.C
+++ b/libseq/fastaFile.C
@@ -320,9 +320,11 @@ fastaFile::clear(void) {
 
   strcpy(_typename, "FastA");
 
+  _randomAccessSupported = true;
+
   _numberOfSequences = 0;
 
-  _rb                = 0L;
+  _rb = 0L;
   memset(&_header, 0, sizeof(fastaFileHeader));
   _index = 0L;
   _names = 0L;
diff --git a/libseq/fastqFile.C b/libseq/fastqFile.C
index 8042582..14dffb5 100644
--- a/libseq/fastqFile.C
+++ b/libseq/fastqFile.C
@@ -317,6 +317,8 @@ fastqFile::clear(void) {
 
   strcpy(_typename, "Fastq");
 
+  _randomAccessSupported = true;
+
   _numberOfSequences = 0;
 
   _rb                = 0L;
diff --git a/libutil/intervalList.H b/libutil/intervalList.H
index 315cace..79f8036 100644
--- a/libutil/intervalList.H
+++ b/libutil/intervalList.H
@@ -77,7 +77,7 @@ public:
     _list     = 0L;
 
 #ifdef _GLIBCXX_PARALLEL
-    //  Don't use the parallel sort, not with the expense of starting threads.
+    //  Don't use the parallel sort, not worth the expense of starting threads.
     __gnu_sequential::sort(id, id + idlen);
 #else
     std::sort(id, id + idlen);
diff --git a/libutil/kazlib/Make.include b/libutil/kazlib/Make.include
deleted file mode 100644
index 7ecb369..0000000
--- a/libutil/kazlib/Make.include
+++ /dev/null
@@ -1,27 +0,0 @@
-# -*- makefile -*-
-
-src    := $/dict.c \
-          $/dict.h \
-          $/except.c \
-          $/except.h \
-          $/hash.c \
-          $/hash.h \
-          $/list.c \
-          $/list.h \
-          $/sfx.c \
-          $/sfx.h
-
-tst    := $/dict-main.c \
-          $/except-main.c \
-          $/hash-main.c \
-          $/list-main.c \
-          $/sfx-main.c
-
-$/.C_SRCS    :=$(filter %.c,${src})
-$/.CXX_SRCS  :=$(filter %.C,${src})
-$/.CXX_LIBS  :=$/libkaz.a
-
-$/.CLEAN := $/*.o
-
-$/libkaz.a: ${$/.C_SRCS:.c=.o} ${$/.CXX_SRCS:.C=.o}
-
diff --git a/libutil/kazlib/blast.pl b/libutil/kazlib/blast.pl
deleted file mode 100755
index 63351c9..0000000
--- a/libutil/kazlib/blast.pl
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/perl
-
-#
-# This is a program whose output can be piped to the test drivers for
-# hash.c and dict.c. It inserts a bunch of data and then deletes it all.
-#
-# The $modulus should be a prime number. This ensures that the $modulus - 1
-# generated keys are all distinct.  The $factor_i and $factor_d values need not
-# be prime, but it should not be a multiple of $modulus (including zero),
-# otherwise a sequence of duplicate keys will be generated: choose numbers
-# in the range [1, $modulus - 1]. Choosing 1 means that
-# insertions (or deletions) will take place in order.
-# The purpose of using the prime modulus number is to generate a repeatable
-# sequence of unique keys that is (possibly) not in sorted order.
-#
-
-# $modulus = 200003;
-# $factor_i = 100;
-# $factor_d = 301;
-
-$modulus = 6113;
-$factor_i = 1669;
-$factor_d = 2036;
-
-for ($i = 1; $i < $modulus; $i++) {
-    printf("a %d %d\n", ($i * $factor_i) % $modulus, $i);
-}
-
-for ($i = 1; $i < $modulus; $i++) {
-    printf("d %d\n", ($i * $factor_d) % $modulus);
-}
-
-print "t\nq\n"
diff --git a/libutil/kazlib/dict.c b/libutil/kazlib/dict.c
deleted file mode 100644
index cd98498..0000000
--- a/libutil/kazlib/dict.c
+++ /dev/null
@@ -1,1238 +0,0 @@
-/*
- * Dictionary Abstract Data Type
- * Copyright (C) 1997 Kaz Kylheku <kaz at ashi.footprints.net>
- *
- * Free Software License:
- *
- * All rights are reserved by the author, with the following exceptions:
- * Permission is granted to freely reproduce and distribute this software,
- * possibly in exchange for a fee, provided that this copyright notice appears
- * intact. Permission is also granted to adapt this software to produce
- * derivative works, as long as the modified versions carry this copyright
- * notice and additional notices stating that the work has been modified.
- * This source code may be translated into executable form and incorporated
- * into proprietary software; there is no requirement for such software to
- * contain a copyright notice related to this source.
- *
- */
-
-#define NDEBUG
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <assert.h>
-#define DICT_IMPLEMENTATION
-#include "dict.h"
-
-//  bpw 20050309 define this to use a qsort(3) compatible sort function,
-//  requiring two dereferences to get the data instead of one.
-//
-#define BE_QSORT_COMPATIBLE
-
-/*
- * These macros provide short convenient names for structure members,
- * which are embellished with dict_ prefixes so that they are
- * properly confined to the documented namespace. It's legal for a 
- * program which uses dict to define, for instance, a macro called ``parent''.
- * Such a macro would interfere with the dnode_t struct definition.
- * In general, highly portable and reusable C modules which expose their
- * structures need to confine structure member names to well-defined spaces.
- * The resulting identifiers aren't necessarily convenient to use, nor
- * readable, in the implementation, however!
- */
-
-#define left dict_left
-#define right dict_right
-#define parent dict_parent
-#define color dict_color
-#define key dict_key
-#define data dict_data
-
-#define nilnode dict_nilnode
-#define nodecount dict_nodecount
-#define maxcount dict_maxcount
-#define compare dict_compare
-#define allocnode dict_allocnode
-#define freenode dict_freenode
-#define context dict_context
-#define dupes dict_dupes
-
-#define dictptr dict_dictptr
-
-#define dict_root(D) ((D)->nilnode.left)
-#define dict_nil(D) (&(D)->nilnode)
-#define DICT_DEPTH_MAX 64
-
-static dnode_t *dnode_alloc(void *context);
-static void dnode_free(dnode_t *node, void *context);
-
-/*
- * Perform a ``left rotation'' adjustment on the tree.  The given node P and
- * its right child C are rearranged so that the P instead becomes the left
- * child of C.   The left subtree of C is inherited as the new right subtree
- * for P.  The ordering of the keys within the tree is thus preserved.
- */
-
-static void rotate_left(dnode_t *upper)
-{
-    dnode_t *lower, *lowleft, *upparent;
-
-    lower = upper->right;
-    upper->right = lowleft = lower->left;
-    lowleft->parent = upper;
-
-    lower->parent = upparent = upper->parent;
-
-    /* don't need to check for root node here because root->parent is
-       the sentinel nil node, and root->parent->left points back to root */
-
-    if (upper == upparent->left) {
-	upparent->left = lower;
-    } else {
-	assert (upper == upparent->right);
-	upparent->right = lower;
-    }
-
-    lower->left = upper;
-    upper->parent = lower;
-}
-
-/*
- * This operation is the ``mirror'' image of rotate_left. It is
- * the same procedure, but with left and right interchanged.
- */
-
-static void rotate_right(dnode_t *upper)
-{
-    dnode_t *lower, *lowright, *upparent;
-
-    lower = upper->left;
-    upper->left = lowright = lower->right;
-    lowright->parent = upper;
-
-    lower->parent = upparent = upper->parent;
-
-    if (upper == upparent->right) {
-	upparent->right = lower;
-    } else {
-	assert (upper == upparent->left);
-	upparent->left = lower;
-    }
-
-    lower->right = upper;
-    upper->parent = lower;
-}
-
-/*
- * Do a postorder traversal of the tree rooted at the specified
- * node and free everything under it.  Used by dict_free().
- */
-
-static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil)
-{
-    if (node == nil)
-	return;
-    free_nodes(dict, node->left, nil);
-    free_nodes(dict, node->right, nil);
-    dict->freenode(node, dict->context);
-}
-
-/*
- * This procedure performs a verification that the given subtree is a binary
- * search tree. It performs an inorder traversal of the tree using the
- * dict_next() successor function, verifying that the key of each node is
- * strictly lower than that of its successor, if duplicates are not allowed,
- * or lower or equal if duplicates are allowed.  This function is used for
- * debugging purposes. 
- */
-
-static int verify_bintree(dict_t *dict)
-{
-    dnode_t *first, *next;
-
-    first = dict_first(dict);
-
-    if (dict->dupes) {
-	while (first && (next = dict_next(dict, first))) {
-#ifdef BE_QSORT_COMPATIBLE
-	    if (dict->compare(&first->key, &next->key) > 0)
-		return 0;
-#else
-	    if (dict->compare(first->key, next->key) > 0)
-		return 0;
-#endif
-	    first = next;
-	}
-    } else {
-	while (first && (next = dict_next(dict, first))) {
-#ifdef BE_QSORT_COMPATIBLE
-            if (dict->compare(&first->key, &next->key) >= 0)
-		return 0;
-#else
-	    if (dict->compare(first->key, next->key) >= 0)
-		return 0;
-#endif
-	    first = next;
-	}
-    }
-    return 1;
-}
-
-
-/*
- * This function recursively verifies that the given binary subtree satisfies
- * three of the red black properties. It checks that every red node has only
- * black children. It makes sure that each node is either red or black. And it
- * checks that every path has the same count of black nodes from root to leaf.
- * It returns the blackheight of the given subtree; this allows blackheights to
- * be computed recursively and compared for left and right siblings for
- * mismatches. It does not check for every nil node being black, because there
- * is only one sentinel nil node. The return value of this function is the
- * black height of the subtree rooted at the node ``root'', or zero if the
- * subtree is not red-black.
- */
-
-static unsigned int verify_redblack(dnode_t *nil, dnode_t *root)
-{
-    unsigned height_left, height_right;
-
-    if (root != nil) {
-	height_left = verify_redblack(nil, root->left);
-	height_right = verify_redblack(nil, root->right);
-	if (height_left == 0 || height_right == 0)
-	    return 0;
-	if (height_left != height_right)
-	    return 0;
-	if (root->color == dnode_red) {
-	    if (root->left->color != dnode_black)
-		return 0;
-	    if (root->right->color != dnode_black)
-		return 0;
-	    return height_left;
-	}
-	if (root->color != dnode_black)
-	    return 0;
-	return height_left + 1;
-    } 
-    return 1;
-}
-
-/*
- * Compute the actual count of nodes by traversing the tree and
- * return it. This could be compared against the stored count to
- * detect a mismatch.
- */
-
-static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root)
-{
-    if (root == nil)
-	return 0;
-    else
-	return 1 + verify_node_count(nil, root->left)
-	    + verify_node_count(nil, root->right);
-}
-
-/*
- * Verify that the tree contains the given node. This is done by
- * traversing all of the nodes and comparing their pointers to the
- * given pointer. Returns 1 if the node is found, otherwise
- * returns zero. It is intended for debugging purposes.
- */
-
-static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node)
-{
-    if (root != nil) {
-	return root == node
-		|| verify_dict_has_node(nil, root->left, node)
-		|| verify_dict_has_node(nil, root->right, node);
-    }
-    return 0;
-}
-
-
-/*
- * Dynamically allocate and initialize a dictionary object.
- */
-
-dict_t *dict_create(dictcount_t maxcount, dict_comp_t comp)
-{
-    dict_t *new = malloc(sizeof *new);
-
-    if (new) {
-	new->compare = comp;
-	new->allocnode = dnode_alloc;
-	new->freenode = dnode_free;
-	new->context = NULL;
-	new->nodecount = 0;
-	new->maxcount = maxcount;
-	new->nilnode.left = &new->nilnode;
-	new->nilnode.right = &new->nilnode;
-	new->nilnode.parent = &new->nilnode;
-	new->nilnode.color = dnode_black;
-	new->dupes = 0;
-    }
-    return new;
-}
-
-/*
- * Select a different set of node allocator routines.
- */
-
-void dict_set_allocator(dict_t *dict, dnode_alloc_t al,
-	dnode_free_t fr, void *context)
-{
-    assert (dict_count(dict) == 0);
-    assert ((al == NULL && fr == NULL) || (al != NULL && fr != NULL));
-
-    dict->allocnode = al ? al : dnode_alloc;
-    dict->freenode = fr ? fr : dnode_free;
-    dict->context = context;
-}
-
-/*
- * Free a dynamically allocated dictionary object. Removing the nodes
- * from the tree before deleting it is required.
- */
-
-void dict_destroy(dict_t *dict)
-{
-    assert (dict_isempty(dict));
-    free(dict);
-}
-
-/*
- * Free all the nodes in the dictionary by using the dictionary's
- * installed free routine. The dictionary is emptied.
- */
-
-void dict_free_nodes(dict_t *dict)
-{
-    dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
-    free_nodes(dict, root, nil);
-    dict->nodecount = 0;
-    dict->nilnode.left = &dict->nilnode;
-    dict->nilnode.right = &dict->nilnode;
-}
-
-/*
- * Obsolescent function, equivalent to dict_free_nodes
- */
-
-void dict_free(dict_t *dict)
-{
-#ifdef KAZLIB_OBSOLESCENT_DEBUG
-    assert ("call to obsolescent function dict_free()" && 0);
-#endif
-    dict_free_nodes(dict);
-}
-
-/*
- * Initialize a user-supplied dictionary object.
- */
-
-dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp)
-{
-    dict->compare = comp;
-    dict->allocnode = dnode_alloc;
-    dict->freenode = dnode_free;
-    dict->context = NULL;
-    dict->nodecount = 0;
-    dict->maxcount = maxcount;
-    dict->nilnode.left = &dict->nilnode;
-    dict->nilnode.right = &dict->nilnode;
-    dict->nilnode.parent = &dict->nilnode;
-    dict->nilnode.color = dnode_black;
-    dict->dupes = 0;
-    return dict;
-}
-
-/* 
- * Initialize a dictionary in the likeness of another dictionary
- */
-
-void dict_init_like(dict_t *dict, const dict_t *template)
-{
-    dict->compare = template->compare;
-    dict->allocnode = template->allocnode;
-    dict->freenode = template->freenode;
-    dict->context = template->context;
-    dict->nodecount = 0;
-    dict->maxcount = template->maxcount;
-    dict->nilnode.left = &dict->nilnode;
-    dict->nilnode.right = &dict->nilnode;
-    dict->nilnode.parent = &dict->nilnode;
-    dict->nilnode.color = dnode_black;
-    dict->dupes = template->dupes;
-
-    assert (dict_similar(dict, template));
-}
-
-/*
- * Remove all nodes from the dictionary (without freeing them in any way).
- */
-
-static void dict_clear(dict_t *dict)
-{
-    dict->nodecount = 0;
-    dict->nilnode.left = &dict->nilnode;
-    dict->nilnode.right = &dict->nilnode;
-    dict->nilnode.parent = &dict->nilnode;
-    assert (dict->nilnode.color == dnode_black);
-}
-
-
-/*
- * Verify the integrity of the dictionary structure.  This is provided for
- * debugging purposes, and should be placed in assert statements.   Just because
- * this function succeeds doesn't mean that the tree is not corrupt. Certain
- * corruptions in the tree may simply cause undefined behavior.
- */ 
-
-int dict_verify(dict_t *dict)
-{
-    dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
-
-    /* check that the sentinel node and root node are black */
-    if (root->color != dnode_black)
-      return(0 * fprintf(stderr, "dict_verify()-- Root node not black!\n"));
-    if (nil->color != dnode_black)
-      return(0 * fprintf(stderr, "dict_verify()-- Nil node not black!\n"));
-    if (nil->right != nil)
-      return(0 * fprintf(stderr, "dict_verify()-- Nul->right not Nil!\n"));
-    /* nil->left is the root node; check that its parent pointer is nil */
-    if (nil->left->parent != nil)
-      return(0 * fprintf(stderr, "dict_verify()-- Nul->left->parent is not Nil!\n"));
-    /* perform a weak test that the tree is a binary search tree */
-    if (!verify_bintree(dict))
-      return(0 * fprintf(stderr, "dict_verify()-- Not a binary search tree!\n"));
-    /* verify that the tree is a red-black tree */
-    if (!verify_redblack(nil, root))
-      return(0 * fprintf(stderr, "dict_verify()-- Not a red-black tree!\n"));
-    if (verify_node_count(nil, root) != dict_count(dict))
-      return(0 * fprintf(stderr, "dict_verify()-- Node count is wrong!\n"));
-    return 1;
-}
-
-/*
- * Determine whether two dictionaries are similar: have the same comparison and
- * allocator functions, and same status as to whether duplicates are allowed.
- */
-
-int dict_similar(const dict_t *left, const dict_t *right)
-{
-    if (left->compare != right->compare)
-	return 0;
-
-    if (left->allocnode != right->allocnode)
-	return 0;
-
-    if (left->freenode != right->freenode)
-	return 0;
-
-    if (left->context != right->context)
-	return 0;
-
-    if (left->dupes != right->dupes)
-	return 0;
-
-    return 1;
-}
-
-/*
- * Locate a node in the dictionary having the given key.
- * If the node is not found, a null a pointer is returned (rather than 
- * a pointer that dictionary's nil sentinel node), otherwise a pointer to the
- * located node is returned.
- */
-
-dnode_t *dict_lookup(dict_t *dict, const void *key)
-{
-    dnode_t *root = dict_root(dict);
-    dnode_t *nil = dict_nil(dict);
-    dnode_t *saved;
-    int result;
-
-    /* simple binary search adapted for trees that contain duplicate keys */
-
-    while (root != nil) {
-#ifdef BE_QSORT_COMPATIBLE
-	result = dict->compare(&key, &root->key);
-#else
-	result = dict->compare(key, root->key);
-#endif
-	if (result < 0)
-	    root = root->left;
-	else if (result > 0)
-	    root = root->right;
-	else {
-	    if (!dict->dupes) {	/* no duplicates, return match		*/
-		return root;
-	    } else {		/* could be dupes, find leftmost one	*/
-		do {
-		    saved = root;
-		    root = root->left;
-#ifdef BE_QSORT_COMPATIBLE
-		    while (root != nil && dict->compare(&key, &root->key))
-			root = root->right;
-#else
-		    while (root != nil && dict->compare(key, root->key))
-			root = root->right;
-#endif
-		} while (root != nil);
-		return saved;
-	    }
-	}
-    }
-
-    return NULL;
-}
-
-/*
- * Look for the node corresponding to the lowest key that is equal to or
- * greater than the given key.  If there is no such node, return null.
- */
-
-dnode_t *dict_lower_bound(dict_t *dict, const void *key)
-{
-    dnode_t *root = dict_root(dict);
-    dnode_t *nil = dict_nil(dict);
-    dnode_t *tentative = 0;
-
-    while (root != nil) {
-#ifdef BE_QSORT_COMPATIBLE
-	int result = dict->compare(&key, &root->key);
-#else
-	int result = dict->compare(key, root->key);
-#endif
-
-	if (result > 0) {
-	    root = root->right;
-	} else if (result < 0) {
-	    tentative = root;
-	    root = root->left;
-	} else {
-	    if (!dict->dupes) {
-	    	return root;
-	    } else {
-		tentative = root;
-		root = root->left;
-	    }
-	} 
-    }
-    
-    return tentative;
-}
-
-/*
- * Look for the node corresponding to the greatest key that is equal to or
- * lower than the given key.  If there is no such node, return null.
- */
-
-dnode_t *dict_upper_bound(dict_t *dict, const void *key)
-{
-    dnode_t *root = dict_root(dict);
-    dnode_t *nil = dict_nil(dict);
-    dnode_t *tentative = 0;
-
-    while (root != nil) {
-#ifdef BE_QSORT_COMPATIBLE
-	int result = dict->compare(&key, &root->key);
-#else
-	int result = dict->compare(key, root->key);
-#endif
-
-	if (result < 0) {
-	    root = root->left;
-	} else if (result > 0) {
-	    tentative = root;
-	    root = root->right;
-	} else {
-	    if (!dict->dupes) {
-	    	return root;
-	    } else {
-		tentative = root;
-		root = root->right;
-	    }
-	} 
-    }
-    
-    return tentative;
-}
-
-/*
- * Insert a node into the dictionary. The node should have been
- * initialized with a data field. All other fields are ignored.
- * The behavior is undefined if the user attempts to insert into
- * a dictionary that is already full (for which the dict_isfull()
- * function returns true).
- */
-
-void dict_insert(dict_t *dict, dnode_t *node, const void *key)
-{
-    dnode_t *where = dict_root(dict), *nil = dict_nil(dict);
-    dnode_t *parent = nil, *uncle, *grandpa;
-    int result = -1;
-
-    node->key = key;
-
-    assert (!dict_isfull(dict));
-    assert (!dict_contains(dict, node));
-    assert (!dnode_is_in_a_dict(node));
-
-    /* basic binary tree insert */
-
-    while (where != nil) {
-	parent = where;
-#ifdef BE_QSORT_COMPATIBLE
-	result = dict->compare(&key, &where->key);
-#else
-	result = dict->compare(key, where->key);
-#endif
-	/* trap attempts at duplicate key insertion unless it's explicitly allowed */
-	assert (dict->dupes || result != 0);
-	if (result < 0)
-	    where = where->left;
-	else
-	    where = where->right;
-    }
-
-    assert (where == nil);
-
-    if (result < 0)
-	parent->left = node;
-    else
-	parent->right = node;
-
-    node->parent = parent;
-    node->left = nil;
-    node->right = nil;
-
-    dict->nodecount++;
-
-    /* red black adjustments */
-
-    node->color = dnode_red;
-
-    while (parent->color == dnode_red) {
-	grandpa = parent->parent;
-	if (parent == grandpa->left) {
-	    uncle = grandpa->right;
-	    if (uncle->color == dnode_red) {	/* red parent, red uncle */
-		parent->color = dnode_black;
-		uncle->color = dnode_black;
-		grandpa->color = dnode_red;
-		node = grandpa;
-		parent = grandpa->parent;
-	    } else {				/* red parent, black uncle */
-	    	if (node == parent->right) {
-		    rotate_left(parent);
-		    parent = node;
-		    assert (grandpa == parent->parent);
-		    /* rotation between parent and child preserves grandpa */
-		}
-		parent->color = dnode_black;
-		grandpa->color = dnode_red;
-		rotate_right(grandpa);
-		break;
-	    }
-	} else { 	/* symmetric cases: parent == parent->parent->right */
-	    uncle = grandpa->left;
-	    if (uncle->color == dnode_red) {
-		parent->color = dnode_black;
-		uncle->color = dnode_black;
-		grandpa->color = dnode_red;
-		node = grandpa;
-		parent = grandpa->parent;
-	    } else {
-	    	if (node == parent->left) {
-		    rotate_right(parent);
-		    parent = node;
-		    assert (grandpa == parent->parent);
-		}
-		parent->color = dnode_black;
-		grandpa->color = dnode_red;
-		rotate_left(grandpa);
-		break;
-	    }
-	}
-    }
-
-    dict_root(dict)->color = dnode_black;
-
-    assert (dict_verify(dict));
-}
-
-/*
- * Delete the given node from the dictionary. If the given node does not belong
- * to the given dictionary, undefined behavior results.  A pointer to the
- * deleted node is returned.
- */
-
-dnode_t *dict_delete(dict_t *dict, dnode_t *delete)
-{
-    dnode_t *nil = dict_nil(dict), *child, *delparent = delete->parent;
-
-    /* basic deletion */
-
-    assert (!dict_isempty(dict));
-    assert (dict_contains(dict, delete));
-
-    /*
-     * If the node being deleted has two children, then we replace it with its
-     * successor (i.e. the leftmost node in the right subtree.) By doing this,
-     * we avoid the traditional algorithm under which the successor's key and
-     * value *only* move to the deleted node and the successor is spliced out
-     * from the tree. We cannot use this approach because the user may hold
-     * pointers to the successor, or nodes may be inextricably tied to some
-     * other structures by way of embedding, etc. So we must splice out the
-     * node we are given, not some other node, and must not move contents from
-     * one node to another behind the user's back.
-     */
-
-    if (delete->left != nil && delete->right != nil) {
-	dnode_t *next = dict_next(dict, delete);
-	dnode_t *nextparent = next->parent;
-	dnode_color_t nextcolor = next->color;
-
-	assert (next != nil);
-	assert (next->parent != nil);
-	assert (next->left == nil);
-
-	/*
-	 * First, splice out the successor from the tree completely, by
-	 * moving up its right child into its place.
-	 */
-
-	child = next->right;
-	child->parent = nextparent;
-
-	if (nextparent->left == next) {
-	    nextparent->left = child;
-	} else {
-	    assert (nextparent->right == next);
-	    nextparent->right = child;
-	}
-
-	/*
-	 * Now that the successor has been extricated from the tree, install it
-	 * in place of the node that we want deleted.
-	 */
-
-	next->parent = delparent;
-	next->left = delete->left;
-	next->right = delete->right;
-	next->left->parent = next;
-	next->right->parent = next;
-	next->color = delete->color;
-	delete->color = nextcolor;
-
-	if (delparent->left == delete) {
-	    delparent->left = next;
-	} else {
-	    assert (delparent->right == delete);
-	    delparent->right = next;
-	}
-
-    } else {
-	assert (delete != nil);
-	assert (delete->left == nil || delete->right == nil);
-
-	child = (delete->left != nil) ? delete->left : delete->right;
-
-	child->parent = delparent = delete->parent;	    
-
-	if (delete == delparent->left) {
-	    delparent->left = child;    
-	} else {
-	    assert (delete == delparent->right);
-	    delparent->right = child;
-	}
-    }
-
-    delete->parent = NULL;
-    delete->right = NULL;
-    delete->left = NULL;
-
-    dict->nodecount--;
-
-    assert (verify_bintree(dict));
-
-    /* red-black adjustments */
-
-    if (delete->color == dnode_black) {
-	dnode_t *parent, *sister;
-
-	dict_root(dict)->color = dnode_red;
-
-	while (child->color == dnode_black) {
-	    parent = child->parent;
-	    if (child == parent->left) {
-		sister = parent->right;
-		assert (sister != nil);
-		if (sister->color == dnode_red) {
-		    sister->color = dnode_black;
-		    parent->color = dnode_red;
-		    rotate_left(parent);
-		    sister = parent->right;
-		    assert (sister != nil);
-		}
-		if (sister->left->color == dnode_black
-			&& sister->right->color == dnode_black) {
-		    sister->color = dnode_red;
-		    child = parent;
-		} else {
-		    if (sister->right->color == dnode_black) {
-			assert (sister->left->color == dnode_red);
-			sister->left->color = dnode_black;
-			sister->color = dnode_red;
-			rotate_right(sister);
-			sister = parent->right;
-			assert (sister != nil);
-		    }
-		    sister->color = parent->color;
-		    sister->right->color = dnode_black;
-		    parent->color = dnode_black;
-		    rotate_left(parent);
-		    break;
-		}
-	    } else {	/* symmetric case: child == child->parent->right */
-		assert (child == parent->right);
-		sister = parent->left;
-		assert (sister != nil);
-		if (sister->color == dnode_red) {
-		    sister->color = dnode_black;
-		    parent->color = dnode_red;
-		    rotate_right(parent);
-		    sister = parent->left;
-		    assert (sister != nil);
-		}
-		if (sister->right->color == dnode_black
-			&& sister->left->color == dnode_black) {
-		    sister->color = dnode_red;
-		    child = parent;
-		} else {
-		    if (sister->left->color == dnode_black) {
-			assert (sister->right->color == dnode_red);
-			sister->right->color = dnode_black;
-			sister->color = dnode_red;
-			rotate_left(sister);
-			sister = parent->left;
-			assert (sister != nil);
-		    }
-		    sister->color = parent->color;
-		    sister->left->color = dnode_black;
-		    parent->color = dnode_black;
-		    rotate_right(parent);
-		    break;
-		}
-	    }
-	}
-
-	child->color = dnode_black;
-	dict_root(dict)->color = dnode_black;
-    }
-
-    assert (dict_verify(dict));
-
-    return delete;
-}
-
-/*
- * Allocate a node using the dictionary's allocator routine, give it
- * the data item.
- */
-
-int dict_alloc_insert(dict_t *dict, const void *key, void *data)
-{
-    dnode_t *node = dict->allocnode(dict->context);
-
-    if (node) {
-	dnode_init(node, data);
-	dict_insert(dict, node, key);
-	return 1;
-    }
-    return 0;
-}
-
-void dict_delete_free(dict_t *dict, dnode_t *node)
-{
-    dict_delete(dict, node);
-    dict->freenode(node, dict->context);
-}
-
-/*
- * Return the node with the lowest (leftmost) key. If the dictionary is empty
- * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
- */
-
-dnode_t *dict_first(dict_t *dict)
-{
-    dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left;
-
-    if (root != nil)
-	while ((left = root->left) != nil)
-	    root = left;
-
-    return (root == nil) ? NULL : root;
-}
-
-/*
- * Return the node with the highest (rightmost) key. If the dictionary is empty
- * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
- */
-
-dnode_t *dict_last(dict_t *dict)
-{
-    dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *right;
-
-    if (root != nil)
-	while ((right = root->right) != nil)
-	    root = right;
-
-    return (root == nil) ? NULL : root;
-}
-
-/*
- * Return the given node's successor node---the node which has the
- * next key in the the left to right ordering. If the node has
- * no successor, a null pointer is returned rather than a pointer to
- * the nil node.
- */
-
-dnode_t *dict_next(dict_t *dict, dnode_t *curr)
-{
-    dnode_t *nil = dict_nil(dict), *parent, *left;
-
-    if (curr->right != nil) {
-	curr = curr->right;
-	while ((left = curr->left) != nil)
-	    curr = left;
-	return curr;
-    }
-
-    parent = curr->parent;
-
-    while (parent != nil && curr == parent->right) {
-	curr = parent;
-	parent = curr->parent;
-    }
-
-    return (parent == nil) ? NULL : parent;
-}
-
-/*
- * Return the given node's predecessor, in the key order.
- * The nil sentinel node is returned if there is no predecessor.
- */
-
-dnode_t *dict_prev(dict_t *dict, dnode_t *curr)
-{
-    dnode_t *nil = dict_nil(dict), *parent, *right;
-
-    if (curr->left != nil) {
-	curr = curr->left;
-	while ((right = curr->right) != nil)
-	    curr = right;
-	return curr;
-    }
-
-    parent = curr->parent;
-
-    while (parent != nil && curr == parent->left) {
-	curr = parent;
-	parent = curr->parent;
-    }
-
-    return (parent == nil) ? NULL : parent;
-}
-
-void dict_allow_dupes(dict_t *dict)
-{
-    dict->dupes = 1;
-}
-
-#undef dict_count
-#undef dict_isempty
-#undef dict_isfull
-#undef dnode_get
-#undef dnode_put
-#undef dnode_getkey
-
-dictcount_t dict_count(dict_t *dict)
-{
-    return dict->nodecount;
-}
-
-int dict_isempty(dict_t *dict)
-{
-    return dict->nodecount == 0;
-}
-
-int dict_isfull(dict_t *dict)
-{
-    return dict->nodecount == dict->maxcount;
-}
-
-int dict_contains(dict_t *dict, dnode_t *node)
-{
-    return verify_dict_has_node(dict_nil(dict), dict_root(dict), node);
-}
-
-static dnode_t *dnode_alloc(void *context)
-{
-    return malloc(sizeof *dnode_alloc(NULL));
-}
-
-static void dnode_free(dnode_t *node, void *context)
-{
-    free(node);
-}
-
-dnode_t *dnode_create(void *data)
-{
-    dnode_t *new = malloc(sizeof *new);
-    if (new) {
-	new->data = data;
-	new->parent = NULL;
-	new->left = NULL;
-	new->right = NULL;
-    }
-    return new;
-}
-
-dnode_t *dnode_init(dnode_t *dnode, void *data)
-{
-    dnode->data = data;
-    dnode->parent = NULL;
-    dnode->left = NULL;
-    dnode->right = NULL;
-    return dnode;
-}
-
-void dnode_destroy(dnode_t *dnode)
-{
-    assert (!dnode_is_in_a_dict(dnode));
-    free(dnode);
-}
-
-void *dnode_get(dnode_t *dnode)
-{
-    return dnode->data;
-}
-
-const void *dnode_getkey(dnode_t *dnode)
-{
-    return dnode->key;
-}
-
-void dnode_put(dnode_t *dnode, void *data)
-{
-    dnode->data = data;
-}
-
-int dnode_is_in_a_dict(dnode_t *dnode)
-{
-    return (dnode->parent && dnode->left && dnode->right);
-}
-
-void dict_process(dict_t *dict, void *context, dnode_process_t function)
-{
-    dnode_t *node = dict_first(dict), *next;
-
-    while (node != NULL) {
-	/* check for callback function deleting	*/
-	/* the next node from under us		*/
-	assert (dict_contains(dict, node));
-	next = dict_next(dict, node);
-	function(dict, node, context);
-	node = next;
-    }
-}
-
-static void load_begin_internal(dict_load_t *load, dict_t *dict)
-{
-    load->dictptr = dict;
-    load->nilnode.left = &load->nilnode;
-    load->nilnode.right = &load->nilnode;
-}
-
-void dict_load_begin(dict_load_t *load, dict_t *dict)
-{
-    assert (dict_isempty(dict));
-    load_begin_internal(load, dict);
-}
-
-void dict_load_next(dict_load_t *load, dnode_t *newnode, const void *key)
-{
-    dict_t *dict = load->dictptr;
-    dnode_t *nil = &load->nilnode;
-   
-    assert (!dnode_is_in_a_dict(newnode));
-    assert (dict->nodecount < dict->maxcount);
-
-#ifndef NDEBUG
-    if (dict->nodecount > 0) {
-#ifdef BE_QSORT_COMPATIBLE
-	if (dict->dupes)
-	    assert (dict->compare(&nil->left->key, &key) <= 0);
-	else
-	    assert (dict->compare(&nil->left->key, &key) < 0);
-#else
-	if (dict->dupes)
-	    assert (dict->compare(nil->left->key, key) <= 0);
-	else
-	    assert (dict->compare(nil->left->key, key) < 0);
-#endif
-    }
-#endif
-
-    newnode->key = key;
-    nil->right->left = newnode;
-    nil->right = newnode;
-    newnode->left = nil;
-    dict->nodecount++;
-}
-
-void dict_load_end(dict_load_t *load)
-{
-    dict_t *dict = load->dictptr;
-    dnode_t *tree[DICT_DEPTH_MAX] = { 0 };
-    dnode_t *curr, *dictnil = dict_nil(dict), *loadnil = &load->nilnode, *next;
-    dnode_t *complete = 0;
-    dictcount_t fullcount = DICTCOUNT_T_MAX, nodecount = dict->nodecount;
-    dictcount_t botrowcount;
-    unsigned baselevel = 0, level = 0, i;
-
-    assert (dnode_red == 0 && dnode_black == 1);
-
-    while (fullcount >= nodecount && fullcount)
-	fullcount >>= 1;
-
-    botrowcount = nodecount - fullcount;
-
-    for (curr = loadnil->left; curr != loadnil; curr = next) {
-	next = curr->left;
-
-	if (complete == NULL && botrowcount-- == 0) {
-	    assert (baselevel == 0);
-	    assert (level == 0);
-	    baselevel = level = 1;
-	    complete = tree[0];
-
-	    if (complete != 0) {
-		tree[0] = 0;
-		complete->right = dictnil;
-		while (tree[level] != 0) {
-		    tree[level]->right = complete;
-		    complete->parent = tree[level];
-		    complete = tree[level];
-		    tree[level++] = 0;
-		}
-	    }
-	}
-
-	if (complete == NULL) {
-	    curr->left = dictnil;
-	    curr->right = dictnil;
-	    curr->color = level % 2;
-	    complete = curr;
-
-	    assert (level == baselevel);
-	    while (tree[level] != 0) {
-		tree[level]->right = complete;
-		complete->parent = tree[level];
-		complete = tree[level];
-		tree[level++] = 0;
-	    }
-	} else {
-	    curr->left = complete;
-	    curr->color = (level + 1) % 2;
-	    complete->parent = curr;
-	    tree[level] = curr;
-	    complete = 0;
-	    level = baselevel;
-	}
-    }
-
-    if (complete == NULL)
-	complete = dictnil;
-
-    for (i = 0; i < DICT_DEPTH_MAX; i++) {
-	if (tree[i] != 0) {
-	    tree[i]->right = complete;
-	    complete->parent = tree[i];
-	    complete = tree[i];
-	}
-    }
-
-    dictnil->color = dnode_black;
-    dictnil->right = dictnil;
-    complete->parent = dictnil;
-    complete->color = dnode_black;
-    dict_root(dict) = complete;
-
-    assert (dict_verify(dict));
-}
-
-void dict_merge(dict_t *dest, dict_t *source)
-{
-    dict_load_t load;
-    dnode_t *leftnode = dict_first(dest), *rightnode = dict_first(source);
-
-    assert (dict_similar(dest, source));	
-
-    if (source == dest)
-	return;
-
-    dest->nodecount = 0;
-    load_begin_internal(&load, dest);
-
-    for (;;) {
-	if (leftnode != NULL && rightnode != NULL) {
-#ifdef BE_QSORT_COMPATIBLE
-	    if (dest->compare(&leftnode->key, &rightnode->key) < 0)
-		goto copyleft;
-	    else
-		goto copyright;
-#else
-	    if (dest->compare(leftnode->key, rightnode->key) < 0)
-		goto copyleft;
-	    else
-		goto copyright;
-#endif
-	} else if (leftnode != NULL) {
-	    goto copyleft;
-	} else if (rightnode != NULL) {
-	    goto copyright;
-	} else {
-	    assert (leftnode == NULL && rightnode == NULL);
-	    break;
-	}
-
-    copyleft:
-	{
-	    dnode_t *next = dict_next(dest, leftnode);
-	#ifndef NDEBUG
-	    leftnode->left = NULL;	/* suppress assertion in dict_load_next */
-	#endif
-	    dict_load_next(&load, leftnode, leftnode->key);
-	    leftnode = next;
-	    continue;
-	}
-	
-    copyright:
-	{
-	    dnode_t *next = dict_next(source, rightnode);
-#ifndef NDEBUG
-	    rightnode->left = NULL;
-#endif
-	    dict_load_next(&load, rightnode, rightnode->key);
-	    rightnode = next;
-	    continue;
-	}
-    }
-
-    dict_clear(source);
-    dict_load_end(&load);
-}
diff --git a/libutil/kazlib/dict.h b/libutil/kazlib/dict.h
deleted file mode 100644
index 2bab634..0000000
--- a/libutil/kazlib/dict.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Dictionary Abstract Data Type
- * Copyright (C) 1997 Kaz Kylheku <kaz at ashi.footprints.net>
- *
- * Free Software License:
- *
- * All rights are reserved by the author, with the following exceptions:
- * Permission is granted to freely reproduce and distribute this software,
- * possibly in exchange for a fee, provided that this copyright notice appears
- * intact. Permission is also granted to adapt this software to produce
- * derivative works, as long as the modified versions carry this copyright
- * notice and additional notices stating that the work has been modified.
- * This source code may be translated into executable form and incorporated
- * into proprietary software; there is no requirement for such software to
- * contain a copyright notice related to this source.
- *
- */
-
-#ifndef DICT_H
-#define DICT_H
-
-#include <limits.h>
-#ifdef KAZLIB_SIDEEFFECT_DEBUG
-#include "sfx.h"
-#endif
-
-/*
- * Blurb for inclusion into C++ translation units
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef unsigned long dictcount_t;
-#define DICTCOUNT_T_MAX ULONG_MAX
-
-/*
- * The dictionary is implemented as a red-black tree
- */
-
-typedef enum { dnode_red, dnode_black } dnode_color_t;
-
-typedef struct dnode_t {
-#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
-    struct dnode_t *dict_left;
-    struct dnode_t *dict_right;
-    struct dnode_t *dict_parent;
-    dnode_color_t dict_color;
-    const void *dict_key;
-    void *dict_data;
-#else
-    int dict_dummy;
-#endif
-} dnode_t;
-
-typedef int (*dict_comp_t)(const void *, const void *);
-typedef dnode_t *(*dnode_alloc_t)(void *);
-typedef void (*dnode_free_t)(dnode_t *, void *);
-
-typedef struct dict_t {
-#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
-    dnode_t dict_nilnode;
-    dictcount_t dict_nodecount;
-    dictcount_t dict_maxcount;
-    dict_comp_t dict_compare;
-    dnode_alloc_t dict_allocnode;
-    dnode_free_t dict_freenode;
-    void *dict_context;
-    int dict_dupes;
-#else
-    int dict_dummmy;
-#endif
-} dict_t;
-
-typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *);
-
-typedef struct dict_load_t {
-#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
-    dict_t *dict_dictptr;
-    dnode_t dict_nilnode;
-#else
-    int dict_dummmy;
-#endif
-} dict_load_t;
-
-extern dict_t *dict_create(dictcount_t, dict_comp_t);
-extern void dict_set_allocator(dict_t *, dnode_alloc_t, dnode_free_t, void *);
-extern void dict_destroy(dict_t *);
-extern void dict_free_nodes(dict_t *);
-extern void dict_free(dict_t *);
-extern dict_t *dict_init(dict_t *, dictcount_t, dict_comp_t);
-extern void dict_init_like(dict_t *, const dict_t *);
-extern int dict_verify(dict_t *);
-extern int dict_similar(const dict_t *, const dict_t *);
-extern dnode_t *dict_lookup(dict_t *, const void *);
-extern dnode_t *dict_lower_bound(dict_t *, const void *);
-extern dnode_t *dict_upper_bound(dict_t *, const void *);
-extern void dict_insert(dict_t *, dnode_t *, const void *);
-extern dnode_t *dict_delete(dict_t *, dnode_t *);
-extern int dict_alloc_insert(dict_t *, const void *, void *);
-extern void dict_delete_free(dict_t *, dnode_t *);
-extern dnode_t *dict_first(dict_t *);
-extern dnode_t *dict_last(dict_t *);
-extern dnode_t *dict_next(dict_t *, dnode_t *);
-extern dnode_t *dict_prev(dict_t *, dnode_t *);
-extern dictcount_t dict_count(dict_t *);
-extern int dict_isempty(dict_t *);
-extern int dict_isfull(dict_t *);
-extern int dict_contains(dict_t *, dnode_t *);
-extern void dict_allow_dupes(dict_t *);
-extern int dnode_is_in_a_dict(dnode_t *);
-extern dnode_t *dnode_create(void *);
-extern dnode_t *dnode_init(dnode_t *, void *);
-extern void dnode_destroy(dnode_t *);
-extern void *dnode_get(dnode_t *);
-extern const void *dnode_getkey(dnode_t *);
-extern void dnode_put(dnode_t *, void *);
-extern void dict_process(dict_t *, void *, dnode_process_t);
-extern void dict_load_begin(dict_load_t *, dict_t *);
-extern void dict_load_next(dict_load_t *, dnode_t *, const void *);
-extern void dict_load_end(dict_load_t *);
-extern void dict_merge(dict_t *, dict_t *);
-
-#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
-#ifdef KAZLIB_SIDEEFFECT_DEBUG
-#define dict_isfull(D) (SFX_CHECK(D)->dict_nodecount == (D)->dict_maxcount)
-#else
-#define dict_isfull(D) ((D)->dict_nodecount == (D)->dict_maxcount)
-#endif
-#define dict_count(D) ((D)->dict_nodecount)
-#define dict_isempty(D) ((D)->dict_nodecount == 0)
-#define dnode_get(N) ((N)->dict_data)
-#define dnode_getkey(N) ((N)->dict_key)
-#define dnode_put(N, X) ((N)->dict_data = (X))
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/libutil/kazlib/docs/CHANGES b/libutil/kazlib/docs/CHANGES
deleted file mode 100644
index 3c949eb..0000000
--- a/libutil/kazlib/docs/CHANGES
+++ /dev/null
@@ -1,290 +0,0 @@
-New in 1.20
-
-    1. Bugfix in except.h. Modified non-volatile auto variables were
-       being accessed after longjmp.
-
-New in 1.19
-
-    1. Rewrite of broken dict_free.
-    2. Fixed embarassing build breakages that accidentally went into 1.18
-    3. Function hash_scan_delete_free renamed to hash_scan_delfree to be
-       distinct from hash_scan_delete in the first 14 characters.
-    4. To resolve inconsistencies between hash_free and dict_free,
-       and a difference between the actual behavior of hash_free  and
-       the documented behavior, these two functions are marked obsolescent.
-       The functions dict_free_nodes and hash_free_nodes are provided.
-       The obsolescent functions continue to work as before, for now.
-    5. Documentation of hash_free is fixed to say that it also subjects
-       the hash to hash_destroy, which is what the implementation does.
-    6. Documentation states what release it is for.
-
-New in 1.18
-
-    1. Error in assert expression in list_merge fixed.
-    2. Semantics of list_merge extended to allow list to be merged
-       onto itself (which is a noop).
-    3. Clarified interface specification of list_transfer and list_extract;
-       the source and destination list may be the same object.
-    4. New functions:
-       dict_init_like: create a dictionary similar to another one;
-       dict_similar: determine whether two dictionaries are similar;
-       dict_merge: merge contents of one dictionary to another.
-    5. Dictionary test main can juggle multiple dictionaries, and test
-       dict_merge. 
-    6. If a hash node is inserted into some hash, it is a now a constraint
-       violation to insert it again into some hash.
-    7. The hash_scan_delete_free function has been implemented; it is to
-       hash_scan_delete what hash_delete_free is to hash_delete.
-
-New in 1.17
-
-    Carl van Tast <vanTast at netway.at>:
-    1. Removed references to ``safe malloc'' from some comments.
-    2. Swapped ``allowed'' and ``not allowed'' in comment to
-       verify_bintree.
-    3. Fixed comment to list_next: this function never returns the
-       sentinel.
-    4. lnode_pool_init: nodes[i].prev = nodes instead of nodes + 1. This
-       saves one or two CPU cycles :-) and it gives a valid address even
-       if we have a (somewhat pathological) pool with just one element.
-
-    Kaz:
-    5. Dropped extra parameter from tree rotation functions in dict.c. Should
-       shave a few cycles.
-    6. Fixed error in the duplicate key iteration idiom example in the
-       documentation (see the section on dict_upper_bound).
-    7. Forgotten #include <string.h> added to hash.c
-
-New in 1.16
-
-    1. Added an interface for loading the contents of a dictionary from an
-       ordered sequence. This is done in O(n) time by a direct bottom-up
-       construction of the red-black tree, making it much faster than
-       the O(n log n) process of inserting each element.
-    2. Miscellaneous cleanup: missing const qualifiers were added
-       to key pointer parameters, some incorrect comments fixed;
-       spelling errors corrected in documentation.
-
-New in 1.15
-
-    1. Another potential exception handling memory leak fixed. This one
-       has to do with throwing an exception from within a try-catch region
-       in which an exception was just caught. The new exception replaces
-       the old without the old's dynamic memory being disposed of.
-    2. Restrictions added on except_rethrow.
-    3. Exception module must now be explicitly initialized with except_init.
-    4. Structure members in exception header renamed to adhere to documented
-       namespace.
-    5. The exwrap.[ch] source files are gone. There is support for memory
-       allocation with exception handling in except.c, which supports user
-       defined allocators.
-    6. Three bugfixes to sfx parser. First, unary operators take a cast
-       expression, not a unary expression. Secondly, sizeof doesn't throw a syntax
-       error anymore on things that look like casts, but maybe are not.
-       Thirdly, empty parentheses weren't handled right in treatment of
-       ambiguous expressions, e.g. (a)() was declared a syntax error.
-    7. Changed the representation of hash table chains. They are now
-       singly linked lists, which means that the overhead of managing 
-       back pointers is gone. Only deletion is slightly more complicated
-       now because it has to search from the beginning of the chain.
-       [Rationale: this is okay, since chains are supposed to be short
-       in a hash table!]
-    8. Rewritten test main() in list.c. It's now more like the others
-       with a menu. Previously it was essentially a file sorting program.
-    9. New function: list_find. Exhaustively searches the list for a
-       matching entry, returns pointer to node if found.
-
-New in 1.14
-
-    1. Got rid of some overbearing copyright restrictions. There is no need for
-       executables to contain copyright notices. In fact, there are no
-       restrictions on the use, or distribution in executable form.
-    2. Tiny tweak in red-black fixup code of dict_insert.
-    3. Keys in hash and dict are declared const void * now in all functions
-       rather than plain void *.  This means that casts are no longer
-       necessary when calling insert or lookup functions with const
-       data as the key. But casts of the return value of hnode_getkey
-       or dnode_getkey may be required.
-    4. Fixed compile breakage of except.c when posix thread support enabled.
-    5. Side effect assertion interface now performs caching, to avoid
-       parsing the same expressions over and over again.  Thus debugging with
-       KAZLIB_SIDEEFFECT_DEBUG incurs a smaller performance hit.
-    6. Major bugfix to sfx expression parser. The function dealing with 
-       disambiguating casts had to be rewritten to do more sophisticated
-       lookahead and backtracking. It all started with Mark Brady discovered
-       that (a++)+b was being incorrectly diagnosed as a syntax error.
-    7. Added documentation. more examples for uses of dictionaries, and
-       exception handling. Some documentation about the internals
-       of exception handling added. Changed document format for narrower
-       margins, reducing page count and increasing readability.
-    8. Bugfix in except_rethrow. It was freeing the dynamic data of the
-       exception even though it's not handled yet.
-
-New in 1.13
-
-    1. Fixed some potential memory leaks in except.c.
-    2. Finished all interface documentation. All that is left now
-       is to flesh out the implementation notes.
-    3. Fixed a bug in POSIX threaded variant of except.c. Null
-       function pointer dereference in unhandled exception case.
-    4. Macros beginning with E[A-Z] have been renamed to stay out
-       of space reserved for <errno.h>.
-    5. Identifiers in exwrap.[ch] have been renamed from having 
-       ex_ prefixed to having exwrap_ prefixes.
-
-New in 1.12
-
-    1. COOL! New module for detecting side effects in C expressions.
-    2. Serious bugfix in hash_init().  The computation of the initial hash
-       mask was completely botched up. Historically this code has seen little
-       testing because hashing over a user supplied table is not extendible. 
-       Users of hash_create() are not affected.
-    3. Tried to make computation of hash_val_t_bit more threadsafe. It should
-       be okay if writes to int objects are atomic, and concurrent writes of
-       the same int value to a given object are safe.
-    4. Makefile renamed to Makefile.gcc. Makevile.vc added. The rename
-       is retroactive to all prior releases.
-    5. OPAQUE_DEBUG becomes KAZLIB_OPAQUE_DEBUG and TEST_MAIN becomes
-       KAZLIB_TEST_MAIN. In general, macros that affect how the modules
-       build should be confined to a special namespace.
-    6. New KAZLIB_SIDEEFFECT_DEBUG feature to enable diagnosis of side
-       effect expressions being passed to macros that evaluate their arguments
-       more than once.
-
-New in 1.11
-
-    1. Improvements in experimental exception handling module:
-       except_throwf has been added which takes printf-like arguments;
-       except_checked_cleanup_pop has been added to provide a measure
-       of safety; there is now a way to pass arbitrary data from the throw site
-       to the catch.
-    2. Improvements in dict_insert. A redundant call to the comparison function
-       has been eliminated, resulting in one fewer comparisons per insert
-       operation! Also a redundant test has been removed from the controlling
-       expression of the fixup loop, taking advantage of the fact that nil
-       is always black, and hence the root node always has a black parent.
-    3. Small change in dict_delete. A test in the fixup loop has been eliminated
-       by temporarily coloring the root node red. See comment and diff between
-       dict.c revision 1.25 and 1.26.
-    4. Test program blast.pl deletes keys out of order; to get in order
-       delete, initialize $factor_d to 1.
-
-New in 1.10
-
-    1. The dict_init function now correctly initializes allocator-related
-       members of the dict structure.
-    2. Tiny optimization in dict_lookup---less frequent cases tested last.
-    3. Added list_extract, for extracting list slices (more general than
-       list_transfer).
-    4. Incorporated changes from Loic Dachary: hash_free() has been
-       added for deleting all nodes; hash and compare functions
-       from the hash.c test code are now available to the user as
-       defaults if null pointers are given to hash_init() or
-       hash_create(); and hash_set_allocator restores the default
-       allocator routines if null pointers are given to it.
-    5. Changes to dict analogous to hash: dict_free() added, etc.
-    6. New exception handling module added (experimental).
-    7. Much new documentation.
-
-New in 1.9
-
-    1. Third argument of list_transfer may be null, in which case no nodes
-       are transferred. [Rationale: allows empty source list to be treated
-       without special case testing when all nodes are being transferred.]
-    2. Two new functions added to dict: dict_upper_bound and dict_lower_bound.
-       These allow for inexact and range searches.
-
-New in 1.8
-
-    1. New improved hashing function in the hash.c test code. It turns out that
-       when I changed the hash table algorithm, the blast.pl testcase was
-       hashing all to a single chain due to the pathologically bad hashing
-       function.  The new hashing function should be good enough for general use.
-       It uses each nybble of the key to index a table of 16 random 32 bit integers.
-       These integers are XOR-ed into the hash value which is rotated after each
-       XOR.
-    2. Spurious semicolon removed from the #define of HASH_VAL_T_BIT.
-    3. I fixed some incorrect comments in hash.c which still talked about the
-       old algorithm from release 1.5 and older.
-    4. The smalloc.c module is no longer supported. It's still in RCS but it's not
-       tagged as being part of release 1.8, and is not used by any of the other
-       sources. The standard library memory allocation functions are now used
-       directly. [Rationale: smalloc.c is overkill and interferes with
-       integration of the other source files into projects. Conscientious programmer
-       already ahve their own tools for debugging allocator corruption, anyway.]
-
-New in 1.7
-
-    1. Missing #include <stdlib.h> added to smalloc.h
-    2. The dict_delete() functions internals have been changed to make it much
-       more sane. This function no longer has the potential to return a node
-       other than the one that is passed to it.
-    3. The changes to dict_delete() also fix a serious bug in dict_process().
-       The dict_process computes a pointer to a node's successor before
-       invoking the user callback to process a node. If the user callback calls
-       dict_delete() on the node, under the old dict_delete() semantics it was
-       possible for the successor to get deleted instead. Thus dict_process()
-       could end up with an invalid pointer.
-    4. The changes to dict_delete() also mean that key and value information will
-       never be relocated from one node to another. User code can now rely on this
-       convenient assumption.
-
-New in 1.6
-
-    1. The extendible hashing algorithm internals have changed. This
-       has a potential impact on the behavior with respect to hashing functions
-       which were written to work well specifically with the old hashing
-       scheme. For a silly reason, in the old hashing scheme, the top N bits
-       were always taken from the results of a hashing function, for a hash
-       table size of 2^N chains. In the new scheme, the bottom N bits are taken
-       instead. [Rationale: This is change makes it easier to write portable
-       hashing functions and simplifies the functions that expand or contract
-       the table, making them more efficient.]
-    2. Added const qualifiers to the rcsid[] and right[] char arrays,
-       which shuts up the GCC compiler from complaining that these are
-       unused statics.
-
-New in 1.5
-
-    1. First two arguments to list_prune_graft() are reversed. The leftmost
-       argument is now the destination list. Moreover, the function has been
-       renamed list_transfer(). [Rationale: this ordering of parameters is
-       consistent with list_merge(), and the standard C <string.h> functions
-       also pass destination pointers on the left.  Renaming the function
-       protects against incorrect use.]
-
-    2. Red-Black tree dictionaries now support duplicate keys.  [Rationale:
-       duplicate keys could be useful in some applications.] When a dictionary
-       is created or initialized, it does not allow duplicate keys. The
-       function dict_allow_dupes() is used to set a flag in a dictionary to
-       henceforth allow duplicates.  Once made, the decision to allow
-       duplicates cannot be reversed.  [Rationale: toggling between allowing
-       and disallowing duplicates does not seem useful. Once duplicates are
-       admitted, there is no point in disallowing duplicates.] When a key is
-       sought in tree that currently allows duplicates, the leftmost node
-       containing that key is chosen from among the nodes that contain
-       duplicates of the key.  Then dict_next() can be used to fetch the
-       remaining duplicates one by one.  No particular order among the
-       duplicates may be assumed.  However, for what it may be worth, the order
-       between any two duplicates is preserved for as long as they both remain
-       in the dictionary.
-
-    3. The function prototypes in the header files have been modified to eliminate
-       parameter names.  [Rationale: parameter names in prototypes have only
-       documentary value, and may clash with macro identifiers defined in other
-       headers.]
-
-    4. Dictionary and hash table now has support for automatic allocation of
-       nodes in the insert and delete operations, which means that the user
-       can add items in one operation instead of the two operations of
-       allocating a node and inserting it. [Rationale: ease of use.] There is
-       support for user-defined allocators; the default allocators use the
-       smalloc.c routines. For any instance of a dict_t or hash_t object, the
-       user can override the allocator functions by supplying his or her
-       own pointers to suitable functions, and a context pointer that 
-       will be passed to these functions when they are called through that
-       particular dict_t or hash_t instance. [Rationale: flexibility, ease of
-       use, promotes good design.] The funtion pointers can only be set when
-       the data structure is empty. [Rationale: it is undesirable to switch to
-       a different allocator when there are nodes in the dictionary; it might
-       lead to the error of freeing a node with an incorrect allocator.]
diff --git a/libutil/kazlib/docs/MUST_READ b/libutil/kazlib/docs/MUST_READ
deleted file mode 100644
index 20ca12e..0000000
--- a/libutil/kazlib/docs/MUST_READ
+++ /dev/null
@@ -1,25 +0,0 @@
-Greetings, Programmer!
-
-I gather that because you are reading this, you are probably considering using
-the C language translation units included here in your own software.   If that
-is the case, I would like to know who you are and urge you to contact me.
-
-Here is why: I rove over this code periodically looking for defects. In fact,
-I use it in my own programming projects.  If I discover a defect, I will
-notify everyone who I know is a user of this software. If there is a serious
-defect in some code that you are using in your software project, wouldn't you
-want to be informed? In fact, there is no question that you _need_ to be
-informed!
-
-Here is what you do: simply send an e-mail message to kaz at ashi.footprints.net
-with the subject "kazlib" and the body "I am a user". Be sure that your message
-has a good return address. I will manually add your e-mail address to a list
-which I will use only for the purpose of notifications regarding Kazlib.   You
-will receive a reply to the effect that you are added. 
-
-If ever you should wish to be removed from this list, simply ask and it shall
-be done.
-
-Yours in earnest,
-
-    Kaz Kylheku
diff --git a/libutil/kazlib/docs/README b/libutil/kazlib/docs/README
deleted file mode 100644
index 08f14a1..0000000
--- a/libutil/kazlib/docs/README
+++ /dev/null
@@ -1,66 +0,0 @@
-This collection of data structures is maintained by
-Kaz Kylheku <kaz at ashi.footprints.net>
-
-INSTRUCTIONS
-
-Simply add the necessary .c and .h files to your project.  Include the
-appropriate .h file in any translation unit that interfaces with one or more of
-the kazlib modules. Then compile and link the modules together with your program.
-
-To use kazlib in a C++ project, don't compile them with a C++ compiler.
-Compile with a C compiler, and include the header files in
-your C++ translation units. Then link together the translated C and C++.
-As of release 1.2, the header files should work with C++.
-
-IMPORTANT NOTES
-
-1. Self checks
-
-The modules in this collection perform extensive self-checks, some of
-which make the performance really poor (by actually raising the overall
-asymptotic complexity of an operation, for example from O(log N) to O(N).  The
-instrumentation assertions can be disabled by compiling with the NDEBUG macro
-defined.
-
-You can check that your project does not violate the principles of
-implementation hiding in connection with its use of the kazlib modules. This
-is accomplished by defining the macro KAZLIB_OPAQUE_DEBUG at the beginning of
-any translation unit which includes the kazlib header files. Note that
-whereas this will detect violations, it will not result in a translation
-that can be linked against the kazlib. When you are done checking, turn
-off KAZLIB_OPAQUE_DEBUG and recompile. If your compiler has a special ``check only''
-mode which enables it to perform syntax and type checking without doing
-an actual translation (similar to lint), it may be a time-saving idea to
-use it in conjunction with KAZLIB_OPAQUE_DEBUG.
-
-2. Macros with side effects
-
-Some of the kazlib header files define macros that evaluate their arguments
-more than once. This means that if expressions with side effects are passed
-to these macros, undesirable and undefined behavior will happen. There is
-support in Kazlib for catching these kinds of bugs: compile with
-KAZLIB_SIDEEFFECT_DEBUG, and add the except.c and sfx.c modules to your
-object. The macros will now parse their expressions at run time to diagnose
-the presence of side effects and function calls. It's easy to add this support
-to your own code!
-
-3. Thread support
-
-POSIX thread support is enabled by predefining KAZLIB_POSIX_THREADS. Currently
-only the exception-handling module has any need for this. When compiled that
-way, it provides thread-safe exception handling. Threads can independently
-throw exceptions and each thread can install its own specific catcher
-for unhandled exceptions. Moreover, each thread can register its own
-memory allocator functions.
-
-Note: this variant of the code also depends on the ability to cast between void
-* and function pointers, which is a common language extension.
-
-4. CVS identification
-
-The source files contain declarations of a static char array variable called
-rcsid. This contains an expansion of the CVS identification of each module,
-making it possible to determine the ``bill of materials'' that went into an
-executable build. I have now wrapped the declarations of these rcsid[] arrays
-so they are conditional on KAZLIB_RCSID being defined. For many users, these
-are just a waste of space.
diff --git a/libutil/kazlib/docs/docs.ist b/libutil/kazlib/docs/docs.ist
deleted file mode 100644
index 808c029..0000000
--- a/libutil/kazlib/docs/docs.ist
+++ /dev/null
@@ -1,4 +0,0 @@
-preamble
-"\\begin{theindex}\n\\addcontentsline{toc}{section}{Index}\n"
-postamble
-"\n\\end{theindex}\n"
diff --git a/libutil/kazlib/docs/docs.ltx b/libutil/kazlib/docs/docs.ltx
deleted file mode 100644
index 139f212..0000000
--- a/libutil/kazlib/docs/docs.ltx
+++ /dev/null
@@ -1,4155 +0,0 @@
-\documentclass{article}
-\usepackage{makeidx}
-\usepackage[margin=1.0in]{geometry}
-\makeatletter
-\newcommand{\defsubsection}{\@startsection
-    {subsection}
-    {2}
-    {0pt}
-    {2.0ex plus 0.1ex minus 0.05ex}
-    {-0pt}
-    {\normalfont\normalsize\bfseries}}
-\newcommand{\defsubsubsection}{\@startsection
-    {subsection}
-    {3}
-    {0ex}
-    {2.0ex plus 0.1ex minus 0.05ex}
-    {1.0ex}
-    {\normalfont\normalsize\bfseries}}
-\renewcommand{\paragraph}{\@startsection
-    {paragraph}
-    {4}
-    {0ex}
-    {2.0ex plus 0.1ex minus 0.05ex}
-    {1.0ex}
-    {\normalsize\bfseries}}
-\makeatother
-\title{Kazlib---Reusable Components\\for C Programming}
-\author{Kaz Kylheku}
-\date{Release 1.20\\July 24, 2001}
-\makeindex
-\setcounter{tocdepth}{1}
-\setcounter{secnumdepth}{4}
-\begin{document}
-\catcode`\_=11
-\def\indextype#1{\index{#1@{\tt #1} type}}
-\def\indexmacro#1{\index{#1@{\tt #1} macro}}
-\def\indexobject#1{\index{#1@{\tt #1} object}}
-\def\indexfunc#1{\index{#1@{\tt #1} function}}
-\def\indexenum#1{\index{#1@{\tt #1} enum constant}}
-\def\synopsis{\paragraph*{Synopsis}}
-\def\constraints{\paragraph*{Constraints}}
-\def\description{\paragraph*{Description}}
-\def\example{\paragraph*{Example}}
-\maketitle
-\abstract{The aim of the Kazlib project is to provide a well-documented
-programming interface featuring commonly needed programming abstractions,
-accompanied by a high quality, portable reference implementation.
-Kazlib consists of four independent components: a list module, a hash table
-module, a dictionary module and an exception handling module. The reference
-implementations of the first three of these are based on, respectively, the
-following algorithms: doubly linked circular list with sentinel node,
-extendible hashing, and red-black tree.}
-\tableofcontents
-\section{Introduction}
-This document establishes the provisions required of an implementation of the
-Kazlib library, and describes a reference implementation thereof.
-This document specifies
-\begin{itemize}
-\item the names and types of identifiers and preprocessor symbols made
-    available by each component;
-\item identifier name spaces reserved for future use by each component;
-\item the interface syntax and semantics of each component operation;
-\item the conditions required for the well-defined execution of each operation;
-\item the externally visible behavior of each component, including global
-    side effects and the effects on the subject data structures;
-
-\item and the implementation language of Kazlib.
-\end{itemize}
-Furthermore, this document describes, but does not specify
-\begin{itemize}
-\item the implementation details of structure objects manipulated by the
-    operations of each component;
-\item objects and functions that are defined by the implementation of
-    each component but are not externally visible;
-\item the algorithms and implementation details of the operations.
-\end{itemize}
-Finally, this document does {\em not\/} specify or describe
-\begin{itemize}
-\item the specific choices for parameters which may be adjusted by an
-    installation or implementation of Kazlib.
-\item the size of any data structure which will exceed the capacity of
-    a particular installation.
-\item the mechanisms or procedures for the translation of Kazlib and
-    their integration with other translation units.
-\end{itemize}
-
-\section{References}
-\label{sec:references}
-
-\begin{trivlist}
-\item ISO 9899:1990, {\it Programming Languages---C.}
-\item {\it Introduction to Algorithms}, Thomas H. Cormen, Charles E.
-Leiserson, Ronald L. Rivest, eighth printing, 1992.
-\end{trivlist}
-
-\section{Definitions and conventions}
-The following terms shall be interpreted in accordance with the definitions
-below. Other terms appearing in this document shall be defined upon their
-first mention, indicated by {\it italic\/} type. Any terms not explicitly
-defined in this document should be interpreted according to ISO 9899-1990,
-clause 3. Failing that, they should be interpreted according to other works
-listed in section \ref{sec:references}.
-\nobreak
-\defsubsection{implementation}: A library and set of C language headers
-which conforms to the specifications of this Document.
-\index{production mode}
-\indexmacro{NDEBUG}
-\defsubsection{production mode}: A mode of operating the implementation
-in such a way that maximum efficiency of execution is achieved at the expense
-of the verification of constraints. An implementation shall provide
-a production mode, which is enabled in an implementation-defined
-manner.\footnote{An implementation may have to supply a separate set of
-libraries for production and for verification use, for instance. The
-manner of selecting libraries varies with each programming environment.}  Each
-translation unit of the program which includes a Kazlib header shall ensure that the macro {\tt
-NDEBUG} is defined prior to the inclusion of that header, otherwise the
-implementation is not said to be operated in production mode.
-\index{verification mode}
-\defsubsection{verification mode}: A mode of operating the implementation in
-such a way that maximum error checking is obtained at the cost of
-execution efficiency. An implementation shall provide a verification mode, which
-is enabled in an implementation-defined manner. If any translation unit which
-includes a Kazlib header defines the macro name {\tt NDEBUG}\footnote{The
-intent is that the standard {\tt assert} macro may be exploited
-by the implementation's headers for the purpose of provisioning verification
-mode.} prior to including that header, the implementation is not said to be in
-verification mode. The least requirements of a Kazlib implementation operated
-in verification mode, is that it shall stop translation or execution of any
-program which violates a constraint. 
-\index{undefined behavior}
-\defsubsection{undefined behavior}: Behavior of a program, upon violation of a
-requirement with respect to the use of Kazlib, or upon use of corrupt or
-incorrect data, for which this document does not impose any requirements.
-Additional undefined behaviors are:
-\begin{itemize}
-\item any behavior that is undefined by the C language standard;
-\item evaluation of an object whose contents are indeterminate;
-\item a violation of any explicit constraint stated in
-this document, if that program was built using Kazlib in production
-mode;\footnote{The intent is that violations of constraints are diagnosed by
-the implementation in verification mode, and hence do not lead to undefined
-behavior.}
-\item a violation of any requirement stated in this document that
-is not designated as a constraint, and is introduced using the word
-{\it shall}; and
-\item any other construct for which no definition of behavior can be deduced
-from this document.
-\end{itemize}
-If a program invokes undefined behavior of any kind, the Kazlib implementation
-is absolved from any requirements as to what events should ensue.  The
-implementation may respond by invoking undefined behavior in the C language
-sense, or it may detect the behavior and terminate with a diagnostic message.
-\defsubsection{implementation-defined}: An adjective which, when appearing
-in the description of a feature, represents a requirement that the
-implementor must supply a definition, and document that
-definition. This adjective is applied to both behavior and to results.
-Implementation-defined behavior is behavior which depends on the
-characteristics of an implementation.\footnote{It is not considered adequate
-for the implementor to allow implementation-defined behavior to produce
-unpredictable effects or to terminate the program when such behavior is
-invoked.}  When said of a result,
-implementation-defined means that a value is successfully computed, but depends
-on the characteristics of the implementation. It is possible for the presence of a
-requirement on a program to be described as implementation-defined, giving the
-implementor a choice whether to make that requirement or not. If a program
-violates a requirement whose presence is implementation-defined, that program's
-behavior is undefined in any implementation which elects to in fact impose that
-requirement.
-\index{implementation-defined}
-\defsubsection{unpredictable result}: A successfully computed value which is
-unreliable because some procedure or data failed to satisfy a property required
-by the computation.
-\defsubsection{constraint}: A semantic restriction with which a program must
-comply. Some sections of this Document contain paragraphs under the heading
-{\it Constraints\/} which list all constraints pertaining to the described
-feature. When operated in production mode, the Kazlib implementation
-is not required to diagnose constraint violations. When operated in
-verification mode, the Kazlib implementation must halt translation or
-execution of a program which violates a constraint.
-\index{constraint}
-\defsubsection{comparison function}: A function which accepts two arguments
-\index{comparison function}
-of type \verb|const void *| and returns a value of type int based on
-a ranking comparison of these arguments, and which satisfies the following
-additional semantic properties. If the two arguments are deemed to be equal, the
-function must return zero. If the first argument is determined to have a
-greater rank than the second, a positive value is returned. Otherwise if the
-first argument is determined to have a lesser rank than the second, a negative
-value is returned. The rank is computed as if each value has associated with it
-an integer, not necessarily unique, and as if these integers are compared for ordinary equality or
-inequality when values are said to be compared.  The assignment of integers is
-up to the designer of the comparison function, and does not change between
-successive invocations of the function.\footnote{Of course, an actual
-comparison function need not assign actual integer ranks to data items, but it
-must behave as if such ranks were assigned.}
-If a comparison function is invoked in the context of an operation on some data
-structure, it shall not invoke any operation on any component of that same
-structure.\footnote{Thus, if a comparison function is invoked from, for
-instance, {\tt list_sort}, it must not call any list operations that 
-inspect or modify the list being sorted, or any of its constituent nodes.}
-\defsubsection{opaque data type}: A data type whose precise definition is
-not documented, and which is intended to be manipulated only using the
-documented interface, which consists of a set of functions.  Many data types in
-Kazlib are described as opaque. A program which bypasses the documented
-interfaces in inspecting or manipulating these data types invokes undefined
-behavior, and is not portable among Kazlib implementations.
-\defsubsection{user}: \index{user} The program which uses Kazlib.
-\defsubsection{user data}: \index{user data} Data provided by the program
-to which Kazlib stores a pointer, but otherwise does not inspect or modify.
-
-\section{Environment}
-\label{sec:environment}
-
-The translation and use of Kazlib requires a conforming, hosted implementation
-of the C language which meets the following additional minimal requirements:
-\begin{enumerate}
-\item The C implementation distinguishes external names by at least their
-initial 15 characters\footnote{The ISO 9899:1990 standard demands only that
-external names be distinguished by their initial six characters.}. External
-names that are distinct in their first 15 characters are treated by the
-implementation as distinct names.  Upper and lower case letters in external
-identifiers need not be treated as distinct.
-\item The C implementation does not claim the identifier \verb|__cplusplus|
-for its internal use as a preprocessor symbol or keyword.
-\end{enumerate}
-If Kazlib headers are used by a C++ program, the C++ implementation
-meets these additional requirements:
-\begin{enumerate}
-\item the C++ implementation identifies itself by predefining the preprocessor
-symbol \verb|__cplusplus|;
-\item the C++ implementation is be capable of linkage against
-the C implementation with which the Kazlib source files units were translated.
-\end{enumerate}
-The Kazlib headers shall not make use of any names that are claimed
-by the C++ programming language, and shall ensure that the \verb|extern "C"|
-mechanism is used for all declarations when they are included into a C++
-translation unit, or otherwise provide compatibility with C++.\footnote{The
-intent is that the Kazlib implementation could, in principle, provide 
-a separate set of headers for use with each language.}
-
-In programming environments that support the programming mechanism of multiple
-threads of execution an implementation of Kazlib may be designated as {\it
-thread safe}.  To be called thread safe, it must guarantee that the use of an
-object by one thread cannot visibly interact or interfere with the concurrent
-or interleaved use of another object by another thread. If a Kazlib
-implementation that is not thread safe is provided for an environment which
-supports threads, it shall be accompanied by documentation which describes
-the extent of this limitation.
-
-A Kazlib implementation can also be designated as being {\it async safe}.
-The minimum requirement for this designation is that an operation on an object
-can be interrupted by delivery of an asynchronous signal and from within the
-catching function for that signal, it is safe to perform an operation on
-another object.  An implementation shall document that it is async safe,
-or the extent to which it fails to be async safe.
-
-\section{General restrictions}
-
-\subsection{Headers}
-
-The Kazlib headers may be included in any order, and may be included more than
-once. Prior to the inclusion of a Kazlib header, the translation unit shall not
-define any macro name that has the same spelling as a C language keyword. The
-Kazlib headers may behave as though they include arbitrary standard C headers,
-so any requirements related to the inclusion of standard headers apply to
-Kazlib headers.  A header shall be included before the first reference to any
-of the functions, types or macros that it defines.
-
-If one or more preprocessor symbols whose names begin with the sequence
-\verb|KAZLIB_| are defined prior to the inclusion of a Kazlib header,
-the behavior is implementation-defined.
-
-\subsection{Reserved macros}
-
-A Kazlib header defines all of the macros explicitly listed in the section of
-this document that defines the contents of that header. It may also define
-additional macros that belong to the macro namespace reserved by that header.
-The translation unit that includes the header shall not \verb|#define| or
-\verb|#undef| any of these macros.
-
-A header may define function-like macros that supplement existing functions,
-provided that such macros do not cause multiple evaluation of arguments except
-as explicitly permitted, and are safe to use wherever the corresponding
-function call would be. These function-like macros may be subject to
-\verb|#undef|.\footnote{In principle, an implementation may provide, within the
-reserved namespaces, additional functions not specified in this document, and
-function-like macro equivalents of these functions. A program that uses such
-identifiers in a block or function scope should use {\tt \#undef} on these
-identifiers prior to their use.}
-
-\subsection{Reserved symbols}
-
-Each Kazlib header provides file scope declarations for the typedef names,
-struct tags, enum constants and function names listed in its corresponding
-section in this document. Moreover, each header may define additional such
-names that fall into the documented reserved namespaces.
-
-The behavior is undefined if a translation unit that includes a Kazlib header
-defines any identifier that is the same as an identifier reserved by the header
-in the same scope and namespace.\footnote{Therefore, it is permitted to redeclare
-or redefine the identifiers reserved by a previously included Kazlib header,
-provided that the declarations or definitions are in a different namespace or
-scope. Reserved names may be redeclared in a block scope, or used as
-statement labels which have function scope and are in their own namespace.}
-
-The behavior is also undefined if the program contains a definition of an
-object or function with external linkage whose name matches an external object
-of unction defined  by Kazlib component that is used as part of the
-program, or whose name is in a namespace reserved by that
-component.\footnote{This restriction exists whether or not the corresponding Kazlib
-header is included.} 
-
-Lastly, the behavior is undefined if a translation unit defines a macro whose
-name is in the space of reserved symbols of a Kazlib header that is included in
-that translation unit.
-
-\subsection{Argument aliasing}
-
-Kazlib provides functions that operate on objects of various types.  Pointers
-to objects are passed to these functions, thereby giving rise to the
-possibility of {\it aliasing}---passing of objects that wholly or partially
-overlap.  The program shall not present aliased objects to any Kazlib function.
-Objects of distinct types shall not be aliased in a function call under any
-circumstances.
-The aliasing of two or more objects of compatible type is permitted only as
-explicitly documented in the description of a function; in all such
-circumstances, only exact overlapping is permitted.\footnote{That is to say,
-where explicitly allowed, a pointer to the same object may be specified for two
-(or more) parameters of like type.}
-
-\subsection{Object initialization}
-
-The Kazlib opaque data types can only be initialized with the initialization
-functions provided by the Kazlib library, or by implementation-defined
-initialization functions.\footnote{Of course, the use of implementation-defined
-functions results in programs that are not portable among library
-implementations.} An opaque object that is initialized by a method other than
-by being passed to an appropriate initialization function, or that is not
-initialized at all, has indeterminate contents.  A pointer to an object having
-indeterminate contents may be passed to an initialization function; the object
-then has well-determined contents.
-
-An object whose initialization function is capable of indicating failure is
-considered indeterminate if the attempt to initialize that object using that
-function does in fact fail. The program shall not attempt to deinitialize such
-an object. The implementation shall reclaim any resources that were allocated
-for an object whose initialization failed. This reclamation need
-not be immediate, but may be delayed; however, the delay shall not
-give rise to the possibility of resource leaks in any correct program.
-
-Those objects for which deinitialization operations are defined should be
-subject to these operations when these objects are no longer needed.  Failure
-to apply the deinitialization functions may result in the leakage of resources.
-
-\subsection{Object copying}
-
-Certain data types may be sensitive to their own location in memory.  This
-means that copying their values by assignment or \verb|memcpy| results in the
-copy having an indeterminate value which cannot be used.  All opaque types in
-Kazlib are assumed to have this property; copying the value of an opaquely
-typed object to another suitably typed object causes the destination
-object to have indeterminate contents. 
-
-\section{List component}
-
-The List component provides a set of functions, macros and type declarations
-which together provide a library for maintaining a possibly empty ordered set
-of elements, called a {\it list}. This list has the following properties:
-\index{List}\begin{enumerate}
-\item If the list is not empty, a first and last element can be identified.
-    In a list having only one element, that one element is both the first and
-    last element.
-\item Each element that is not the last element has another element as its
-    {\it successor}.
-    \index{successor!of a list element}
-    \index{List!successor of an element}
-\item Each element that is not the first element has a {\it
-    predecessor}.
-    \index{predecessor!of a list element}
-    \index{List!predecessor of an element}
-\item No element is the predecessor or successor of more than one element.
-\item If one element is the successor of another, the other is necessarily the
-    predecessor of the first.
-\item Each element is associated with arbitrary {\it satellite\/} data.
-\end{enumerate}
-The {\it size} of a list, also known as the {\it list count}, is simply the
-number of elements contained in it.\index{size!of a list}\index{List!count}
-
-A list imposes a maximum value on the number of nodes that may be in it
-simultaneously. This is known as the list's {\it capacity}. A list that
-has the maximum number of nodes is said to be full.
-
-\subsection{Interface}
-
-\subsubsection{The {\tt list.h} header}
-
-Each C or C++ translation unit that is to use the functionality of
-the List component shall include the header \verb|list.h|. This header
-shall contain declarations of types and external functions, and definitions of
-macros.
-The following typedef names shall be defined:\index{List!typedef names}
-\index{typedefs!defined by List}
-\begin{verbatim}
-    list_t                      listcount_t
-    lnode_t                     lnodepool_t
-\end{verbatim}
-In addition, the following structure tags may be defined:\index{List!tag names}
-\index{tags!defined by List}
-\begin{verbatim}
-    struct list_t
-    struct lnode_t
-    struct lnodepool_t
-\end{verbatim}
-The following external function names shall be declared:
-\index{List!function names}\index{functions!defined by List}
-\begin{verbatim}
-    list_append                 list_prev                          
-    list_contains               list_process                       
-    list_count                  list_return_nodes                  
-    list_create                 list_sort                          
-    list_del_first              list_find
-    list_del_last               list_transfer                      
-    list_delete                 list_verify                        
-    list_destroy                lnode_borrow                       
-    list_destroy_nodes          lnode_create                       
-    list_extract                lnode_destroy                      
-    list_first                  lnode_get                          
-    list_init                   lnode_init                         
-    list_ins_after              lnode_is_in_a_list                 
-    list_ins_before             lnode_pool_create                  
-    list_is_sorted              lnode_pool_destroy                 
-    list_isempty                lnode_pool_init                    
-    list_isfull                 lnode_pool_isempty                 
-    list_last                   lnode_pool_isfrom                  
-    list_merge                  lnode_put                          
-    list_next                   lnode_return                       
-    list_prepend                
-\end{verbatim}
-The following preprocessor symbols (macros) shall be defined:
-\index{List!macro names}\index{macros!defined by List}
-\indexmacro{LISTCOUNT_T_MAX}
-\indexmacro{LIST_H}
-\begin{verbatim}
-    LISTCOUNT_T_MAX
-    LIST_H\end{verbatim}
-\index{symbols!reserved by List}\index{List!reserved symbols}
-Macro identifiers which begin with the upper-case prefix \verb|LIST| are
-reserved for future extensions to the \verb|list.h| header, as are
-names in the ordinary and tag namespaces which begin with
-\verb|list_| or \verb|lnode_|. External names which begin with \verb|list_| or
-\verb|lnode_| are reserved by the Kazlib library regardless of what header
-files are included.
-
-\subsubsection{The {\tt list_t} type}
-
-\indextype{list_t}
-The type \verb|list_t| is an opaque data type which maintains information about the
-current state of a single list.  A list consists of an instance of the
-\verb|list_t| type, plus zero or more instances of the type \verb|lnode_t|. An
-instance of the \verb|list_t| type can be dynamically created using the
-\verb|list_create| function, and destroyed by the \verb|list_destroy| function.
-Alternately, the program can declare an object of type \verb|list_t| and have
-it initialized via the \verb|list_init| function. 
-
-\subsubsection{The {\tt listcount_t} type}
-
-\indextype{listcount_t}
-\indexmacro{LISTCOUNT_T_MAX}
-The type \verb|listcount_t| is an unsigned integral type which represents
-the number of nodes in a list. The specific choice of unsigned integral type
-is implementation defined. The \verb|LISTCOUNT_T_MAX| macro expands to a
-constant expression of type \verb|listcount_t| which specifies the maximum
-value of that type.\footnote{For example, if the implementation defines
-{\tt listcount_t} as an alias for the type unsigned long, then 
-{\tt LISTCOUNT_T_MAX} must have the same value as {\tt ULONG_MAX}.}
-
-\subsubsection{The {\tt lnode_t} type}
-
-\indextype{lnode_t}
-The type \verb|lnode_t| is an opaque type that represents a single node of a
-list. A node contains a a reference to satellite data provided by the user,
-and also stores the key that is associated with the node when it is inserted.
-Nodes may be dynamically created by the \verb|lnode_create| function.
-Alternately, the program may supply an \verb|lnode_t| object that can be
-initialized by the \verb|lnode_init| function. 
-
-\subsubsection{The {\tt lnodepool_t} type}
-
-\indextype{lnodepool_t}
-The \verb|lnodepool_t| type provides an alternate method for supplying list
-nodes to the application. A user-supplied or dynamically allocated fixed size
-array of nodes is converted into a a {\it pool\/} of nodes from which free
-nodes may be obtained and to which they may be returned. A user-supplied node
-pool is created by the function \verb|lnode_pool_init| which requires a pointer
-to an object of type \verb|lnode_pool_t|, a pointer to the first element of an
-array of \verb|lnode_t| objects, as well as an integer representing the size of
-the array. Alternately, the function \verb|lnode_pool_create| will dynamically
-allocate an object of type \verb|lnode_pool_t| containing the specified number
-of list nodes. 
-
-\subsubsection{The {\tt list_append} function}
-
-    \indexfunc{list_append}
-    \index{List!appending a node}
-    \index{append node to list}
-    \synopsis
-    \begin{verbatim}
-    void list_append(list_t *, lnode_t *);\end{verbatim}
-
-    \constraints
-    The second argument shall not refer to a node that is already in a list
-    or in a list node pool. The first argument shall not refer to a list
-    that is full.
-
-    \description
-    The append operation causes the node pointed at by the second
-    argument to become the last node in the list pointed at by the first
-    argument.\footnote{That is to say, after the operation, the
-    {\tt list_last} function, when applied to the list, shall return a pointer
-    to that node.}
-
-    If the first argument is an expression with side effects, the behavior
-    is undefined.\footnote{Thus, the implementation may provide a macro
-    version of {\tt list_append} which evaluates the first argument
-    more than once.}
-    \index{macros!and side effects}
-
-\subsubsection{The {\tt list_contains} function}
-
-    \indexfunc{list_contains}
-    \index{List!testing for presence of node}
-    \nobreak
-    \synopsis
-    \begin{verbatim}
-    int list_contains(list_t *, lnode_t *node);\end{verbatim}
-    \nobreak
-    \description
-    \nobreak
-    The \verb|list_contains| function shall return 1 if the node
-    pointed at by the second argument is in the list pointed at by the first
-    argument.  Otherwise, it shall return 0.
-
-\subsubsection{The {\tt list_count} function}
-
-    \indexfunc{list_count}
-    \index{List!count}
-    \index{List!size}
-    \synopsis
-    \begin{verbatim}
-    listcount_t list_count(list_t *);\end{verbatim}
-
-    \description
-
-    The \verb|list_count| function returns a value which represents the number
-    of nodes currently stored in the list pointed at by the argument.
-
-\subsubsection{The {\tt list_create} function}
-
-    \indexfunc{list_create}
-    \index{List!creation of}
-    \index{create!list object}
-    \synopsis
-    \begin{verbatim}
-    list_t *list_create(listcount_t);\end{verbatim}
-
-    \description
-    The \verb|list_create| function instantiates and initializes an object of
-    type \verb|list_t|, and returns a pointer to it unless insufficient
-    resources exist for the creation of the object, in which case a null
-    pointer is returned.
-
-    The value of the function's argument establishes, for the entire duration
-    of the list object, its capacity.
-
-    The newly created list object is empty.
-
-\subsubsection{The {\tt list_del_first} function}
-
-    \index{List!first node}
-    \indexfunc{list_del_first}
-    \index{List!deletion}
-    \index{delete!first node of a list}
-    \synopsis
-    \begin{verbatim}
-    lnode_t *list_del_first(list_t *);\end{verbatim}
-
-    \constraints
-    The argument shall not point to an empty list.
-
-    \description
-    The \verb|list_del_first| function removes the first node from the
-    list pointed at by the argument and returns a pointer to that
-    node. 
-
-    If the argument is an expression with side effects, the behavior is
-    undefined.\index{macros!and side effects}
-
-\subsubsection{The {\tt list_del_last} function}
-
-    \index{List!last node}
-    \indexfunc{list_del_last}
-    \index{List!deletion}
-    \index{delete!last node of a list}
-    \synopsis
-    \begin{verbatim}
-    lnode_t *list_del_last(list_t *);\end{verbatim}
-
-    \constraints
-    The argument shall not point to an empty list.
-
-    \description
-    The \verb|list_del_last| function removes the last node from the list
-    specified by the argument, and returns a pointer to that node. If,
-    prior to the operation, that node had a predecessor, that predecessor
-    shall become the new last node of the list. Otherwise, the list
-    shall become empty.
-
-    The new value of the list count shall be one less than its value
-    prior to the call to this function.
-
-    If the argument is an expression with side effects, the behavior is
-    undefined.\index{macros!and side effects}
-
-\subsubsection{The {\tt list_delete} function}
-
-    \indexfunc{list_delete}
-    \index{List!deletion}
-    \index{delete!arbitrary node of a list}
-    \synopsis
-    \begin{verbatim}
-    lnode_t *list_delete(list_t *, lnode_t *);\end{verbatim}
-
-    \constraints
-    The second argument shall point to a node that is inside the list
-    pointed at by the first argument.
-
-    \description
-    The \verb|list_delete| function removes the node pointed at by its
-    second argument from the list pointed at by its first argument.
-    A pointer to the deleted node is returned.
-
-\subsubsection{The {\tt list_destroy} function}
-
-    \indexfunc{list_destroy}
-    \index{List!destruction of}
-    \synopsis
-    \begin{verbatim}
-    void list_destroy(list_t *);\end{verbatim}
-
-    \constraints
-    The argument shall point to an empty list.
-
-    \description
-    The empty list pointed at by the argument is destroyed. If the list has
-    not been created by a call to the \verb|list_create| function, the
-    behavior is undefined.
-
-    A pointer that previously referred to a list that has been disposed by
-    \verb|list_destroy| has an indeterminate value.
-
-\subsubsection{The {\tt list_destroy_nodes} function}
-
-    \indexfunc{list_destroy_nodes}
-    \synopsis
-    \begin{verbatim}
-    void list_destroy_nodes(list_t *);\end{verbatim}
-
-    \description
-    The nodes, if any, contained in the list pointed at by the argument are
-    disposed of as if by a call to the \verb|lnode_destroy| function. If any
-    node contained in the list was created by means other than the
-    \verb|lnode_create| function, the behavior is undefined.
-
-    After the operation, the list is empty.
-
-    Any pointer that referred to any of the destroyed nodes takes on an
-    indeterminate value.
-
-\subsubsection{The {\tt list_extract} function}
-
-    \index{List!node range extraction}
-    \indexfunc{list_extract}
-    \synopsis
-    \begin{verbatim}
-    void list_extract(list_t *, list_t *, lnode_t *, lnode_t *);\end{verbatim}
-
-    \constraints
-    The second argument points to the {\it source list}. The third
-    argument is either null, or points to a node that is an occupant
-    of the source list. This node is called the {\it starting node}.
-    The fourth argument is either null, or points to a node that is
-    an occupant of the source list. This node is called the {\it ending
-    node}. If the starting node and ending node are both specified, and are
-    distinct nodes, then the starting node shall appear earlier in the source
-    list than the ending node.
-
-    The transfer request shall not call for the capacity of the  destination
-    list to be exceeded.
-
-    \description
-    The \verb|list_extract| function moves nodes from the source
-    list to the {\it destination list\/} pointed at by the first
-    argument.\footnote{This right-to-left direction of transfer is consistent
-    with the semantics of standard C library functions such as {\tt memmove} or
-    {\tt strcpy}.}
-
-    If the third and fourth arguments are not null, the entire range of nodes
-    from the starting node and to the ending node, inclusive, is transferred
-    from the source list to the end of the destination list, where they appear
-    in their original order. Other nodes in the source list, if any, are
-    unaffected.
-
-    If the third and fourth arguments both point to the same node, that
-    node alone is transferred to the end of the destination list.
-
-    If either the third argument or the fourth argument is null, or both are null,
-    no transfer of nodes takes place.
-
-    The source and destination list may be the same object.
-
-\subsubsection{The {\tt list_first} function}
-
-    \index{List!first node}
-    \indexfunc{list_first}
-    \synopsis
-    \begin{verbatim}
-    lnode_t *list_first(list_t *);\end{verbatim}
-
-    \description
-    If the list pointed at by the argument is an empty list, a null pointer
-    is returned. Otherwise, a pointer to the first node in that list is
-    returned.
-
-    If the argument is an expression with side effects, the behavior is
-    undefined.\index{macros!and side effects}
-
-\subsubsection{The {\tt list_init} function}
-
-    \indexfunc{list_init}
-    \synopsis
-    \begin{verbatim}
-    list_t *list_init(list_t *, listcount_t);\end{verbatim}
-
-    \constraints
-    The second argument shall not have a zero value.
-
-    \description
-    The \verb|list_init| function initializes the list object pointed at by the
-    first argument, turning it into a valid, empty list. If the object is an
-    already initialized list, the behavior is undefined. A list returned by
-    \verb|list_create| is considered initialized. The second argument 
-    specifies the maximum number of nodes that may simultaneously occupy the
-    list.
-
-    The value returned is that of the first argument.
-
-\subsubsection{The {\tt list_ins_after} function}
-
-    \indexfunc{list_ins_after}
-    \index{insert!node into list}
-    \index{List!insertion}
-    \synopsis
-    \begin{verbatim}
-    void list_ins_after(list_t *, lnode_t *, lnode_t *);\end{verbatim}
-
-    \constraints
-    The first argument shall point to a list that is not already full.  The
-    second argument shall point to a node, called the {\it new node}, that is not
-    already an occupant of the list pointed at by the first argument, nor
-    of any other list or node pool object. The third
-    argument shall point to a node, called the {\it reference node}, that is an
-    occupant of the list.
-
-    \description
-    The new node becomes an occupant of the list, such that its predecessor
-    is the reference node. If the reference node has a successor, the
-    new node is inserted between the reference node and that successor.
-    Otherwise, the new node becomes the last node of the list.
-
-\subsubsection{The {\tt list_ins_before} function}
-
-    \indexfunc{list_ins_before}
-    \index{insert!node into list}
-    \index{List!insertion}
-    \synopsis
-    \begin{verbatim}
-    void list_ins_before(list_t *, lnode_t *, lnode_t *);\end{verbatim}
-
-    \constraints
-    The first argument shall point to a list that is not already full.  The
-    second argument shall point to a node, called the {\it new node}, that is not
-    already an occupant of the list pointed at by the first argument, nor
-    of any other list or node pool object. The third
-    argument shall point to a node, called the {\it reference node}, that is an
-    occupant of the list.
-
-    \description
-    The new node becomes an occupant of the list, such that its successor
-    is the reference node. If the reference node has a predecessor, the
-    new node is inserted between the reference node and that predecessor.
-    Otherwise, the new node becomes the first node of the list.
-    
-\subsubsection{The {\tt list_is_sorted} function}
-\label{list:is:sorted}
-    \indexfunc{list_is_sorted}
-
-    \synopsis
-    \begin{verbatim}
-    int list_is_sorted(list_t *,
-            int (const void *, const void *));\end{verbatim}
-
-    \description
-    The first argument points to a list object. The second is assumed to
-    point to a comparison function.
-    
-    If the list has exactly one node or is empty, $1$ is returned
-    unconditionally.  Otherwise, nodes of the list are examined to
-    determine whether they are in a sorted order according to the comparison
-    function. This is true if the integer ranks of their data items,
-    examined from the first node of the list through to the last node, form a
-    monotonically increasing sequence. If the nodes are in order, the value $1$
-    is returned. Otherwise $0$ is returned.
-    
-    If the list has two or more nodes, and the second argument is a pointer to
-    a function that has the correct type, but does not satisfy the semantic
-    properties of a comparison function, the result is unpredictable, but is
-    guaranteed to be one of the values~$0$~or~$1$. 
-
-\subsubsection{The {\tt list_isempty} function}
-
-    \indexfunc{list_isempty}
-    \synopsis
-    \begin{verbatim}
-    int list_isempty(list_t *);\end{verbatim}
-
-    \description
-    The \verb|list_isempty| function returns $1$ if the list pointed at by
-    the first argument is empty. Otherwise it returns $0$.
-
-\subsubsection{The {\tt list_isfull} function}
-
-    \indexfunc{list_isfull}
-    \synopsis
-    \begin{verbatim}
-    int list_isfull(list_t *);\end{verbatim}
-
-    \description
-    The \verb|list_isfull| function returns $1$ if the list pointed at by
-    the first argument is full. Otherwise it returns $0$.
-    A list is considered full when it contains the maximum number of nodes
-    that was specified upon its initialization.
-
-    If the argument is an expression with side effects, the behavior is
-    undefined.\index{macros!and side effects}
-
-\subsubsection{The {\tt list_last} function}
-
-    \index{List!last node}
-    \indexfunc{list_last}
-    \synopsis
-    \begin{verbatim}
-    lnode_t *list_last(list_t *);\end{verbatim}
-
-    \description
-    If the list pointed at by its first argument is empty, the \verb|list_last|
-    function returns a null pointer. Otherwise it returns a pointer to the
-    last node.
-
-    If the argument is an expression with side effects, the behavior is
-    undefined.\index{macros!and side effects}
-
-\subsubsection{The {\tt list_merge} function}
-
-    \index{List!merge operation}
-    \indexfunc{list_merge}
-    \synopsis
-    \begin{verbatim}
-    void list_merge(list_t *, list_t *,
-            int (const void *, const void *));\end{verbatim}
-
-    \constraints
-    The list pointed at by the first argument is called the {\it destination
-    list}. The second argument points to the {\it source list}. The third
-    argument points to a comparison function.  The sum of the number of nodes
-    occupying the source list and the destination list shall not exceed the
-    maximum number of nodes that are permitted to occupy the destination list.
-    Furthermore, both the source and destination list shall be sorted such that
-    a call to \verb|list_is_sorted| given a pointer to either list as a first
-    argument, and the pointer to the comparison function as its second
-    argument, shall yield the value $1$.
-
-    \description
-    Nodes from the sorted source list are merged into the sorted destination
-    list. After the operation, the source list is empty and the destination
-    list contains all of the nodes it contained prior to the operation, as well
-    as all of the nodes that the source list contained. The nodes are in sorted
-    order according to the comparison function.
-
-    If the third argument is a pointer to a function that has the correct type,
-    but does not fulfill the semantic properties of a comparison function, the
-    order of the nodes in the destination list is unpredictable.
-
-    If the source and destination list are the same object, the
-    \verb|list_merge| operation has no effect.
-
-\subsubsection{The {\tt list_next} function}
-
-    \indexfunc{list_next}
-    \synopsis
-    \begin{verbatim}
-    lnode_t *list_next(list_t *, lnode_t *);\end{verbatim}
-
-    \constraints
-    The node pointed at by the second argument is an occupant of the list pointed
-    at by the first argument.
-
-    \description
-    If the node pointed at by the second argument has a successor, a pointer to
-    that successor is returned. Otherwise, a null pointer is returned.
-
-    If the second argument is an expression which has side effects, the behavior
-    is undefined.\index{macros!and side effects}
-
-\subsubsection{The {\tt list_prepend} function}
-
-    \indexfunc{list_prepend}
-    \index{List!prepending a node}
-    \index{prepend node to list}
-    \synopsis
-    \begin{verbatim}
-    void list_prepend(list_t *, lnode_t *);\end{verbatim}
-
-    \constraints
-    The second argument shall not refer to a node that is already in a list
-    or in a list node pool. The first argument shall not refer to a list
-    that is full.
-
-    \description
-    The prepend operation causes the node pointed at by the second
-    argument to become the first node in the list pointed at by the first
-    argument. After the operation, the \verb|list_first| function, when
-    applied to the list, shall return a pointer to that node.
-    If, prior to to the operation, the list is empty, then the prepended node
-    shall become the first node in that list, otherwise, the prepended node
-    becomes the predecessor of what was previously the first node.
-
-    If the first argument is an expression with side effects, the behavior
-    is undefined.\index{macros!and side effects}
-
-\subsubsection{The {\tt list_prev} function}
-
-    \indexfunc{list_prev}
-    \synopsis
-    \begin{verbatim}
-    lnode_t *list_prev(list_t *, lnode_t *);\end{verbatim}
-
-    \constraints
-    The node pointed at by the second argument is an occupant of the list pointed
-    at by the first argument.
-
-    \description
-    If the node pointed at by the second argument has a predecessor, a pointer to
-    that predecessor is returned. Otherwise, a null pointer is returned.
-
-    If the second argument is an expression which has side effects, the behavior
-    \index{macros!and side effects}
-    is undefined.
-
-\subsubsection{The {\tt list_process} function}
-
-    \indexfunc{list_process}
-    \synopsis
-    \begin{verbatim}
-    void list_process(list_t *, void *,
-            void (*)(list_t *, lnode_t *, void *));\end{verbatim}
-    \nobreak
-    \description
-    The \verb|list_process| function iterates over the nodes of a list,
-    and for each node invokes a callback function.\footnote{In most cases,
-    it is more convenient and preferable to 
-    iterate over the list using explicit calls to {\tt list_first}
-    and {\tt list_next}.}
-    The second argument is a {\it context pointer\/} which can have any value.
-    The third argument of
-    \verb|list_process| shall be a pointer to a function which is compatible
-    with the specified type. If the list contains one or more nodes,
-    then the function is invoked once for each node, in order from first
-    to last. On each invocation, the first argument of the callback is a
-    pointer to the list; the second argument is a pointer to a node, called
-    the {\it subject node}; and the third argument repeats the context pointer
-    value that was originally passed to \verb|list_process|.
-
-    The callback function may delete the subject node by, for instance, calling
-    \verb|list_delete|. It may insert new nodes to any place in the list;
-    however, if such an insertion causes the subject node to acquire
-    a new successor, it is implementation-defined whether upon returning
-    from the callback function, the traversal shall continue with the
-    new successor, or with the original successor.
-    
-    The callback function, and any function invoked from the callback
-    function, shall not destroy the list or make any modifications
-    other than the insertion of new nodes, or the deletion of the 
-    subject node.
-
-    The callback function may recursively invoke \verb|list_process| for the
-    same list or for a different list; the callback invocations arising out of
-    the nested call inherit all of the restrictions of the outer callback in
-    addition to being subject to the usual restrictions.\footnote{This means,
-    for instance, that if two callbacks are in progress for different
-    subject nodes from the same list, the inner callback may not delete
-    its subject node, because it inherits the restriction that the only
-    permitted deletion is the outer callback's subject node.}
-
-    The callback function may freely operate on a different list,
-    subject to any inherited restrictions.
-
-\subsubsection{The {\tt list_return_nodes} function}
-
-    \indexfunc{list_return_nodes}
-    \synopsis
-    \begin{verbatim}
-    void list_return_nodes(list_t *, lnodepool_t *);\end{verbatim}
-
-    \description
-
-    Every node in the list specified by the first argument
-    is returned to the node pool specified by the second argument
-    If the list contains a node that has not been allocated
-    from that node pool, the behavior is undefined.
-
-\subsubsection{The {\tt list_sort} function}
-
-    \index{List!sort operation}
-    \indexfunc{list_sort}
-    \synopsis
-    \begin{verbatim}
-    void list_sort(list_t *, int (const void *, const void *));\end{verbatim}
-
-    \description
-
-    The \verb|list_sort| function changes the order of the nodes of the list
-    specified by the first argument according to the comparison function
-    pointed at by the second argument. 
-
-    If the list is empty, or contains only one node, the comparison function is
-    not called.
-
-    Whenever the comparison function is invoked, its arguments are are the data
-    pointers stored in two distinct nodes of the list.
-
-\subsubsection{The {\tt list_find} function}
-
-    \index{List!find operation}
-    \indexfunc{list_find}
-    \synopsis
-    \begin{verbatim}
-    lnode_t *list_find(list_t *,
-           const void *, int (const void *, const void *));\end{verbatim}
-
-    \description
-
-    The \verb|list_find| function exhaustively searches the key for a node
-    whose satellite data matches a search key according to the comparison
-    function. The first argument is the list to be searched, the second
-    argument specifies the search key and the third argument is a pointer
-    to the comparison function.
-
-    The comparison function is invoked to compare the key against the
-    satellite data of successive nodes of the list, starting with the first
-    node. A pointer to the first node for which the comparison function returns
-    zero is returned.
-
-    If the list is empty, or the comparison function returns non-zero for
-    each item, a null pointer is returned.
-
-\subsubsection{The {\tt list_transfer} function}
-
-    \index{List!node transfer}
-    \indexfunc{list_transfer}
-    \synopsis
-    \begin{verbatim}
-    void list_transfer(list_t *, list_t *, lnode_t *);\end{verbatim}
-
-    \constraints
-    The third argument is either null, or it points at a node which is an
-    occupant of the list pointed at by the second argument.
-
-    The transfer request shall not call for the capacity of the  destination
-    list to be exceeded.
-
-    \description
-    The \verb|list_transfer| function moves nodes from the list
-    pointed at by the second argument to the list pointed at by
-    the first argument.
-
-    If the third argument is not null, it specifies the node in the source list
-    at which the transfer begins. That node, its successor, and all 
-    subsequent nodes, are transferred to the end of the destination list where
-    they appear in their original order. Other nodes in the source list are
-    unaffected.
-
-    If the third argument is null, no transfer of nodes takes place.
-
-    The source and destination list may be the same object.
-
-    If \verb|DL|, \verb|SL| and \verb|SN| are appropriately typed expressions,
-    the function call
-
-\begin{verbatim}
-    void list_transfer(DL, SL, SN);
-\end{verbatim}
-    is equivalent to 
-\begin{verbatim}
-    list_extract(DL, SL, SN, list_last(SL));
-\end{verbatim}
-    except that \verb|SL| is evaluated only once.
-
-\subsubsection{The {\tt list_verify} function}
-
-    \indexfunc{list_verify}
-    \synopsis
-    \begin{verbatim}
-    int list_verify(list_t *list);\end{verbatim}
-
-    \description
-    The intent of the \verb|list_verify| function is to perform a verification
-    on the list object, regardless of whether the Kazlib implementation is
-    operated in verification or production mode. If the list objects
-    and its constituent nodes have been correctly manipulated, and the
-    program has not caused any undefined behaviors, the value $1$ is returned.
-    Otherwise, the function may be able to, but is not guaranteed to, detect
-    corruption, and return the value zero.
-
-\subsubsection{The {\tt lnode_borrow} function}
-
-    \indexfunc{lnode_borrow}
-    \synopsis
-    \begin{verbatim}
-    lnode_t *lnode_borrow(lnodepool_t *, void *);\end{verbatim}
-
-    \description
-
-    The \verb|lnode_borrow| function allocates a node from
-    the pool managed by the given \verb|lnodepool_t| object.
-    If the request succeeds, a pointer to the node is returned.  If the object
-    has run out of nodes, the return value is a null pointer.
-
-\subsubsection{The {\tt lnode_create} function}
-
-    \indexfunc{lnode_create}
-    \synopsis
-    \begin{verbatim}
-    lnode_t *lnode_create(void *);\end{verbatim}
-
-    \description
-
-    The \verb|lnode_create| function dynamically allocates a list node,
-    stores in it the data value specified in the argument and
-    returns a pointer to it. The allocation is performed by a call to the
-    standard \verb|malloc| function. If the allocation fails, a null
-    pointer is returned.
-
-\subsubsection{The {\tt lnode_destroy} function}
-
-    \indexfunc{lnode_destroy}
-    \synopsis
-    \begin{verbatim}
-    void lnode_destroy(lnode_t *);\end{verbatim}
-
-    \description
-
-    The \verb|lnode_destroy| function destroys a list node that has been
-    allocated with the \verb|lnode_create| function.  The value of any pointer
-    that referred to the node that was thus freed is indeterminate.
-
-    If the node is currently the occupant of a list, the behavior is undefined
-    if the list is subsequently used.
-
-\subsubsection{The {\tt lnode_get} function}
-
-    \indexfunc{lnode_get}
-    \synopsis
-    \begin{verbatim}
-    void *lnode_get(lnode_t *);\end{verbatim}
-
-    \description
-
-    The \verb|lnode_get| function retrieves the \verb|void *| data value
-    associated with a node.\footnote{This is the {\bf only} interface for
-    retrieving the data element.}
-    
-\subsubsection{The {\tt lnode_init} function}
-
-    \indexfunc{lnode_init}
-    \synopsis
-    \begin{verbatim}
-    lnode_t *lnode_init(lnode_t *, void *);\end{verbatim}
-
-    The \verb|lnode_init| function initializes the contents
-    of the specified list node object, assigning it the
-    data value specified as the second argument. 
-    The first argument is a pointer which refers to 
-    a data object that has a suitable size and alignment
-    for the representation of an \verb|lnode_t| type.
-    After initialization with \verb|lnode_init|, the object is subsequently
-    eligible as an operand to the functions of the List component.
-
-\subsubsection{The {\tt lnode_is_in_a_list} function}
-
-    \indexfunc{lnode_is_in_a_list}
-    \synopsis
-    \begin{verbatim}
-    int lnode_is_in_a_list(lnode_t *);\end{verbatim}
-
-    \description
-
-    The \verb|lnode_is_in_a_list| function determines whether the given node is
-    an occupant of some list. If the node is in a list, the function returns
-    the value $1$.  If the node is not in any list, the return value is zero.
-
-\subsubsection{The {\tt lnode_pool_create} function}
-
-    \indexfunc{lnode_pool_create}
-    \synopsis
-    \begin{verbatim}
-    lnodepool_t *lnode_pool_create(listcount_t);\end{verbatim}
-
-    \constraints
-
-    The value of the argument shall not be zero.
-
-    \description
-
-    The \verb|lnode_pool_create| function dynamically allocates,
-    by means of the standard library function \verb|malloc|
-    a node pool object containing the number of nodes specified
-    as the first argument. If not enough resources are available,
-    a null pointer is returned, otherwise a pointer to the
-    \verb|lnodepool_t| object is returned.
-
-\subsubsection{The {\tt lnode_pool_destroy} function}
-
-    \indexfunc{lnode_pool_destroy}
-    \synopsis
-    \begin{verbatim}
-    void lnode_pool_destroy(lnodepool_t *);\end{verbatim}
-
-    \description
-
-    The \verb|lnode_pool_destroy| function deallocates a
-    node pool that was allocated by \verb|lnode_pool_create|.
-    The value of any pointer which referred to the
-    node pool object becomes indeterminate.
-
-\subsubsection{The {\tt lnode_pool_init} function}
-
-    \indexfunc{lnode_pool_init}
-    \synopsis
-    \begin{verbatim}
-    lnodepool_t *lnode_pool_init(lnodepool_t *,
-            lnode_t *, listcount_t);\end{verbatim}
-
-    \constraints
-
-    The third argument, which specifies the node count, shall not be zero.
-
-    \description
-
-    The \verb|lnode_pool_init| function initializes a data object
-    that has a suitable size and alignment to represent an
-    \verb|lnodepool_t| type. A pointer to this object is passed
-    as the first argument. The node pool thus created draws nodes
-    from an array specified by the second argument, which shall be a pointer to
-    an object that can behave like an array of \verb|lnode_t| objects.
-    The third argument specifies the number of elements in this array.
-
-    After this function, the object pointed at by the \verb|lnodepool_t *|
-    argument is eligible for use with the node pool management functions
-    of the List component. Nodes may be drawn from the pool and returned to it.
-
-    As long as the pool continues to be used, the program should not directly
-    manipulate the node array. In particular, if the program modifies any
-    part of the array, then the behavior is undefined if the
-    \verb|lnodepool_t| object or any nodes drawn from it are subsequently
-    passed to a List function. The program shall not directly use the array
-    elements as independent \verb|lnode_t| objects while the array is
-    associated with the pool; in particular, it shall not pass these elements
-    to Kazlib functions that operate on \verb|lnode_t|.
-    
-    The behavior is undefined if the same array is associated with more than
-    one node pool object, or if two node pool objects are given overlapping
-    arrays.
-
-    The node array is managed in an manner that is specific to the
-    implementation; the intent is that each element of the array represents a
-    distinct node object, a pointer to which can be returned in response to an
-    allocation request.
-
-    The \verb|lnode_pool_init| function returns a copy of the first argument.
-
-\subsubsection{The {\tt lnode_pool_isempty} function}
-
-    \indexfunc{lnode_pool_isempty}
-    \synopsis
-    \begin{verbatim}
-    int lnode_pool_isempty(lnodepool_t *);\end{verbatim}
-
-    \description
-
-    The \verb|lnode_pool_isempty| function tests the 
-    specified \verb|lnodepool_t| object for ability to supply nodes.
-    If the object has been
-    subject to so many requests that it is no longer capable of
-    of supplying additional list nodes, the value $1$ is returned.
-    Otherwise the return value returned is zero.
-
-\subsubsection{The {\tt lnode_pool_isfrom} function}
-
-    \indexfunc{lnode_pool_isfrom}
-    \synopsis
-    \begin{verbatim}
-    int lnode_pool_isfrom(lnodepool_t *, lnode_t *);\end{verbatim}
-
-    \description
-
-    The function \verb|lnode_pool_isfrom|, intended to serve as a software
-    verification aid, determines whether a list node originates from
-    a particular node pool. The return value is $1$ if this relationship is
-    true, otherwise zero.
-
-\subsubsection{The {\tt lnode_put} function}
-
-    \indexfunc{lnode_put}
-    \synopsis
-    \begin{verbatim}
-    void lnode_put(lnode_t *, void *);\end{verbatim}
-
-    \description
-
-    The function \verb|lnode_put| replaces the data element
-    associated with the list node. 
-
-\subsubsection{The {\tt lnode_return} function}
-
-    \indexfunc{lnode_return}
-    \synopsis
-    \begin{verbatim}
-    void lnode_return(lnodepool_t *, lnode_t *);\end{verbatim}
-
-    \constraints
-
-    The node pointed at by the second argument was derived by an allocation
-    request from the pool pointed at by the first argument.\footnote{In
-    other words, the {\tt lnode_pool_isfrom} function, were it called with
-    the same two arguments, would return $1$ if this constraint is met.}
-
-    Furthermore, the node must not be the occupant of a list.
-
-    \description
-
-    The \verb|lnode_return| function returns a node back to the node pool from
-    which it came. The node must not be subsequently used as an argument to any
-    List functions, until it happens to be allocated again. The pointer to
-    the node object remains valid, and may be returned by a subsequent
-    allocation request from the same node pool.
-
-\subsection{Implementation}
-\index{List!reference implementation}
-
-This section describes the elements of the reference implementation of the
-List component. No requirement is imposed that an implementation should
-follow the reference implementation. The same is true of the
-implementation notes for the other components.
-
-\subsubsection{Types}
-\index{implementation!List types}
-\index{typedefs!implementation of List}
-
-The reference List implementation is a doubly-linked circular list
-\index{sentinel node!of linked list}
-with a {\it sentinel node}. The node structure type is defined like this:
-\begin{verbatim}
-    typedef struct lnode_t {
-        struct lnode_t *list_next;
-        struct lnode_t *list_prev;
-        void *list_data;
-    } lnode_t;
-\end{verbatim}
-and the list structure is defined like this:
-\begin{verbatim}
-    typedef struct list_t {
-        lnode_t list_nilnode;
-        listcount_t list_nodecount;
-        listcount_t list_maxcount;
-    } list_t;
-\end{verbatim}
-The \verb|list_nilnode| member of the list object is the sentinel. It is
-always present in the list, never deleted. When the list is empty, the sentinel
-node's \verb|list_next| and \verb|list_prev| pointers simply point back at the sentinel
-node.  The \verb|list_maxcount| member of the list tells how many nodes may be
-inserted and \verb|list_nodecount| keeps track of the actual count.
-
-The reason the sentinel node is called \verb|list_nilnode| is that it
-acts as the successor of a list's tail node, if there is one,
-and as the predecessor of the first node.  In a linked list implementation
-that does not use a sentinel node, the \verb|list_next| pointer of
-the the tail node and the \verb|list_prev| pointer of the first node would
-be null.
-
-Note that prefixed names are used for all of the structure members.  This is so
-that the header file conforms to the documented namespace. If, for example, the
-\verb|list_nilnode| member were simply called \verb|nilnode|, then
-if the program contained somewhere a macro called \verb|nilnode|, there would
-be a potential clash. If the program defined \verb|nilnode| prior to including
-the \verb|list.h| header, the declaration of \verb|struct list_t| would
-be confounded. If the program defined \verb|nilnode| after 
-including \verb|list.h|, the definition would interfere with \verb|list.h|
-macros whose replacement text refers to the \verb|nilnode| member.
-
-For programming convenience, the list implementation source file defines short
-macro names for the structure members:
-\begin{verbatim}
-    #define next list_next
-    #define prev list_prev
-    #define data list_data
-\end{verbatim}
-... and so forth. These names are private to the translation unit, which
-includes only standard ANSI C headers.  Some of the examples in this section
-make use of the short names; it is assumed that these macros are in effect.
-
-\subsubsection{Selected operations}
-\index{implementation!List operations}
-
-\paragraph{Retrieving the first node}
-\index{List!first node}
-
-Given a pointer \verb|P| to a \verb|list_t| type, the \verb|list_first|
-function examines the value of \verb|P->nilnode.next| which points
-at the head node if the list is not empty. If the list is empty,
-then this expression points back at the sentinel node. In
-other words, the comparison
-\begin{verbatim}
-    P->nilnode.next == &P->nilnode
-\end{verbatim}
-yields true when the list is empty. In this case, the interface requires that
-a null pointer be returned by \verb|list_first|.  The implementation actually
-uses the above test, through a test for \verb|P->nodecount| being equal to
-zero is also possible.
-
-In general, any operation which produces a pointer to the nilnode that must be
-returned back to the calling program  must test for that case and return a null
-pointer instead to satisfy the interface requirements.
-
-\paragraph{Node deletion}
-\index{List!deletion}
-
-Thanks to the use of the sentinel node, the list deletion operation doesn't
-have to test for special cases. A node in the middle of the list is
-deleted in exactly the same way as the first or the last node:
-\begin{verbatim}
-    lnode_t *list_delete(list_t *list, lnode_t *del)
-    {
-        lnode_t *next = del->next;
-        lnode_t *prev = del->prev;
-
-        assert (list_contains(list, del));
-
-        prev->next = next;
-        next->prev = prev;
-        list->nodecount--;
-
-        del->next = del->prev = NULL;
-
-        return del;
-    }
-\end{verbatim}
-Quite simply, the successor and predecessor of the deleted node are connected
-together so that the deleted node is spliced out from the list. If the node is
-the last remaining one, then the sentinel node serves as both the successor and
-the predecessor. The effect of the deletion then is to set the sentinel's next
-and previous links to point to itself, as they did initially when the list was
-previously empty.
-
-The next and prev pointers are set to null not only for enhanced error checking
-in language implementations that trap dereferences of null pointers,
-but also to indicate that the node is not on any list. The interface
-function \verb|lnode_is_in_a_list| makes use of this.
-
-It's worth discussing in some detail why the values of expressions
-\verb|del->next| and \verb|del->prev| are cached in local variables.  The
-actual statements that splice the node out of the list could instead have been
-written:
-\begin{verbatim}
-    del->prev->next = del->next;
-    del->next->prev = del->prev;
-\end{verbatim}
-However, this causes some compilers to generate less than optimal code because
-they fail to apply common subexpression elimination to the double
-occurrence of \verb|del->next|.  Caching this expression in a local variable
-helps to get better code by making the semantics more obvious.  In any case,
-modern compilers tend to do a good job of caching locals in high speed storage,
-particularly on architectures generously endowed with registers, so using a few
-extra locals is unlikely to lead to worse target code. The principle of using
-local variables to perform ``manual CSE'' is applied throughout the Kazlib
-reference implementation.
-
-\paragraph{Node insertion}
-Node insertion is also simple, thanks to the sentinel node which makes
-the doubly linked list circular. All insertions are done using
-the functions \verb|list_ins_before| and \verb|list_ins_after|.
-These are very similar, so it suffices to show \verb|list_ins_before|:
-\begin{verbatim}
-    void list_ins_before(list_t *list, lnode_t *new, lnode_t *this)
-    {
-        lnode_t *that = this->prev;
-
-        assert (new != NULL);
-        assert (!list_contains(list, new));
-        assert (!lnode_is_in_a_list(new));
-        assert (this == list_nil(list) || list_contains(list, this));
-        assert (list->nodecount + 1 > list->nodecount);
-
-        new->next = this;
-        new->prev = that;
-        that->next = new;
-        this->prev = new;
-        list->nodecount++;
-
-        assert (list->nodecount <= list->maxcount);
-    }
-\end{verbatim}
-The node \verb|this| is the one before which the new node is being
-inserted. Internally, the pointer \verb|that| points to the
-node after which the insertion takes place. In other words, the function
-inserts the node \verb|new| in between \verb|this| and \verb|that|.
-
-Note the copious assertions which verify all of the documented constraints:
-that the node is not already on the list, or any other list, that the reference
-node \verb|this| is in the list, and that the list capacity won't be exceeded,
-and that the node count doesn't overflow its type.
-
-\index{List!insertion}
-
-\section{Hash component}
-
-The Hash component provides a means to manage collections of elements, called
-hashes, that are not ordered. Each element in the collection has a unique key,
-which is used for searching and inserting. The intent is that the
-implementation is based on extendible hashing, and the interface allows for
-user-defined hashing functions. The number of elements that can be stored
-in a hash is limited; maximum number of entries in a hash is known as its
-{\it capacity}.
-
-\subsection{Interface}
-
-\subsubsection{The {\tt hash.h} header}
-
-Each C or C++ translation unit that is to use the functionality of the Hash
-component shall include the header \verb|hash.h|. This header shall
-contain declarations of types and external functions, and definitions of
-macros.  The following typedef names shall be
-defined:\index{Hash!typedef names}
-\index{typedefs!defined by Hash}
-\begin{verbatim}
-    hash_t                      hashcount_t
-    hnode_t                     hash_val_t
-    hash_comp_t                 hnode_alloc_t
-    hscan_t                     hnode_free_t
-    hash_fun_t
-\end{verbatim}
-In addition, the following structure tags may be defined:\index{Hash!tag names}
-\index{tags!defined by Hash}
-\begin{verbatim}
-    struct hash_t
-    struct hnode_t
-    struct hscan_t
-\end{verbatim}
-The following external function names shall be declared:
-\index{Hash!function names}\index{functions!defined by Hash}
-\begin{verbatim}
-    hash_create                 hash_count           
-    hash_set_allocator          hash_size            
-    hash_destroy                hash_isfull          
-    hash_free_nodes             hash_isempty         
-    hash_init                   hash_scan_begin      
-    hash_insert                 hash_scan_next       
-    hash_lookup                 hash_scan_delete     
-    hash_delete                 hash_scan_delfree
-    hash_alloc_insert           hash_verify          
-    hash_delete_free            hnode_create         
-    hnode_put                   hnode_init           
-    hnode_get                   hnode_destroy        
-    hnode_getkey                hash_free
-\end{verbatim}
-\index{Hash!external objects}
-In addition, the external object name
-\begin{verbatim}
-    hash_val_t_bit
-\end{verbatim}
-shall be declared.  The following preprocessor symbols (macros) shall be
-defined: \index{Hash!macro names}\index{macros!defined by Hash}
-\indexmacro{HASHCOUNT_T_MAX}
-\indexmacro{HASH_VAL_T_BIT}
-\indexmacro{HASH_VAL_T_MAX}
-\indexmacro{HASH_H}
-\begin{verbatim}
-    HASHCOUNT_T_MAX
-    HASH_VAL_T_BIT
-    HASH_H\end{verbatim}
-\index{symbols!reserved by Hash}\index{Hash!reserved symbols}
-Macro identifiers which begin with the upper-case prefix \verb|HASH| are
-reserved for future extensions to the \verb|hash.h| header, as are
-names in the ordinary and tag namespaces which begin with \verb|hash_|,
-\verb|hnode_| or \verb|hscan_|. External names which begin with \verb|hash_|,
-\verb|hnode_| or \verb|hscan_| are reserved by the Kazlib library regardless of
-what headers are included.
-
-\subsubsection{The {\tt hash_t} type}
-
-\indextype{hash_t}
-The type \verb|hash_t| is an opaque data type which maintains information about
-the current state of a single hash.  From the programmer's viewpoint, a hash
-consists of an instance of the \verb|hash_t| type, plus zero or more instances
-of the type \verb|hnode_t|. An instance of the \verb|hash_t| type can be
-dynamically created using the \verb|hash_create| function, and destroyed by the
-\verb|hash_destroy| function.  Alternately, the program can declare an object
-of type \verb|hash_t| and have it initialized via the \verb|hash_init|
-function.  When initializing a hash this way, the user must also provide
-a fixed-size array of \verb|hnode_t *| objects which serves as the hash table.
-\footnote{A hash initialized this way does not support extendible hashing,
-because there is no mechanism for growing the user-supplied array.}
-
-\subsubsection{The {\tt hnode_t} type}
-
-\indextype{hnode_t}
-The \verb|hnode_t| type is an opaque type that represents a single element
-that can be inserted into a hash. A hash node contains a a reference to
-satellite data provided by the user.  Nodes may be dynamically created by the
-\verb|hnode_create| function.  Alternately, the program may supply an
-\verb|hnode_t| object that can be initialized by the \verb|hnode_init|
-function. 
-
-\subsubsection{The {\tt hash_comp_t} type}
-
-\indextype{hash_comp_t}
-The \verb|hash_comp_t| type is a typedef name for the pointer-to-function type
-\begin{verbatim}
-    int (*)(const void *, const void *);
-\end{verbatim}
-In the context of the Hash component, this type denotes pointers to
-comparison functions.
-
-\subsubsection{The {\tt hscan_t} type}
-
-\indextype{hscan_t}
-The \verb|hscan_t| typedef stands for an opaque type which represents
-context information for traversing a hash. It is initialized by the
-\verb|hash_scan_begin| function, which specifies a hash to be
-traversed. Successive elements are retrieved using the \verb|hash_scan_next|
-function, which eventually indicates that no more elements
-remain. Inserting to, or deleting from a hash other than using
-the function \verb|hash_scan_delete| causes any \verb|hscan_t|
-objects that refer to it to become indeterminate.
-
-\subsubsection{The {\tt hashcount_t} type}
-
-\indextype{hashcount_t}
-\indexmacro{HASHCOUNT_T_MAX}
-This is an unsigned integral type which is capable of representing the number
-of nodes in a hash. 
-The \verb|HASHCOUNT_T_MAX| macro expands to a
-constant expression of type \verb|hashcount_t| which specifies the maximum
-value of that type.
-
-\subsubsection{The {\tt hash_val_t} type}
-
-\indextype{hash_val_t}
-\indexmacro{HASH_VAL_T_MAX}
-The \verb|hash_val_t| type is an unsigned integral type capable of
-holding at least 32 bits. The purpose of this type is to represent the
-output values of hashing functions.
-The \verb|HASH_VAL_T_MAX| macro expands to a
-constant expression of type \verb|hash_val_t| which specifies the maximum
-value of that type.
-
-\subsubsection{The {\tt hnode_alloc_t} type}
-
-\index{Hash!allocator function}
-The \verb|hnode_alloc_t| identifier is a typedef name for the pointer-to-function
-type
-\begin{verbatim}
-    hnode_t *(*)(void *);
-\end{verbatim}
-In other words, a pointer to a function that takes a \verb|void *|
-argument and returns a pointer to \verb|hnode_t|.
-A function of this type which meets certain behavior criteria may be
-registered with a \verb|hash_t| object as node allocator, together
-with a compatible deallocator function. The \verb|void *| argument
-passes user-specified context information through to the
-allocator routines (see section \ref{section:hash_set_allocator}).
-
-\subsubsection{The {\tt hnode_free_t} type}
-
-\index{Hash!deallocator function}
-The \verb|hnode_free_t| identifier is a typedef name for the
-pointer-to-function type
-\begin{verbatim}
-    void (*)(hnode_t *, void *);
-\end{verbatim}
-A function of this type which meets certain behavior criteria may be
-registered with a \verb|hash_t| object as node deallocator
-together with a compatible allocator function.
-
-\subsubsection{The {\tt hash_fun_t} type}
-
-\index{hashing function}
-The \verb|hash_fun_t| identifier is a typedef name for the
-pointer-to-function type
-\begin{verbatim}
-    hash_val_t (*hash_fun_t)(const void *);
-\end{verbatim}
-A function of this type which behaves a certain way is called
-a {\it hashing function}.  To be a viable hashing function, such
-a function must take a pointer to a key object, and produce
-an integer value that depends only on the contents of the key,
-and possibly on information that does not change over the lifetime of any hash
-for which that hashing function is used.  Additional requirements for hashing
-functions are introduced later.
-
-\subsubsection{The {\tt hash_val_t_bit} object}
-
-    \indexobject{hash_val_t_bit}
-    \synopsis
-    \begin{verbatim}
-    extern int hash_val_t_bit;\end{verbatim}
-
-    \description
-
-    The \verb|hash_val_t_bit| object of type int has a fixed value
-    which counts the number of bits in the \verb|hash_val_t| object.
-    The program shall not store a value into this object.
-    
-    The value of \verb|hash_val_t_bit| need not be correct until the
-    first successful call to \verb|hash_create| or to \verb|hash_init|
-    completes.
-
-    The implementation shall provide the macro \verb|HASH_VAL_T_BIT| which
-    expands to a non-lvalue expression that has the same value and type as the
-    object, but which may be a constant expression.\footnote{The intent of
-    providing these values is to ease the implementation of portable hashing
-    functions that take advantage of all of the available bits of a given
-    Kazlib implementation. Alternately, hashing functions may be constructed to
-    only use the lower 32 bits of the type.}
-
-\subsubsection{The {\tt hash_create} function}
-
-    \indexfunc{hash_create}
-    \index{Hash!creation of}
-    \index{create!hash object}
-    \synopsis
-    \begin{verbatim}
-    hash_t *hash_create(hashcount_t, hash_comp_t, hash_fun_t);\end{verbatim}
-
-    \description
-
-    If sufficient resources exist, the \verb|hash_create| function instantiates
-    and initializes an object of type \verb|hash_t| and returns a pointer to
-    it. Otherwise it returns a null pointer.
-
-    The first argument establishes the capacity of the hash, which is
-    initially empty.
-
-    The second argument is a pointer to a comparison function that will be
-    associated with the \verb|hash_t| object for its entire duration.
-
-    \index{hashing function}
-    The third argument is either null or a pointer to a hashing function
-    that is permanently associated with the object. If it is null, a {\it default
-    hashing function\/} is assigned by the implementation.
-
-    The hashing function shall be invoked with an argument that is one
-    of the keys that are being inserted into, or sought after, in the
-    hash. The hashing function must produce the same value each time it
-    is called for a given key. It is up to the hash user to define the
-    representation of keys, to manage their storage, and to provide a matching
-    hashing function.  The hash stores only generic \verb|void *| pointers to
-    keys. 
-
-    The default hashing function assumes that keys are null terminated
-    strings. That is to say, it behaves as though its \verb|void *|
-    argument points to the first elements of an array of \verb|unsigned|
-    \verb|char|, the last of which is a null character. The use of
-    the default hashing function with keys that do not have this representation
-    results in undefined behavior.
-    
-\subsubsection{The {\tt hash_set_allocator} function}
-
-    \indexfunc{hash_set_allocator}
-    \label{section:hash_set_allocator}
-
-    \synopsis
-    \begin{verbatim}
-    void hash_set_allocator(hash_t *, hnode_alloc_t,
-            hnode_free_t, void *);\end{verbatim}
-
-    \constraints
-
-    The second and third arguments---the function pointers---shall either
-    both be null, or both be non-null. The hash pointed at by the first
-    argument shall be empty.
-
-    \description
-
-    When a hash is initialized, it is outfitted with a pair of default
-    node allocation functions. These functions may be replaced with functions
-    supplied by the program by calling the \verb|hash_set_allocator| function
-    and specifying two suitable pointers. If these pointers are null, the
-    default functions are restored.
-
-    These functions are called to allocate and free \verb|hnode_t| 
-    objects by the functions \verb|hash_alloc_insert|
-    and \verb|hash_delete_free| (see sections
-    \ref{section:hash_delete_free} and \ref{section:hash_alloc_insert}).
-
-    If sufficient resources exist, the allocation function shall
-    return a pointer to a unique storage object that is large enough
-    and suitably aligned to represent an object of type \verb|dnode_t|.
-    Otherwise, the function shall return a null pointer.
-
-    The deallocation function shall be capable of disposing of the
-    objects created by the matching allocator function.
-
-
-\subsubsection{The {\tt hash_destroy} function}
-
-    \indexfunc{hash_destroy}
-    \synopsis
-    \begin{verbatim}
-    void hash_destroy(hash_t *);\end{verbatim}
-
-    \constraints
-
-    The hash pointed at by the first argument shall be empty.
-
-    \description
-
-    The \verb|hash_destroy| function deinitializes and deallocates a hash
-    that was created with \verb|hash_create|.
-    All pointers and \verb|hscan_t| objects that referred to the hash become
-    indeterminate.
-
-\subsubsection{The {\tt hash_free_nodes} function}
-
-    \indexfunc{hash_free_nodes}
-    \synopsis
-    \begin{verbatim}
-    void hash_free_nodes(hash_t *);\end{verbatim}
-
-    \description
-
-    The \verb|hash_free_nodes| function removes each node from
-    the hash and destroys it as if by calling \verb|hash_delete_free|
-    (Section \ref{section:hash_delete_free}). The order in which
-    the nodes are destroyed is unspecified.
-
-\subsubsection{The {\tt hash_free} function}
-
-    \indexfunc{hash_free}
-    \synopsis
-    \begin{verbatim}
-    void hash_free(hash_t *);\end{verbatim}
-
-    \description
-
-    Every node in the hash is removed from the hash and is then subject to the
-    deallocation function. The overall effect is as if the function
-    \verb|hash_delete_free| (Section \ref{section:hash_delete_free}) were
-    invoked on each node, and then \verb|hash_destroy| invoked on the
-    hash itself.
-
-    This function is obsolescent, and will be removed from some future revision
-    of this document.
-
-\subsubsection{The {\tt hash_init} function}
-
-    \indexfunc{hash_init}
-    \synopsis
-    \begin{verbatim}
-    hash_t *hash_init(hash_t *, hashcount_t, hash_comp_t,
-        hash_fun_t, hnode_t **, hashcount_t);
-    \end{verbatim}
-
-    \constraints
-
-    The last argument, which specifies the size of the program-supplied table,
-    shall be integral power of two that is greater than one---that is to say, an
-    integer of the form $2^k$ where $k$ is a positive integer.
- 
-    \description
- 
-    The \verb|hash_init| function configures the specified \verb|hash_t| object
-    to use a specified array of \verb|hnode_t *| pointer objects as a table.
-    The user is responsible for providing storage for the \verb|hash_t|
-    object and the array. As in the \verb|hash_create| interface,
-    the second parameter specifies the capacity, and the subsequent
-    arguments specify the comparison and hashing function, respectively.
-    The last two arguments specify the table of pointers. The array object
-    shall have at least as many elements as indicated by the last parameter,
-    otherwise the behavior is undefined. The call to \verb|hash_init| is said
-    to register the array with the hash.
-
-    The program shall not register the same array with more than one hash.
-    More specifically, once the program modifies a registered array, or
-    registers it with another hash, it must discontinue use of the first hash.
-    \footnote{Note that no explicit deinitialization function is provided to
-    dissociate the array. A program disposes of a hash created by
-    {\tt hash_init} by discontinuing its use.}
- 
-\subsubsection{The {\tt hash_insert} function}
-
-    \indexfunc{hash_insert}
-    \label{section:hash_insert}
-    \synopsis
-    \begin{verbatim}
-    void hash_insert(hash_t *, hnode_t *, const void *);\end{verbatim}
-
-    \constraints
-    The hash is not full.  The key specified by the \verb|void *| parameter
-    does not already exist in the specified hash. The node specified
-    by the second parameter is not already inserted into a hash.
-
-    \description
-    The \verb|hash_insert| function adds a new node to a hash. The user
-    must supply a node object that was initialized with \verb|hnode_init|
-    or dynamically created with \verb|hnode_create|. If the node is
-    already inserted into the same hash or any other hash, the behavior
-    is undefined.
-
-    A program may modify a key or node that has been inserted into a hash, or
-    cause the storage of the key or the node to become invalid.  However, any
-    subsequent use of the hash invokes undefined behavior, with the following
-    exception: the data pointer stored within a node may be modified using the
-    \verb|hnode_put| function.
-
-    The \verb|hash_insert| function invokes the hashing function callback with
-    the key pointer as the argument.
-
-    The \verb|hash_insert| function may need to acquire additional storage in
-    order to support hash table growth. If the storage allocation fails, the
-    function shall fully recover, and insert the node without growing the
-    table.
-
-    The Hash implementation shall not modify the storage referenced by a key,
-    and shall not access it other than indirectly through the supplied hashing
-    and comparison functions.
-
-\subsubsection{The {\tt hash_lookup} function}
-
-    \indexfunc{hash_lookup}
-    \synopsis
-    \begin{verbatim}
-    hnode_t *hash_lookup(hash_t *, const void *);\end{verbatim}
-
-    \description
-
-    The \verb|hash_lookup| function searches the given hash for a node
-    matching the given key. Unless the hash is empty, the key shall be
-    compared against one or more keys that are already in the hash,
-    using the comparison function. The key pointer may
-    be identical to one that has already been inserted into the
-    hash.\footnote {In that case, the comparison function must correctly
-    cope with aliased parameters}.
-
-    If the key is found in the hash, a pointer to the corresponding node
-    is returned.\footnote{The corresponding node is the one that was specified
-    in the call to {\tt hash_insert} together with the matching key.}
-
-    If the key is not found, a null pointer is returned.
-
-\subsubsection{The {\tt hash_delete} function}
-
-    \indexfunc{hash_delete}
-    \synopsis
-    \begin{verbatim}
-    hnode_t *hash_delete(hash_t *, hnode_t *);\end{verbatim}
-
-    \constraints
-    The specified node is an occupant of the given hash.
-
-    \description
-    The \verb|hash_delete| function removes from the given hash a
-    node that has previously been inserted into it. The key under
-    which the node was inserted is also removed from the hash.\footnote{Thus
-    the program may arbitrarily manipulate the removed key without destroying
-    the integrity of the hash.}
-
-    Any existing \verb|hscan_t| iterator which is associated with the
-    hash becomes indeterminate.\footnote{To delete the current node during hash
-    table traversal, the {\tt hash_scan_delete} function must be used
-    instead.}
-
-
-\subsubsection{The {\tt hash_alloc_insert} function}
-
-    \label{section:hash_alloc_insert}
-    \indexfunc{hash_alloc_insert}
-
-    \synopsis
-    \begin{verbatim}
-    int hash_alloc_insert(hash_t *, const void *, void *);\end{verbatim}
-
-    \constraints
-
-    The second argument specifies the insertion key. The hash shall not
-    already contain this key.
-
-    \description
-
-    The \verb|hash_alloc_insert| function dynamically allocates and
-    initializes a \verb|hnode_t| object and inserts it into the 
-    given hash. The second argument and third arguments are pointers
-    to user data and key objects, either of which may be null.
-
-    The allocation is performed by a call to the default allocation
-    function, or to the function that was configured using
-    \verb|hash_set_allocator| (Section \ref{section:hash_set_allocator}).
-
-    If the allocation succeeds, the insertion is performed and
-    the value 1 is returned.  If the allocation fails, no insertion is
-    performed and 0 is returned.
-
-\subsubsection{The {\tt hash_delete_free} function}
-
-    \label{section:hash_delete_free}
-    \indexfunc{hash_delete_free}
-
-    \synopsis
-    \begin{verbatim}
-    void hash_delete_free(hash_t *, hnode_t *)
-    \end{verbatim}
-
-    \constraints
-    The given node can be found within the given hash.
-   
-    \description
-    The \verb|hash_delete_free| function is the reverse of
-    \verb|hash_alloc_insert|. It removes the given node form the
-    hash as if by a call to \verb|hash_delete| and then deletes it using the
-    default or user-defined allocator (Section
-    \ref{section:hash_set_allocator}). If the given node had not been created
-    using \verb|hash_alloc_insert|, the behavior is undefined.
-
-\subsubsection{The {\tt hnode_put} function}
-
-    \indexfunc{hnode_put}
-    \synopsis
-    \begin{verbatim}
-    void hnode_put(hnode_t *, void *);\end{verbatim}
-
-    \description
-    The function \verb|hnode_put| replaces the data element
-    associated with the hash node.
-
-\subsubsection{The {\tt hnode_get} function}
-
-    \indexfunc{hnode_get}
-    \synopsis
-    \begin{verbatim}
-    void *hnode_get(hnode_t *);\end{verbatim}
-
-    \description
-    The \verb|hnode_get| function retrieves the \verb|void * | data value
-    associated with the given hash node.
-
-\subsubsection{The {\tt hnode_getkey} function}
-
-    \indexfunc{hnode_getkey}
-    \synopsis
-    \begin{verbatim}
-    const void *hnode_getkey(hnode_t *);\end{verbatim}
-
-    \description
-
-    The \verb|hnode_getkey| function retrieves the \verb|void *| key value 
-    associated with the given node. A node acquires an associated key
-    when it is inserted into a hash (see section \ref{section:hash_insert}).
-    Invoking \verb|hnode_getkey| on a node that has not been inserted
-    into a hash results in undefined behavior.
-
-\subsubsection{The {\tt hash_count} function}
-
-    \indexfunc{hash_count}
-    \synopsis
-    \begin{verbatim}
-    hashcount_t hash_count(hash_t *);\end{verbatim}
-
-    \description
-    The \verb|hash_count| function returns a value which represents the number
-    of nodes currently stored in the hash pointed at by the argument.
-
-\subsubsection{The {\tt hash_size} function}
-
-    \indexfunc{hash_size}
-    \synopsis
-    \begin{verbatim}
-    hashcount_t hash_size(hash_t *hash)\end{verbatim}
-
-    \description
-    The \verb|hash_size| function returns an implementation-defined value that
-    depends on the number of entries in the given hash.  The intent is that the
-    value represent the size of the internal hash table managed by the given
-    hash.
-
-\subsubsection{The {\tt hash_isfull} function}
-
-    \indexfunc{hash_isfull}
-    \synopsis
-    \begin{verbatim}
-    int hash_isfull(hash_t *);\end{verbatim}
-
-    \description
-    The \verb|hash_isfull| function returns 1 if the hash is full,
-    otherwise it returns 0.
-
-    If the argument is an expression with side effects, the behavior is
-    undefined.\index{macros!and side effects}
-
-
-\subsubsection{The {\tt hash_isempty} function}
-
-    \indexfunc{hash_isempty}
-    \synopsis
-    \begin{verbatim}
-    int hash_isempty(hash_t *);\end{verbatim}
-
-    \description
-    The \verb|hash_isempty| function returns 1 if the given hash is empty,
-    otherwise it returns 0.
-
-\subsubsection{The {\tt hash_scan_begin} function}
-
-    \indexfunc{hash_scan_begin}
-    \synopsis
-    \begin{verbatim}
-    void hash_scan_begin(hscan_t *, hash_t *);\end{verbatim}
-
-    \description
-    The \verb|hash_scan_begin| initializes the \verb|hscan_t| iterator object,
-    preparing it for a traversal of the given hash.
-
-    After this initialization, if the hash is modified in any way by
-    the performance of an insertion or deletion operation, the
-    value of the \verb|hscan_t| object becomes indeterminate,
-    with one exception:  the \verb|hash_scan_delete| function or the
-    \verb|hash_scan_delfree| function may be used to delete the current
-    node.
-
-\subsubsection{The {\tt hash_scan_next} function}
-
-    \indexfunc{hash_scan_next}
-    \synopsis
-    \begin{verbatim}
-    hnode_t *hash_scan_next(hscan_t *);\end{verbatim}
-
-    \description
-    If any unvisited nodes remain, the \verb|hash_scan_next| function advances
-    to the next one and returns a pointer to it. Otherwise, it returns a null
-    pointer. Repeated invocations of \verb|hash_scan_next| return a pointer to
-    every node that has been inserted into the table, in no particular order,
-    such that no node is reported twice.
-
-\subsubsection{The {\tt hash_scan_delete} function}
-
-    \indexfunc{hash_scan_delete}
-    \synopsis
-    \begin{verbatim}
-    hnode_t *hash_scan_delete(hash_t *, hnode_t *);
-    \end{verbatim}
-
-    \constraints
-    The specified node is an occupant of the given hash.
-
-    \description
-    This function is almost exactly like \verb|hash_delete| except that it may
-    be used to delete a node that has been most recently obtained from
-    \verb|hash_scan_next| without destroying the validity of the \verb|hscan_t|
-    iterator from which the node was obtained.
-
-\subsubsection{The {\tt hash_scan_delfree} function}
-
-    \label{section:hash_scan_delfree}
-    \indexfunc{hash_scan_delfree}
-
-    \synopsis
-    \begin{verbatim}
-    void hash_scan_delfree(hash_t *, hnode_t *)
-    \end{verbatim}
-
-    \constraints
-    The given node can be found within the given hash.
-   
-    \description
-    The \verb|hash_scan_delfree| function is similar to
-    \verb|hash_delete_free|. It removes the given node form the
-    hash and then deletes it using the default or user-defined allocator
-    (Section \ref{section:hash_set_allocator}). If the given node
-    had not been created using \verb|hash_alloc_insert|, the behavior
-    is undefined.
-
-    The deletion from the hash is performed as if by a call to
-    \verb|hash_scan_delete|, thus it is safe to delete a node that
-    was most recently obtained from a \verb|hash_scan_next| without
-    destroying the validity of the \verb|hscan_t| iterator.
-
-\subsubsection{The {\tt hash_verify} function}
-
-    \indexfunc{hash_verify}
-    \synopsis
-    \begin{verbatim}
-    int hash_verify(hash_t *hash);\end{verbatim}
-
-    \description
-    The intent of the \verb|hash_verify| function is to perform a verification
-    on the hash object, regardless of whether the Kazlib implementation is
-    operated in verification or production mode. If the hash object
-    and its constituent nodes have been correctly manipulated, and the
-    program has not caused any undefined behaviors, the value $1$ is returned.
-    Otherwise, the function may be able to, but is not guaranteed to, detect
-    corruption, and return the value zero.
-
-\subsubsection{The {\tt hnode_create} function}
-
-    \indexfunc{hnode_create}
-    \synopsis
-    \begin{verbatim}
-    hnode_t *hnode_create(void *);\end{verbatim}
-
-    \description
-    The \verb|hnode_create| function dynamically allocates a hash node,
-    stores in it the data value specified in the argument and
-    returns a pointer to it. The allocation is performed by a call to the
-    standard \verb|malloc| function. If the allocation fails, a null
-    pointer is returned.
-
-    The node's key pointer remains indeterminate until it is the subject of a
-    \verb|hash_insert| operation.
-
-\subsubsection{The {\tt hnode_init} function}
-
-    \indexfunc{hnode_init}
-    \synopsis
-    \begin{verbatim}
-    hnode_t *hnode_init(hnode_t *, void *);\end{verbatim}
-
-    \description
-    The \verb|hnode_init| function initializes the contents
-    of the specified hash node object, assigning it the
-    data value specified as the second argument. 
-    The first argument is a pointer which refers to 
-    a data object that has a suitable size and alignment
-    for the representation of an \verb|hnode_t| type.
-    After initialization with \verb|hnode_init|, the object is subsequently
-    eligible as an operand to the functions of the hash component,
-    other than \verb|hnode_getkey|.
-
-    The node's key pointer remains indeterminate until it is the subject of a
-    \verb|hash_insert| operation.
-
-\subsubsection{The {\tt hnode_destroy} function}
-
-    \indexfunc{hnode_destroy}
-    \synopsis
-    \begin{verbatim}
-    void hnode_destroy(hnode_t *);\end{verbatim}
-
-    \description
-    The \verb|hnode_destroy| function destroys a hash node that has been
-    allocated with the \verb|hnode_create| function.  The value of any pointer
-    that referred to the node that was thus freed is indeterminate.
-
-    If the node is currently the occupant of a hash, the behavior is undefined
-    if the hash is subsequently used.
-
-\subsection{Implementation}
-
-TODO
-
-\section{Dictionary component}
-
-\index{Dictionary}
-The Dictionary component provides a means to manage ordered sequences of
-elements, having the following properties:
-\begin{enumerate}
-\item If the dictionary is not empty, a first and last element can be identified.
-    In a dictionary having only one element, that one element is both the first and
-    last element.
-\item Each element that is not the last element has another element as its
-    {\it successor}.
-    \index{successor!of a dictionary element}
-    \index{Dictionary!successor of an element}
-\item Each element that is not the first element has a {\it predecessor}.
-    \index{predecessor!of a dictionary element}
-    \index{Dictionary!predecessor of an element}
-\item No element is the predecessor or successor of more than one element.
-\item If one element is the successor of another, the other is necessarily the
-    predecessor of the first.
-\item Each element is associated with a piece of information known as 
-    the key. The sequence is ordered according to the relation imposed
-    by the comparison function: the key of an element compares
-    greater than or equal to the key of its predecessor.
-\item If duplicate keys are present, then elements
-    having the same key form a subsequence with no other keys in it, which
-    follows from the previous property. No additional ordering is imposed
-    within such subsequences.
-\item Each element is associated with arbitrary satellite data.
-\end{enumerate}
-
-The Dictionary component supports efficient operations over such ordered
-sequences: such as insertion, deletion, ordered traversal, as well as exact and
-range searches.\footnote{The implicit association of keys and satellite data,
-together with the ability of efficiently search by key to retrieve data, gives
-rise to the term {\it dictionary}. A dictionary need not be ordered; a hash can
-therefore also be considered to be a kind of dictionary; the Kazlib
-nomenclature is somewhat unfortunate in that regard.}
-
-The number of elements that can be stored in a dictionary is limited; maximum
-number of entries in a dictionary is known as its {\it capacity}.
-
-\subsection{Interface}
-
-\subsubsection{The {\tt dict.h} header}
-
-Each C or C++ translation unit that is to use the functionality of the Dict
-component shall include the header \verb|dict.h|. This header shall
-contain declarations of types and external functions, and definitions of
-macros.  The following typedef names shall be
-defined:\index{Dict!typedef names}
-\index{typedefs!defined by Dict}
-\begin{verbatim}
-    dict_t                      dnode_process_t
-    dnode_t                     dnode_alloc_t
-    dictcount_t                 dnode_free_t
-    dict_comp_t                 dict_load_t
-\end{verbatim}
-In addition, the following structure tags may be defined:\index{Dict!tag names}
-\index{tags!defined by Dict}
-\begin{verbatim}
-    struct dict_t
-    struct dnode_t
-\end{verbatim}
-The following external function names shall be declared:
-\index{Dict!function names}\index{functions!defined by Dict}
-\begin{verbatim}
-    dict_create                 dict_count                     
-    dict_set_allocator          dict_isempty                   
-    dict_destroy                dict_isfull                    
-    dict_free_nodes             dict_contains                  
-    dict_init                   dict_allow_dupes               
-    dict_verify                 dnode_is_in_a_dict             
-    dict_lookup                 dnode_create                   
-    dict_lower_bound            dnode_init                     
-    dict_upper_bound            dnode_destroy                  
-    dict_insert                 dnode_get                      
-    dict_delete                 dnode_getkey                   
-    dict_alloc_insert           dnode_put                      
-    dict_delete_free            dict_process                   
-    dict_first                  dict_load_begin
-    dict_last                   dict_load_next
-    dict_next                   dict_load_end 
-    dict_prev                   dict_free
-\end{verbatim}
-The following preprocessor symbols shall be
-defined: \index{Dict!macro names}\index{macros!defined by Dict}
-\indexmacro{DICTCOUNT_T_MAX}
-\indexmacro{DICT_H}
-\begin{verbatim}
-    DICTCOUNT_T_MAX
-    DICT_H\end{verbatim}
-\index{symbols!reserved by Dict}\index{Dict!reserved symbols}
-Macro identifiers which begin with the upper-case prefix \verb|DICT| are
-reserved for future extensions to the \verb|dict.h| header, as are
-names in the ordinary and tag namespaces which begin with \verb|dict_|
-or \verb|dnode_|. External names which begin with \verb|dict_|
-or \verb|dnode_| are reserved by the Kazlib library regardless of
-what headers are included.
-
-\subsubsection{The {\tt dict_t} type}
-
-\indextype{dict_t}
-The type \verb|dict_t| is an opaque data type which represents a single
-dictionary. A dictionary consists of an instance of the \verb|dict_t| type,
-plus zero or more instances of the type \verb|dnode_t|. An object of type
-\verb|dict_t| can be initialized by the \verb|dict_init| function. Alternately,
-the \verb|dict_create| function will dynamically allocate and initialize a
-dictionary.  An empty dictionary created by \verb|dict_create| may be disposed
-of using \verb|dict_destroy|.
-
-\subsubsection{The {\tt dnode_t} type}
-
-\indextype{dnode_t}
-The \verb|dnode_t| type represents a single entry in a dictionary called a
-dictionary node.  The object stores a pointer to user data, and a key pointer
-that is assigned to the dictionary node at the time when it is inserted into
-the dictionary. A \verb|dnode_t| may be dynamically created using
-\verb|dnode_create| and destroyed using \verb|dnode_destroy|. Alternately,
-the program may supply storage for a \verb|dnode_t| object and initialize
-it using the \verb|dnode_init| function.
-
-\subsubsection{The {\tt dictcount_t} type}
-
-\indextype{dictcount_t}
-\indexmacro{DICTCOUNT_T_MAX}
-This is an unsigned integral type which is capable of representing the number
-of nodes in a dictionary.  The \verb|DICTCOUNT_T_MAX| macro expands to a
-constant expression of type \verb|dictcount_t| which specifies the maximum
-value of that type.
-
-\subsubsection{The {\tt dict_comp_t} type}
-
-\indextype{dict_comp_t}
-The \verb|dict_comp_t| type is a typedef name for the pointer-to-function type
-\begin{verbatim}
-    int (*)(const void *, const void *);
-\end{verbatim}
-In the context of the Dictionary component, this type denotes pointers to
-comparison functions. 
-
-\subsubsection{The {\tt dnode_process_t} type}
-
-\indextype{dnode_process_t}
-The type \verb|dnode_process_t| is a typedef name for the pointer-to-function type
-\begin{verbatim}
-    void (*)(dict_t *, dnode_t *, void *);
-\end{verbatim}
-In the context of the Dictionary component, this is the type of a
-dictionary node processing function (See section \ref{section:dict_process}).
-The first two parameters identify a dictionary and the node within that
-dictionary that is being processed. The third argument is a context pointer.
-
-\subsubsection{The {\tt dnode_alloc_t} type}
-
-\indextype{dnode_alloc_t}
-The type \verb|dnode_alloc_t| is a typedef name for the pointer-to-function type
-\begin{verbatim}
-    dnode_t *(*)(void *);
-\end{verbatim}
-A function compatible with this type which meets certain other criteria may be
-registered with a \verb|dict_t| object as a node allocator function
-(See section \ref{section:dict_set_allocator}).
-
-\subsubsection{The {\tt dnode_free_t} type}
-
-\indextype{dnode_free_t}
-The type \verb|dnode_free_t| is a typedef name for the pointer-to-function type
-\begin{verbatim}
-    void (*)(dnode_t *, void *);
-\end{verbatim}
-A function compatible with this type which meets certain other criteria may be
-registered with a \verb|dict_t| object as a node deallocator function.
-(See section \ref{section:dict_set_allocator}).
-
-\subsubsection{The {\tt dict_load_t} type}
-
-\indextype{dict_load_t}
-
-The \verb|dict_load_t| type is opaque, and represents a context structure
-used during the process of constructing a dictionary from an ordered list
-of nodes.  (See sections \ref{section:dict_load_begin} to
-\ref{section:dict_load_end}).
-
-\subsubsection{The {\tt dict_create} function}
-
-    \indexfunc{dict_create}
-    \index{Dictionary!creation of}
-    \index{create!dictionary object}
-
-    \synopsis
-    \begin{verbatim}
-    dict_t *dict_create(dictcount_t, dict_comp_t);\end{verbatim}
-
-    \description
-    The \verb|dict_create| function allocates a new
-    object of type \verb|dict_t| and initializes it to act as
-    a dictionary.
-    
-    If insufficient resources exist for the allocation,
-    a null pointer is returned, otherwise a pointer to the dictionary
-    is returned.
-    
-    The first argument specifies the capacity of the dictionary,
-    which is initially empty.
-
-    The second argument is a comparison function that is used for comparing
-    keys during insertion and searching operations, and is associated
-    with the dictionary for its entire duration.
-
-\subsubsection{The {\tt dict_set_allocator} function}
-
-    \label{section:dict_set_allocator}
-    \indexfunc{dict_set_allocator}
-
-    \synopsis
-    \begin{verbatim}
-    void dict_set_allocator(dict_t *, dnode_alloc_t,
-            dnode_free_t, void *);\end{verbatim}
-
-    \constraints
-
-    The second and third arguments---the function pointers---shall either
-    both be null, or both be non-null. The dictionary pointed at by the first
-    argument shall be empty.
-
-    \description
-
-    When a dictionary is initialized, it is outfitted with a pair of default
-    node allocation functions. These functions may be replaced with functions
-    supplied by the program by calling the \verb|dict_set_allocator| function
-    and specifying two suitable pointers. If these pointers are null, the
-    default functions are restored.
-
-    These functions are called to allocate and free \verb|dnode_t|
-    objects by the functions \verb|dict_alloc_insert|
-    and \verb|dict_delete_free| (see sections
-    \ref{section:dict_delete_free} and \ref{section:dict_alloc_insert}).
-
-    If sufficient resources exist, the allocation function shall
-    return a pointer to a unique storage object that is large enough
-    and suitably aligned to represent an object of type \verb|dnode_t|.
-    Otherwise, the function shall return a null pointer.
-
-    The deallocation function shall be capable of disposing of the
-    objects created by the matching allocator function.
-
-\subsubsection{The {\tt dict_destroy} function}
-
-    \indexfunc{dict_destroy}
-
-    \synopsis
-    \begin{verbatim}
-    void dict_destroy(dict_t *);\end{verbatim}
-
-    \constraints
-
-    The dictionary pointed at by the first argument shall be empty.
-
-    \description
-
-    The \verb|dict_destroy| function deinitializes and deallocates a dictionary
-    object that was created by \verb|dict_create|.  All pointers that
-    referred to the dictionary become indeterminate.
-
-\subsubsection{The {\tt dict_free_nodes} function}
-
-    \indexfunc{dict_free_nodes}
-
-    \synopsis
-    \begin{verbatim}
-    void dict_free_nodes(dict_t *);\end{verbatim}
-
-    \description
-
-    Every node in the dictionary is removed from the dictionary and is then
-    subject to the deallocation function, as if the function
-    \verb|dict_delete_free| (Section \ref{section:dict_delete_free}) were
-    invoked on each node, in some unspecified order.
-
-\subsubsection{The {\tt dict_free} function}
-
-    \indexfunc{dict_free}
-
-    \synopsis
-    \begin{verbatim}
-    void dict_free(dict_t *);\end{verbatim}
-
-    \description
-
-    This function is obsolescent, and will be removed from some future revision
-    of this document. It is equivalent to \verb|dict_free_nodes|.
-
-\subsubsection{The {\tt dict_init} function}
-
-    \indexfunc{dict_init}
-
-    \synopsis
-    \begin{verbatim}
-    dict_t *dict_init(dict_t *, dictcount_t, dict_comp_t);\end{verbatim}
-
-    \description
- 
-    The \verb|dict_init| function prepares specified \verb|dict_t| object
-    to behave as a dictionary that may subsequently be used with the other
-    dictionary functions.
-    
-    The first argument points to the \verb|dict_t| object to be initialized.
-    The second argument specifies the capacity of the dictionary. The third
-    argument is a pointer to the comparison function which shall be associated
-    with the dictionary for its entire duration.
-
-\subsubsection{The {\tt dict_verify} function}
-
-    \indexfunc{dict_verify}
-
-    \synopsis
-    \begin{verbatim}
-    int dict_verify(dict_t *);\end{verbatim}
-
-    \description
-
-    The intent of the \verb|dict_verify| function is to perform a verification
-    on the dictionary object, regardless of whether the Kazlib implementation
-    is operated in verification or production mode. If the dictionary object
-    and its constituent nodes have been correctly manipulated, and the program
-    has not caused any undefined behaviors, the value $1$ is returned.
-    Otherwise, the function may be able to, but is not guaranteed to, detect
-    corruption, and return the value zero.
-
-\subsubsection{The {\tt dict_lookup} function}
-
-    \indexfunc{dict_lookup}
-
-    \synopsis
-    \begin{verbatim}
-    dnode_t *dict_lookup(dict_t *, const void *);\end{verbatim}
-
-    \description
-    The \verb|dict_lookup| function searches the given dictionary for a node
-    matching the given key. Unless the dictionary is empty, the key shall be
-    compared against one or more keys that are already in the dictionary, using
-    the comparison function. The key pointer may be identical to one that has
-    already been inserted into the dictionary.
-
-    If the key is found in the dictionary, a pointer to the corresponding node
-    is returned.
-
-    If the key is not found, a null pointer is returned.
-
-    If the dictionary contains more than one key which matches the search
-    key, then the first key in the subsequence of duplicate keys is returned.
-
-\subsubsection{The {\tt dict_lower_bound} function}
-
-    \indexfunc{dict_lower_bound}
-
-    \synopsis
-    \begin{verbatim}
-    dnode_t *dict_lower_bound(dict_t *, const void *);\end{verbatim}
-
-    \description
-
-    The \verb|dict_lower_bound| function searches the dictionary in a manner
-    similar to \verb|dict_lookup|.
-    
-    If the given key exists in the dictionary, the behavior is exactly the same
-    as \verb|dict_lookup|.
-    
-    However, if the key is not found, then the node which has the smallest key
-    that is greater than the search key is returned. If no such key exists
-    (because the search key is higher than any other key in the dictionary
-    or the dictionary is empty) then a null pointer is returned.
-
-    \example
-    Suppose that pointer \verb|d| refers to a dictionary whose registered
-    comparison function performs lexicographic comparisons on ordinary
-    C strings, similar to \verb|strcmp|.  To iterate over all keys that
-    begin with the letter \verb|d|, the following idiom can be used:
-    \begin{verbatim}
-    dict_t *d;
-    dnode_t *n, *start, *end;
-    /*...*/
-    start = dict_lower_bound(d, "d");
-    end = dict_lower_bound(d, "e");
-    for (n = start; n != end; n = dict_next(d, n)) {
-        /* n points to each node in turn whose
-           key starts with 'd' */
-    }
-    \end{verbatim}
-    Note that if the dictionary is empty, or has keys which are all lower
-    than \verb|"d"|, then both \verb|start| and \verb|end| shall be null
-    pointers, and the loop body will never execute since the two are equal.
-    Also note that if there are keys that begin with \verb|d| and the
-    dictionary's last node has a key that starts with \verb|d|, then \verb|end|
-    is null, otherwise \verb|end| points to the first key that doesn't begin
-    with \verb|d|. In both cases, the loop will terminate after processing the
-    last \verb|d| key, because \verb|dict_next| shall produce a pointer that is
-    equal to \verb|end|.
-
-\subsubsection{The {\tt dict_upper_bound} function}
-
-    \indexfunc{dict_upper_bound}
-
-    \synopsis
-    \begin{verbatim}
-    dnode_t *dict_upper_bound(dict_t *, const void *);\end{verbatim}
-
-    \description
-
-    The \verb|dict_upper_bound| function searches the dictionary in a manner
-    similar to \verb|dict_lookup|.
-    
-    If the given key exists in the dictionary, the behavior is exactly the same
-    as \verb|dict_lookup| with one difference: 
-    If the dictionary contains more than one key which matches the search
-    key, then the last key in the sequence of duplicates is returned,
-    rather than the first.
-    
-    However, if the key is not found, then the node which has the greatest key
-    that is lower than the search key is returned. If no such key exists
-    (because the search key is lower than any other key in the dictionary
-    or the dictionary is empty) then a null pointer is returned.
-  
-    \example
-    The following idiom can be used to iterate over a sequence of duplicate
-    keys without the overhead of performing a full comparison before each
-    iteration to detect the first non-matching key. 
-    \begin{verbatim}
-    dict_t *d;
-    void *key;
-    dnode_t *n, *start, *end;
-
-    /* ... Initialize d, and key. ...*/
-    start = dict_lower_bound(d, key);
-    end = dict_upper_bound(d, key);
-
-    /* advance end to first non-matching key */
-    if (end != 0)
-        end = dict_next(d, end);
-    else
-        end = start;	/* start == dict_first(d) in this case */
-
-    for (n = start; n != end; n = dict_next(d, n)) {
-        /* n points to duplicate keys in turn */
-    }
-    \end{verbatim}
-    Immediately prior to the execution of the if statement, exactly one of the
-    following conditions is true:
-    \begin{itemize}
-    \item The key was found in the dictionary; \verb|start| points to the
-	first duplicate node and \verb|end| points to the last.
-    \item The dictionary has only higher keys than the search key; \verb|start|
-	points to the first node in the dictionary and \verb|end| is null.
-    \item The dictionary has only lower keys than the search key; \verb|end|
-	points to the last node in the dictionary, and \verb|start| is null.
-    \item The dictionary has both lower and higher keys; \verb|end| and \verb|start|
-	point to two consecutive nodes, respectively, such that the node
-	pointed at by \verb|end| has a lower key than the search key and
-	the node pointed at by \verb|start| has a higher key.
-    \item The dictionary is empty; \verb|start| and \verb|end| are null.
-    \end{itemize}
-    The if statement ensures that if the dictionary contains no matching
-    keys, than \verb|start| and \verb|end| are equal, and if the dictionary
-    contains one or more matching keys, than \verb|end| points to the first
-    non-matching node, or is null if there is no such node.  Thus the loop
-    performs correctly in all circumstances.
-
-\subsubsection{The {\tt dict_insert} function}
-
-    \label{section:dict_insert}
-    \indexfunc{dict_insert}
-
-    \synopsis
-    \begin{verbatim}
-    void dict_insert(dict_t *, dnode_t *, const void *);\end{verbatim}
-
-    \constraints
-    The dictionary is not full.  If the dictionary has not been configured
-    to allow duplicate keys, the key specified by the \verb|void *| parameter
-    does not already exist in the dictionary.
-
-    \description
-    The \verb|dict_insert| function adds a new node to a dictionary. The user
-    must supply a node object that was initialized with \verb|dnode_init| or
-    dynamically created with \verb|dnode_create|. If the node is already
-    inserted into the same dictionary or any other dictionary, the behavior is
-    undefined.
-
-    Duplicate keys may be inserted into a dictionary only if the dictionary
-    has been configured to permit duplicate keys (see section
-    \ref{section:dict_allow_dupes}). If this is the case, it is also
-    permissible to insert the same key more than once: the implementation shall
-    not distinguish between distinct keys that are declared equal by a
-    correctly designed comparison function, and two key pointers that refer to
-    the same key.
-
-    A program may modify a key or node that has been inserted into a
-    dictionary, or cause the storage of the key or the node to become invalid.
-    However, any subsequent use of the dictionary invokes undefined behavior, with
-    the following exception: the data pointer stored within a node may be
-    modified using the \verb|dnode_put| function.
-
-    The Dictionary implementation shall not modify the storage referenced by a
-    key, and shall not access it other than indirectly through the supplied
-    comparison function.
-
-\subsubsection{The {\tt dict_delete} function}
-
-    \indexfunc{dict_delete}
-
-    \synopsis
-    \begin{verbatim}
-    dnode_t *dict_delete(dict_t *, dnode_t *);\end{verbatim}
-
-    \constraints
-    The specified node is an occupant of the given dictionary.
-
-    \description
-    The \verb|dict_delete| function removes from the given dictionary a
-    node that has previously been inserted into it. The key under
-    which the node was inserted is also removed from the dictionary.
-
-\subsubsection{The {\tt dict_alloc_insert} function}
-
-    \label{section:dict_alloc_insert}
-    \indexfunc{dict_alloc_insert}
-
-    \synopsis
-    \begin{verbatim}
-    int dict_alloc_insert(dict_t *, const void *, void *);\end{verbatim}
-
-    \constraints
-
-    The second argument specifies the insertion key. The dictionary shall not
-    already contain this key unless it has been configured as allowing
-    duplicates.
-
-    \description
-
-    The \verb|dict_alloc_insert| function dynamically allocates and
-    initializes a \verb|dnode_t| object and inserts it into the 
-    given dictionary. The second argument and third arguments are pointers
-    to user data and key objects, either of which may be null.
-
-    The allocation is performed by a call to the default allocation
-    function, or to the function that was configured using
-    \verb|dict_set_allocator| (Section \ref{section:dict_set_allocator}).
-
-    If the allocation succeeds, the insertion is performed and
-    the value 1 is returned.  If the allocation fails, no insertion is
-    performed and 0 is returned.
-
-\subsubsection{The {\tt dict_delete_free} function}
-
-    \label{section:dict_delete_free}
-    \indexfunc{dict_delete_free}
-
-    \synopsis
-    \begin{verbatim}
-    void dict_delete_free(dict_t *, dnode_t *);\end{verbatim}
-
-    \constraints
-    The given node can be found within the given dictionary.
-   
-    \description
-    The \verb|dict_delete_free| function is the reverse of
-    \verb|dict_alloc_insert|. It removes the given node form the
-    dictionary and then deletes it using the default or user-defined allocator
-    (Section \ref{section:dict_set_allocator}). If the given node
-    had not been created using \verb|dict_alloc_insert|, the behavior
-    is undefined.
-
-\subsubsection{The {\tt dict_first} function}
-
-    \indexfunc{dict_first}
-
-    \synopsis
-    \begin{verbatim}
-    dnode_t *dict_first(dict_t *);\end{verbatim}
-
-    \description
-    If the dictionary pointed at by the argument is empty, a null pointer
-    is returned. Otherwise, a pointer to the first node in that dictionary is
-    returned. 
-
-\subsubsection{The {\tt dict_last} function}
-
-    \indexfunc{dict_last}
-
-    \synopsis
-    \begin{verbatim}
-    dnode_t *dict_last(dict_t *);\end{verbatim}
-
-    \description
-    If the dictionary pointed at by the argument is empty, a null pointer
-    is returned. Otherwise, a pointer to the last node in that dictionary is
-    returned. 
-
-
-\subsubsection{The {\tt dict_next} function}
-
-    \indexfunc{dict_next}
-
-    \synopsis
-    \begin{verbatim}
-    dnode_t *dict_next(dict_t *, dnode_t *);\end{verbatim}
-
-    \constraints
-    The node pointed at by the second argument is an occupant of the dictionary
-    pointed at by the first argument.
-
-    \description
-    If the node pointed at by the second argument has a successor, a pointer to
-    that successor is returned. Otherwise, a null pointer is returned.
-
-    \example
-    The \verb|dict_first| and \verb|dict_next| functions can be used together
-    to iterate over all of the elements of the dictionary, as in the following
-    idiom:
-    \begin{verbatim}
-    dict_t *d;
-    dnode_t *n;
-    /*...*/
-    for (n = dict_first(d); n != 0; n = dict_next(d, n)) {
-        /* n points to each node in turn */
-    }
-    \end{verbatim}
-
-\subsubsection{The {\tt dict_prev} function}
-
-    \indexfunc{dict_prev}
-
-    \synopsis
-    \begin{verbatim}
-    dnode_t *dict_prev(dict_t *, dnode_t *);\end{verbatim}
-
-    \constraints
-    The node pointed at by the second argument is an occupant of the dictionary
-    pointed at by the first argument.
-
-    \description
-    If the node pointed at by the second argument has a predecessor, a pointer
-    to that predecessor is returned. Otherwise, a null pointer is returned.
-
-\subsubsection{The {\tt dict_count} function}
-
-    \indexfunc{dict_count}
-
-    \synopsis
-    \begin{verbatim}
-    dictcount_t dict_count(dict_t *);\end{verbatim}
-
-    \description
-    The \verb|dict_count| function returns a value which represents the number
-    of nodes currently stored in the dictionary pointed at by the argument.
-
-\subsubsection{The {\tt dict_isempty} function}
-
-    \indexfunc{dict_isempty}
-
-    \synopsis
-    \begin{verbatim}
-    int dict_isempty(dict_t *);\end{verbatim}
-
-    \description
-    The \verb|dict_isempty| function returns 1 if the given dictionary is
-    empty, otherwise it returns 0.
-
-\subsubsection{The {\tt dict_isfull} function}
-
-    \indexfunc{dict_isfull}
-
-    \synopsis
-    \begin{verbatim}
-    int dict_isfull(dict_t *);\end{verbatim}
-
-    \description
-    The \verb|dict_isfull| function returns 1 if the dictionary is full,
-    otherwise it returns 0.
-
-    If the argument is an expression with side effects, the behavior is
-    undefined.\index{macros!and side effects}
-
-\subsubsection{The {\tt dict_contains} function}
-
-    \indexfunc{dict_contains}
-
-    \synopsis
-    \begin{verbatim}
-    int dict_contains(dict_t *, dnode_t *);\end{verbatim}
-
-    \description
-    The \verb|dict_contains| function searches the given dictionary to
-    determine whether the given node is an occupant. If the node is found, 1 is
-    returned, otherwise 0 is returned.\footnote{The intent is to support
-    verification.  The search may be inefficient compared to {\tt
-    dict_lookup}.}
-
-\subsubsection{The {\tt dict_allow_dupes} function}
-
-    \label{section:dict_allow_dupes}
-    \indexfunc{dict_allow_dupes}
-
-    \synopsis
-    \begin{verbatim}
-    void dict_allow_dupes(dict_t *);\end{verbatim}
-
-    \constraints
-    The dictionary specified by the first argument shall be empty.
-
-    \description
-    The \verb|dict_allow_dupes| function configures the given dictionary to
-    support duplicate keys. This can only be done when the dictionary is empty,
-    and the change cannot be reverted.
-
-\subsubsection{The {\tt dnode_is_in_a_dict} function}
-
-    \indexfunc{dnode_is_in_a_dict}
-
-    \synopsis
-    \begin{verbatim}
-    int dnode_is_in_a_dict(dnode_t *);\end{verbatim}
-
-    \description
-    The \verb|dnode_is_in_a_dict| function reports whether the given node
-    is currently the occupant of some dictionary. If so, 1 is returned.
-    Otherwise 0 is returned.
-
-\subsubsection{The {\tt dnode_create} function}
-
-    \indexfunc{dnode_create}
-
-    \synopsis
-    \begin{verbatim}
-    dnode_t *dnode_create(void *);\end{verbatim}
-
-    \description
-    The \verb|dnode_create| function dynamically allocates a dictionary node,
-    stores in it the data value specified in the argument and
-    returns a pointer to it. The allocation is performed by a call to the
-    standard \verb|malloc| function. If the allocation fails, a null
-    pointer is returned.
-
-    The node's key pointer remains indeterminate until it is the subject of a
-    \verb|dict_insert| operation.
-
-\subsubsection{The {\tt dnode_init} function}
-
-    \indexfunc{dnode_init}
-
-    \synopsis
-    \begin{verbatim}
-    dnode_t *dnode_init(dnode_t *, void *);\end{verbatim}
-
-    \description
-    The \verb|dnode_init| function initializes the contents
-    of the specified dictionary node object, assigning it the
-    data value specified as the second argument. 
-    The first argument is a pointer which refers to 
-    a data object that has a suitable size and alignment
-    for the representation of an \verb|dnode_t| type.
-    After initialization with \verb|dnode_init|, the object is subsequently
-    eligible as an operand to the functions of the dictionary component,
-    other than \verb|dnode_getkey|.
-
-    The node's key pointer remains indeterminate until it is the subject of a
-    \verb|dict_insert| operation.
-
-\subsubsection{The {\tt dnode_destroy} function}
-
-    \indexfunc{dnode_destroy}
-
-    \synopsis
-    \begin{verbatim}
-    void dnode_destroy(dnode_t *);\end{verbatim}
-
-    \description
-    The \verb|dnode_destroy| function destroys a dictionary node that has been
-    allocated with \verb|dnode_create|.  The value of any pointer
-    that referred to the node that was thus freed is indeterminate.
-
-    If the node is currently the occupant of a dictionary, the behavior is
-    undefined if the hash is subsequently used.
-
-\subsubsection{The {\tt dnode_get} function}
-
-    \indexfunc{dnode_get}
-
-    \synopsis
-    \begin{verbatim}
-    void *dnode_get(dnode_t *);\end{verbatim}
-
-    \description
-    The \verb|dnode_get| function retrieves the \verb|void * | data value
-    associated with the given dictionary node.
-
-\subsubsection{The {\tt dnode_getkey} function}
-
-    \indexfunc{dnode_getkey}
-
-    \synopsis
-    \begin{verbatim}
-    const void *dnode_getkey(dnode_t *);\end{verbatim}
-
-    \description
-
-    The \verb|dnode_getkey| function retrieves the \verb|void *| key value 
-    associated with the given node. A node acquires an associated key
-    when it is inserted into a dictionary (see section \ref{section:dict_insert}).
-    Invoking \verb|dnode_getkey| on a node that has not been inserted
-    into a dictionary results in undefined behavior.
-
-\subsubsection{The {\tt dnode_put} function}
-
-    \indexfunc{dnode_put}
-
-    \synopsis
-    \begin{verbatim}
-    void dnode_put(dnode_t *, void *);\end{verbatim}
-
-    \description
-    The function \verb|dnode_put| replaces the data element
-    associated with the dictionary node.
-
-\subsubsection{The {\tt dict_process} function}
-
-    \label{section:dict_process}
-    \indexfunc{dict_process}
-
-    \synopsis
-    \begin{verbatim}
-    void dict_process(dict_t *, void *, dnode_process_t);\end{verbatim}
-
-    \description
-    The \verb|dict_process| function iterates over the nodes of a dict,
-    and for each node invokes a callback function.\footnote{In most cases,
-    it is more convenient and preferable to 
-    iterate over the dict using explicit calls to {\tt dict_first}
-    and {\tt dict_next}.}
-    The second argument is a {\it context pointer\/} which can have any value.
-    The third argument of
-    \verb|dict_process| shall be a pointer to a function which is compatible
-    with the specified type. If the dict contains one or more nodes,
-    then the function is invoked once for each node, in order from first
-    to last. On each invocation, the first argument of the callback is a
-    pointer to the dict; the second argument is a pointer to a node, called
-    the {\it subject node}; and the third argument repeats the context pointer
-    value that was originally passed to \verb|dict_process|.
-
-    The callback function may delete the subject node by, for instance, calling
-    \verb|dict_delete|. It may insert new nodes into the dictionary;
-    however, if such an insertion causes the subject node to acquire
-    a new successor, it is implementation-defined whether upon returning
-    from the callback function, the traversal shall continue with the
-    new successor, or with the original successor.
-    
-    The callback function, and any function invoked from the callback
-    function, shall not destroy the dictionary or make any modifications
-    other than the insertion of new nodes, or the deletion of the 
-    subject node.
-
-    The callback function may recursively invoke \verb|dict_process| for the
-    same dictionary or for a different dictionary; the callback invocations arising out of
-    the nested call inherit all of the restrictions of the outer callback in
-    addition to being subject to the usual restrictions.\footnote{This means,
-    for instance, that if two callbacks are in progress for different
-    subject nodes from the same dictionary, the inner callback may not delete
-    its subject node, because it inherits the restriction that the only
-    permitted deletion is the outer callback's subject node.}
-
-    The callback function may freely operate on a different dictionary,
-    subject to any inherited restrictions.
-
-\subsubsection{The {\tt dict_load_begin} function}
-
-    \label{section:dict_load_begin}
-    \indexfunc{dict_load_begin}
-
-    \synopsis
-    \begin{verbatim}
-    void dict_load_begin(dict_load_t *, dict_t *);\end{verbatim}
-
-    \constraints
-    The dictionary specified by the second argument is empty.
-
-    \description
-    The \verb|dict_load_begin| function prepares a context object
-    for the task of constructing the contents of a dictionary  out of
-    a sequence of elements which is already sorted according to the
-    sorting function of the dictionary.\footnote{This process is more efficient 
-    than inserting all of the elements into a dictionary using {\tt dict_insert}. 
-    In the reference implementation, this process runs in linear time, or $O(n)$
-    whereas construction by repeated insertions runs in $O(n\log n)$ time.}
-    The actual construction is performed
-    by zero or more calls to \verb|dict_load_next| and is finalized by
-    \verb|dict_load_end|.
-
-    The \verb|dict_load_begin| function is said to bind the dictionary
-    and context object together; the only way to unbind the two 
-    is by calling \verb|dict_load_end| on the context object.
-
-    The program shall not manipulate a dictionary that is bound to
-    a context object, other than by calling \verb|dict_load_next|.
-
-    The program shall not attempt to bind a dictionary to more than one context
-    object simultaneously, or a context object to more than one dictionary
-    simultaneously.
-
-\subsubsection{The {\tt dict_load_next} function}
-
-    \label{section:dict_load_next}
-    \indexfunc{dict_load_next}
-
-    \synopsis
-    \begin{verbatim}
-    void dict_load_next(dict_load_t *, dnode_t *, const void *);\end{verbatim}
-
-    \constraints
-    The node pointed at by the second argument is not an occupant of
-    any dictionary. The key specified by the third argument is greater
-    than or equal to all keys specified in previous calls to 
-    \verb|dict_load_next| in the context of the same construction,
-    according to the comparison function of the dictionary that is
-    being constructed. That is to say, successive calls specify monotonically
-    increasing keys.
-    The dictionary is not full.
-
-    \description
-    The \verb|dict_load_next| function continues the construction of a
-    dictionary from an ordered list of elements by specifying the next
-    node in the sequence, along with its key. After this call, the node
-    is considered to be inserted into the dictionary as if by
-    \verb|dict_insert|.
-
-\subsubsection{The {\tt dict_load_end} function}
-
-    \label{section:dict_load_end}
-    \indexfunc{dict_load_end}
-
-    \synopsis
-    \begin{verbatim}
-    void dict_load_end(dict_load_t *);\end{verbatim}
-
-    \description
-    The \verb|dict_load_end| function finalizes the construction of
-    a dictionary from a ordered sequence.  It breaks the binding between
-    the \verb|dict_load_t| context object and the dictionary.
-
-\subsection{Implementation}
-
-TODO
-
-\section{Exception component}
-\label{section:exception_component}
-\index{Exception}
-
-The Exception component provides distributed error handling in the form of
-exceptions, behind an interface designed to be implementable using only the
-portable features of standard C. The features of this interface are:
-\begin{itemize}
-\item the ability to set up nested try-catch regions which declare specific
-exceptions that they can handle;
-\item grouped exceptions, allowing handlers to catch specific exceptions,
-or any exception within a group;
-\item the ability to designate a function that is called in the event
-that an exception is thrown that has no handler.
-\item a mechanism for releasing resources acquired by code that is terminated
-by an exception;
-\item the ability to pass dynamically allocated data from the throw site to the
-catch site.
-\end{itemize}
-
-An exception is simply a means of returning to a prior place in the program's
-execution. The ANSI C language provides crude, but portable, exception handling
-consisting of the \verb|jmp_buf| type, the \verb|setjmp| macro and the
-\verb|longjmp| function. The Kazlib Exception component can be implemented in
-terms of these primitives. The constraint to implementability in standard C
-leads to a number of concessions:
-\begin{itemize}
-\item A program can leave cleanup regions and try-catch regions by improper
-means, such as using \verb|goto|, \verb|return| or \verb|break|. This is
-difficult to diagnose, and is simply documented as undefined behavior.
-There is no support in the standard language for designating code that is
-executed whenever a statement block terminates by any means.
-\item For the same reason, the exception handling interface described here
-has an explicit mechanism for deallocation of resources associated with
-statement blocks that are terminated by exceptions. This interface is
-not as convenient as language support for automatic cleanup. Correct
-management of temporary dynamic resources using this interface requires
-programmer discipline.
-\item The requirement to be able to use \verb|setjmp| to save a context
-to be later returned to during exception processing brings in restrictions
-related to non-volatile objects. If non-volatile objects are modified 
-between the time an exception handling region is initiated and the time
-an exception is caught in the region, these objects have indeterminate
-values.\footnote{This liberty in ANSI C allows compiler
-or library writers to implement {\tt setjmp} as a simple mechanism that
-takes a snapshot of the machine context. Objects that are optimized into
-special storage---such as registers---and whose values change since the
-context saving operation will be clobbered when the context is restored
-by {\tt longjmp}.} 
-\end{itemize}
-
-\subsection{Interface}
-
-\subsubsection{The {\tt except.h} header}
-
-Each C or C++ translation unit that is to use the functionality of the Exception
-component shall include the header \verb|except.h|. This header shall
-contain declarations of types and external functions, and definitions of
-macros.  The following typedef names shall be
-defined:\index{Exception!typedef names}
-\begin{verbatim}
-    except_id_t
-    except_t
-\end{verbatim}
-The following external function names shall be declared:
-\index{Exception!function names}\index{functions!defined by Exception}
-\begin{verbatim}
-    except_init                 except_group   
-    except_deinit               except_message 
-    except_rethrow              except_data    
-    except_throw                except_take_data
-    except_throwd               except_set_allocator
-    except_throwf               except_alloc
-    except_unhandled_catcher    except_free
-    except_code            
-\end{verbatim}
-The following preprocessor symbols shall be
-defined: \index{Exception!macro names}\index{macros!defined by Exception}
-\indexmacro{XCEPT_H}
-\begin{verbatim}
-    XCEPT_H                     except_cleanup_pop
-    XCEPT_GROUP_ANY             except_checked_cleanup_pop
-    XCEPT_CODE_ANY              except_try_push
-    XCEPT_BAD_ALLOC             except_try_pop
-    except_cleanup_push
-\end{verbatim}
-Finally, these two enum constants are defined:
-\begin{verbatim}
-    except_no_call
-    except_call
-\end{verbatim}
-\index{symbols!reserved by Exception}\index{Exception!reserved symbols} Macro
-identifiers which begin with the upper-case prefix \verb|XCEPT|\footnote{The
-prefix {\tt XCEPT} is used rather than {\tt EXCEPT} because ISO 9899 reserves
-preprocessor symbols beginning with {\tt E} followed by a digit or
-capital letter for future extensions to the {\tt <errno.h>} header.}
-are reserved for future extensions to the \verb|except.h|
-header, as are names in the ordinary and tag namespaces which begin with
-\verb|except_|. External names which begin with \verb|except_| are reserved by
-the Kazlib library regardless of what headers are included.
-
-\subsubsection{The {\tt except_id_t} type}
-
-\label{section:except_id_t}
-\indextype{except_id_t}
-\indexmacro{XCEPT_GROUP_ANY}
-\indexmacro{XCEPT_CODE_ANY}
-The type \verb|except_id_t| is an aggregate consisting of two unsigned long
-values which represent an {\it exception group\/} and {\it exception code},
-respectively, in that order.\footnote{Thus, the program may initialize
-an {\tt except_id_t} object using two brace-enclosed initializers which
-specify the group and code.} An exception group is a value which identifies a
-group of related exceptions. An exception code is a value which identifies a
-specific exception uniquely within a group.  The codes are assigned by the
-program designer. The Exception component reserves only the group and code
-values of zero, which, when used to specify a catch, match any value.
-
-The preprocessor symbols \verb|XCEPT_GROUP_ANY| and
-\verb|XCEPT_CODE_ANY| each expand to a constant integral expression having the
-value zero.  These symbols are intended, in a catch specification, to clearly
-convey that any exception or any group is being caught.
-
-The preprocessor symbol \verb|XCEPT_BAD_ALLOC| expands to an integral constant
-expression having the value 1. This symbol is intended to represent the
-standard exception group for failed memory allocations.
-(See section \ref{section:except_throwf}).
-
-The exception groups from 1 to 15 are reserved for implementation use.
-
-\subsubsection{The {\tt except_t} type}
-
-\indextype{except_t}
-An object of type \verb|except_t| keeps track of all of the information that is
-passed when an exception is thrown, and is known as an {\it exception
-descriptor}.  The type is opaque, hence the program shall manipulate this type
-using only the interface functions provided.
-
-\subsubsection{The {\tt except_init} function}
-
-    \indexfunc{except_init}
-
-    \synopsis
-    \begin{verbatim}
-    int except_init(void);\end{verbatim}
-
-    \description
-    The \verb|except_init| function allocates resources needed by the
-    Exception component.  Before using any of the other exception interface
-    functions or macros, the program shall perform at least one successful call
-    to \verb|except_init|.
-
-    If the initialization succeeds, \verb|except_init| returns 1. Otherwise
-    it returns 0.
-
-    The \verb|except_init| function may be called more than once. After a
-    successful call, every subsequent call shall be successful up to an
-    implementation-defined maximum number of repetitions, which shall be at least
-    as large as the \verb|INT_MAX| from \verb|limits.h|. \footnote{
-    The intent is to support, but not enforce, a style of global initialization
-    whereby each module which requires the use of another module calls its
-    initialization function from its own initialization function. Only the
-    first such call performs the initialization of the module; subsequent calls
-    merely increment a counter. During deinitialization, the counter is
-    decremented and cleanup takes place when the counter reaches zero.}
-
-\subsubsection{The {\tt except_deinit} function}
-
-    \indexfunc{except_deinit}
-
-    \synopsis
-    \begin{verbatim}
-    void except_deinit(void);\end{verbatim}
-
-    \description
-    The \verb|except_deinit| function releases the resources 
-    that were allocated by \verb|except_init|.
-
-    For the resource deallocation to actually take place, the
-    \verb|except_deinit| must be called as many times as the
-    number of times \verb|except_init| was successfully called.
-
-    If \verb|except_deinit| is called more times than \verb|except_init| is
-    successfully called, the behavior is undefined.
-
-\subsubsection{The {\tt except_rethrow} function}
-
-    \indexfunc{except_rethrow}
-
-    \synopsis
-    \begin{verbatim}
-    void except_rethrow(except_t *);\end{verbatim}
-    
-    \description
-    The rethrow function is used to rethrow a caught exception.  The argument
-    shall not be null. An exception shall not be rethrown from outside of the
-    {\it try-catch region\/} in which it was caught. An exception shall not be
-    rethrown from a try-catch region other than the one in which it was caught.
-    It shall not be rethrown from a try-catch or cleanup region enclosed within
-    the one in which it was caught.
-
-    When an exception is rethrown, the search for a handler does not begin with
-    the region in which the exception was caught. Instead, this region is
-    terminated, and the search continues with the enclosing one, if one
-    exists.
-
-\subsubsection{The {\tt except_throw} function}
-
-    \indexfunc{except_throw}
-
-    \synopsis
-    \begin{verbatim}
-    void except_throw(long, long, const char *);\end{verbatim}
-
-    \constraints
-    The first two arguments specify the exception group and code,
-    respectively. Neither of these arguments shall be zero.
-
-    \description
-    The \verb|except_throw| function causes an exception to be thrown.
-
-    If the throw takes place in a try-catch region where an exception
-    was just caught, this original exception is considered handled. In
-    this case, the new exception is still eligible for handling by the
-    same try-catch region.
-
-    The third argument points to the first character of a string
-    which becomes the {\it exception message}. Because the throwing of
-    the exception may cause the current statement block to terminate,
-    this string data shall be non-local. It may be a string literal, since the
-    implementation shall not modify the message, or it may be an ordinary
-    object of static duration. If it is dynamic data, it becomes the handler's
-    responsibility to extract the message from the caught exception and
-    free the data.\footnote{The programmer should consider using 
-    {\tt except_throwd} to pass arbitrary dynamic data from the throw
-    site to the try-catch region.}
-
-    The \verb|except_throw| function does not return. The implementation
-    searches for a suitable try-catch region starting with the one
-    initiated by the most recent \verb|except_try_push|. If there
-    is no enclosing region, the search fails.  Otherwise if a match is found,
-    execution continues at the start of the target try-catch region, appearing
-    to be a second return from \verb|except_try_push| distinguished by a non-null
-    value of the \verb|except_t *| object.
-
-    If no match is found during exception processing, the exception is
-    handled internally by the implementation. The implementation then
-    calls the currently registered function for catching unhandled
-    exceptions (see section \ref{section:except_unhandled_catcher}).
-
-    The default catcher for unhandled exceptions shall terminate the program
-    with a diagnostic which identifies the code, group and exception message.
-
-    During the search for an exception handler, cleanup handlers may be
-    encountered. They are removed from the inside out and called with
-    their registered arguments. This process is called {\it unwinding}.
-    \index{unwinding}
-
-\subsubsection{The {\tt except_throwd} function}
-
-    \indexfunc{except_throwd}
-
-    \synopsis
-    \begin{verbatim}
-    void except_throwd(long, long, const char *, void *);\end{verbatim}
-
-    \constraints
-    The first two arguments specify the exception group and code,
-    respectively. Neither of these arguments shall be zero.
-
-    \description
-    The \verb|except_throwd| function is the same as \verb|except_throw| in
-    every respect except that it has an additional \verb|void *| parameter. A
-    null argument may be used for this parameter, or it may be any valid
-    pointer value.
-
-    When the exception is handled, and the handler does not remove this pointer
-    using \verb|except_take_data| then the implementation shall automatically
-    invoke the function \verb|except_free| on this pointer.
-
-\subsubsection{The {\tt except_throwf} function}
-
-    \indexfunc{except_throwf}
-    \label{section:except_throwf}
-
-    \synopsis
-    \begin{verbatim}
-    void except_throwf(long, long, const char *, ...);\end{verbatim}
-
-    \constraints
-    The first two arguments specify the exception group and code,
-    respectively. Neither of these arguments shall be zero.
-
-    \description
-
-    This function is almost exactly the same as \verb|except_throw|
-    except that the exception message is not directly specified.
-    Instead, the \verb|char *| argument specifies a format string which may be
-    followed by trailing arguments. The format string and trailing arguments
-    are interpreted as the format string and arguments of the standard C
-    function \verb|printf| and are subject to the same requirements.
-    
-    The format string is interpreted, and the results of formatting are placed into
-    buffer provided by the implementation.  The implementation shall provide
-    space for at least 1024 bytes of storage for the result of the formatting,
-    including the null terminator byte. If the formatting requires more space
-    than the implementation provides, the behavior is undefined.
-
-    The results of the formatted print shall become the exception message
-    of the thrown exception.
-
-    If the implementation is unable to allocate resources for the formatted
-    message, it shall throw a code 1 exception having an unspecified code in
-    group \verb|XCEPT_BAD_ALLOC| with an implementation-defined message.
-    (See section \ref{section:except_id_t}).
-
-\subsubsection{The {\tt except_unhandled_catcher} function}
-
-    \label{section:except_unhandled_catcher}
-    \indexfunc{except_unhandled_catcher}
-
-    \synopsis
-    \begin{verbatim}
-    void (*except_unhandled_catcher(void (*)(except_t *)))
-            (except_t *);\end{verbatim}
-
-    \description
-    The \verb|except_unhandled_catcher| function installs a new
-    function for catching unhandled exceptions. The argument is a 
-    pointer to a catching function that returns nothing, and accepts a pointer
-    of type \verb|except_t *|.  A pointer to the previously installed
-    catching function is returned. If the program did not previously
-    install a catching function, then a pointer to the default catching
-    function is returned. The program may retain this pointer and
-    use it to reinstall the default function.
-
-    A function for catching unhandled exceptions should not return. If it
-    returns, the implementation shall terminate the program with a diagnostic.
-
-\subsubsection{The {\tt except_code} function}
-
-    \indexfunc{except_code}
-
-    \synopsis
-    \begin{verbatim}
-    unsigned long except_code(except_t *);\end{verbatim}
-
-    \description
-    The \verb|except_code| is an accessor function which returns the
-    exception code of the given exception descriptor.
-
-\subsubsection{The {\tt except_group} function}
-
-    \indexfunc{except_group}
-
-    \synopsis
-    \begin{verbatim}
-    unsigned long except_group(except_t *);\end{verbatim}
-
-    \description
-    The \verb|except_group| is an accessor function which returns the
-    exception group of the given exception descriptor.
-
-\subsubsection{The {\tt except_message} function}
-
-    \indexfunc{except_message}
-
-    \synopsis
-    \begin{verbatim}
-    const char *except_message(except_t *);\end{verbatim}
-
-    \description
-    The \verb|except_group| is an accessor function which returns 
-    a pointer to the string of text that was specified when the
-    exception was thrown (the exception message).
-
-\subsubsection{The {\tt except_data} function}
-
-    \indexfunc{except_data}
-
-    \synopsis
-    \begin{verbatim}
-    void *except_data(except_t *);\end{verbatim}
-
-    \description
-    The \verb|except_group| returns the data pointer that
-    was specified in the \verb|except_throwd| call.
-    If the exception was not thrown by \verb|except_throwd|
-    the return value is unspecified.
-
-
-\subsubsection{The {\tt except_take_data} function}
-
-    \indexfunc{except_take_data}
-
-    \synopsis
-    \begin{verbatim}
-    void *except_take_data(except_t *);\end{verbatim}
-
-    \description
-    The \verb|except_take_data| returns the data pointer that
-    was specified in the \verb|except_throwd| call, and
-    updates the exception descriptor so that the pointer is
-    set to null.
-
-    If the exception was not thrown by \verb|except_throwd|
-    the result is unspecified.
-
-\subsubsection{The {\tt except_cleanup_push} macro}
-
-    \indexmacro{except_cleanup_push}
-
-    \synopsis
-    \begin{verbatim}
-    void except_cleanup_push(void (*)(void *), void *);\end{verbatim}
-
-    \description
-    The call to \verb|except_cleanup_push| shall be matched with a call to
-    \verb|except_cleanup_pop| which must occur in the same statement block at
-    the same level of nesting.\footnote{This requirement allows an implementation
-    to provide an {\tt except_cleanup_push} macro which opens up a statement
-    block and a {\tt except_cleanup_pop} which closes the statement block.
-    The space for the registered pointers can then be efficiently allocated
-    from automatic storage.}
-
-    The \verb|except_cleanup_push| macro registers a cleanup handler that will
-    be called if an exception subsequently occurs before the matching
-    \verb|except_cleanup_pop| is executed, and is not intercepted and handled by
-    a try-catch region that is nested between the two.
-
-    The first argument to \verb|except_cleanup_push| is a pointer
-    to the cleanup handler, a function that returns nothing and takes
-    a single argument of type \verb|void *|. The second argument
-    is a \verb|void *| value that is registered along with the handler.
-    This value is what is passed to the registered handler, should it
-    be called.
-
-    Cleanup handlers are called in the reverse order of their nesting: inner
-    handlers are called before outer handlers.
-
-    The program shall not leave the cleanup region between the call to the macro
-    \verb|except_cleanup_push| and the matching call to
-    \verb|except_cleanup_pop| by means other than throwing an exception, or
-    calling \verb|except_cleanup_pop|.
-
-    Within the call to the cleanup handler, it is possible that new exceptions
-    may happen.  Such exceptions must be handled before the cleanup handler
-    terminates. If the call to the cleanup handler is terminated by an
-    exception, the behavior is undefined.\footnote{The exception which triggered
-    the cleanup is not yet caught; thus the program would be effectively trying
-    to replace an exception with one that isn't in a well-defined state.}
-
-\subsubsection{The {\tt except_cleanup_pop} macro}
-
-    \indexmacro{except_cleanup_pop}
-    \label{section:except_cleanup_pop}
-
-    \synopsis
-    \begin{verbatim}
-    void except_cleanup_pop(int);\end{verbatim}
-
-    \description
-    A call to the \verb|except_cleanup_pop| macro shall match each
-    call to \verb|except_cleanup_push| which shall be in the
-    same statement block at the same nesting level.  It shall
-    match the most recent such a call that is not matched
-    by a previous \verb|except_cleanup_pop| at the same level.
-
-    This macro causes the registered cleanup handler to be removed.  If, and
-    only if the argument is other than zero, the cleanup handler is called.
-    In that case, the registered context pointer is passed to the cleanup
-    handler.
-
-    \indexenum{except_no_call}
-    \indexenum{except_call}
-    The enumeration constants \verb|except_no_call| and \verb|except_call|
-    may be used as arguments to this function instead of
-    the equivalent constants \verb|0| and \verb|1|.
-
-    The program shall not leave the region between the call to the macro
-    \verb|except_cleanup_push| and the matching call to
-    \verb|except_cleanup_pop| other than by throwing an exception, or
-    by executing the \verb|except_cleanup_pop|.
-
-\subsubsection{The {\tt except_checked_cleanup_pop} macro}
-
-    \indexmacro{except_checked_cleanup_pop}
-
-    \synopsis
-    \begin{verbatim}
-    void except_checked_cleanup_pop(void (*)(void *), int);\end{verbatim}
-
-    \constraints
-    The first pointer-to-function argument shall match the pointer value that
-    was registered by the matching \verb|except_cleanup_push| macro.
-
-    \description
-    The \verb|except_checked_cleanup_pop| macro may be used as an alternative to
-    \verb|except_cleanup_pop|. In verification mode, the constraint serves to
-    provide additional safety by making an explicit declaration regarding which
-    handler is being called (or ignored, as the case may be).
-
-    The program shall not leave the region between the call to the macro
-    \verb|except_cleanup_push| and the call to
-    \verb|except_checked_cleanup_pop| by means other than throwing an
-    exception, or executing the latter macro.
-
-\subsubsection{The {\tt except_try_push} macro}
-
-    \indexmacro{except_try_push}
-    \label{section:except_try_push}
-
-    \synopsis
-    \begin{verbatim}
-    void except_try_push(const except_id_t [],
-            size_t, except_t **);\end{verbatim}
-
-    \description
-    The \verb|except_try_push| marks the beginning of a try-catch region
-    of the program. It must be matched by a \verb|except_try_pop| written in
-    the same statement block at the same level of nesting, which
-    terminates the try-catch region. Regions may be nested.
-
-    The program shall not leave a try-catch region other than by throwing
-    an exception or by executing the \verb|except_try_pop|.\footnote{Thus,
-    leaving the try-catch region using {\tt goto}, {\tt return},
-    {\tt break} or {\tt continue} leads to undefined behavior.}
-
-    The first argument is a pointer to the first element of an array of
-    \verb|except_id_t| objects, the number of elements of which is specified by
-    the second argument. The array specifies which exceptions are caught.
-    The implementation shall treat this array as read-only.\footnote{Thus,
-    the program may allocate the array in static storage.}
-
-    The third argument of \verb|except_try_push| shall point to an object
-    of type \verb|except_t *|. After the call to \verb|except_try_push|,
-    the program shall inspect the value of this object. A null value indicates
-    that no exception has been thrown. A non-null value indicates that an
-    exception was thrown, and is now caught. In other words, when an exception
-    is caught by a try-catch region, then control passes from the throw site
-    back to the first statement after the \verb|except_try_push| statement of
-    the try-catch region. This case is distinguished from an ordinary return by
-    the non-null value of the pointer object that was specified by the third
-    argument of the earlier call to \verb|except_try_push|.
-
-    An exception is considered handled if it is caught in a try-catch region
-    which subsequently terminates by executing its \verb|except_try_pop| or by
-    throwing another exception.  When an exception is considered handled, any
-    dynamic data that was associated with that exception is
-    freed.\footnote{Dynamic data may be explicitly associated with an exception
-    using {\tt except_throwd}. Other types of throw may associate unspecified
-    dynamic data.} It's possible for more than one exception to be active
-    at once. During the processing of one exception, a try-catch region
-    which catches the exception may execute a nested try-catch region
-    in which independent exception processing takes place. Provided that 
-    no exception escapes from the inner try-catch region, the original
-    exception remains pending. But if an exception escapes from the inner
-    region, it causes the original exception to be handled.\footnote{Thus, a
-    given try-catch region cannot catch multiple exceptions concurrently.}
-   
-    The caught exception may be rethrown by calling \verb|except_rethrow|,
-    specifying the the value of the caught exception descriptor as the
-    argument.  Rethrowing a caught exception causes the innermost try-catch
-    region to terminate, but the exception is not considered handled. The
-    search for a handler continues with the second most enclosing region.
-
-    Throwing a new exception during the handling of a caught exception may
-    cause the {\it same\/} try-catch region to catch that exception; the
-    try-catch region is not terminated until it is determined that it doesn't
-    catch the new exception.
-
-    Each entry in the array of \verb|except_id_t| objects specifies what
-    exceptions are caught by the try-catch region. When an exception is
-    thrown, the implementation searches for the inner-most try-catch region
-    which has at least one match for the thrown exception in its catch
-    specification array. 
-
-    A match occurs when a specification exactly matches the group and code of
-    the thrown exception. If a catch specification is for group 0, then it
-    matches any group. If a catch specification is for code 0, then it matches
-    any exception code. A catch specification of group 0 and code 0 catches all
-    exceptions.
-
-    Non-volatile automatic variables that are local to the function containing
-    the try-catch region, and that are modified after \verb|except_try_push|
-    begins the try-catch region have indeterminate values when an exception is
-    caught.
-
-    Once a caught exception is handled or re-thrown, the value of the
-    \verb|except_t *| pointer which referenced it becomes indeterminate.
-    If a re-thrown exception is caught again, the implementation shall
-    produce a valid \verb|except_t *| pointer.
-
-    \example
-    The following example illustrates the use of \verb|except_try_push| and
-    related macros and functions.
-    \begin{verbatim}
-    #include <stdlib.h>
-    #include <assert.h>
-    #include "except.h"
-
-    #define MY_GROUP 42
-    #define MY_CODE   1
-
-    static void func_that_throws(void)
-    {
-        except_throw(MY_GROUP, MY_CODE, "this is an exception");        
-    }
-
-    static void func_that_cleans_up(void)
-    {
-        void *local_data = malloc(10);
-
-        except_cleanup_push(free, local_data);
-        func_that_throws();
-        except_checked_cleanup_pop(free, except_call);
-    }
-
-    void func_that_catches(void)
-    {
-        /* catch specification */
-        static const except_id_t catch_spec[] = {
-            { MY_GROUP, XCEPT_CODE_ANY }
-        };
-        /* exception handle */
-        except_t *exc;
-
-        except_try_push(catch_spec, 1, &exc);
-
-        /*
-         * Start of try-catch region: when exception is 
-         * thrown, control returns here.
-         */
-
-        if (exc == 0) {
-            /* try code that may throw an exception */
-
-            func_that_cleans_up();
-        } else {
-            /* handle exception that was thrown */
-
-            assert (except_group(exc) == MY_GROUP);
-            printf("exception caught: %s %ld %ld\n",
-                except_message(exc),
-                except_group(exc), except_code(exc));
-
-            goto terminate; /* ERROR! jumping out of try-catch */
-        }
-
-        /* end of try-catch region */
-
-        except_try_pop();
-    terminate:
-        ;
-    }
-    \end{verbatim}
-    In this example, the function \verb|func_that_catches| is intended to be
-    called first.  It sets up a try-catch region which traps exceptions having
-    the group identification \verb|MY_GROUP| (or 42). Any code within that
-    group is caught because the code catch was specified as
-    \verb|XCEPT_CODE_ANY|. When the \verb|except_try_push| macro is executed,
-    it sets the value of \verb|exc| to null. Then \verb|func_that_cleans_up| is
-    called, which throws an exception in the \verb|MY_GROUP| group. This
-    exception is caught, so control resumes at the top of the try-catch region,
-    with \verb|exc| set to a non-null value.  Thus the else clause of the if
-    statement is now executed.  The handling code simply prints the exception
-    message on standard output, as well as the numeric group and code.  The
-    subsequent goto statement demonstrates a serious programming error.
-
-    The \verb|func_that_cleans_up| function illustrates the use of cleanup
-    regions. Dynamic memory is allocated which must not be allowed to leak
-    when an exception is thrown, so a cleanup handler is set up to free the
-    memory in that event. The standard C function \verb|free| happens to have,
-    the right type signature and semantics that it can be used directly as a
-    cleanup handler.   Should no exception be thrown, the cleanup pop macro
-    will perform the call to the cleanup handler, because it is invoked with
-    argument \verb|except_call|.
-
-\subsubsection{The {\tt except_try_pop} macro}
-
-    \indexmacro{except_try_pop}
-
-    \synopsis
-    \begin{verbatim}
-    void except_try_pop(void);\end{verbatim}
-
-    \description
-
-    The \verb|except_try_pop| macro terminates a try-catch region. It must
-    match a previous \verb|except_try_push| macro in the same statement
-    block at the same level of nesting which is not already matched by an
-    earlier \verb|except_try_pop|.
-
-\subsubsection{The {\tt except_set_allocator} function}
-
-    \indexfunc{except_set_allocator}
-    \label{section:except_set_allocator}
-
-    \synopsis
-    \begin{verbatim}
-    void except_set_allocator(void *(*)(size_t), void (*)(void *));\end{verbatim}
-
-    \description
-    The \verb|except_set_allocator| function installs a pair of allocator
-    routines that will be used by the Exception component for future allocation
-    and deallocation requests. 
-
-    The first argument points to a function that resembles the standard C
-    \verb|malloc| in type and semantics. The second argument points to a
-    function that similarly resembles the standard C function \verb|free|.
-
-    The default allocators are \verb|malloc| and \verb|free|. 
-    The call
-    \begin{verbatim}
-    except_set_allocator(malloc, free);
-    \end{verbatim}
-    may be used to restore these default allocator functions.
-
-    The program shall not call \verb|except_set_allocator| if an exception
-    was thrown and has not yet been handled.\footnote{Doing so could, for example,
-    create a mismatch whereby a pointer to data allocated with the previously installed
-    allocator function would be passed to the new deallocator function.}
-
-    The allocator function shall create a unique object consisting of at least
-    as many bytes of storage as indicated by the value of the argument.
-    The pointer returned shall be suitably aligned to represent an object
-    of any type. If insufficient resources exist, the pointer returned shall be
-    null. Requesting an object of zero size may produce a unique pointer
-    that shall be acceptable to the deallocator function, or a null pointer.
-
-    The deallocator function shall be capable of destroying objects created
-    by the corresponding allocator function. Passing a null pointer to the
-    deallocator shall have no effect.
-
-\subsubsection{The {\tt except_alloc} function}
-
-    \indexfunc{except_alloc}
-
-    \synopsis
-    \begin{verbatim}
-    void *except_alloc(size_t);\end{verbatim}
-
-    \description
-    The \verb|except_alloc| function allocates memory using the default
-    memory allocator or one installed by the program.
-    (See section \ref{section:except_set_allocator}).
-
-    If the allocation succeeds, a non-null pointer to the allocated object is
-    returned.
-
-    If the allocator indicates failure by returning a null pointer,
-    then instead of returning, \verb|except_alloc| throws exception code 1 
-    in the group \verb|XCEPT_BAD_ALLOC| (See section \ref{section:except_id_t}).
-
-    If a zero size request is specified, then an exception is thrown or
-    a non-null pointer is returned, depending on the treatment of such
-    requests by the underlying allocator.
-
-\subsubsection{The {\tt except_free} function}
-
-    \indexfunc{except_free}
-
-    \synopsis
-    \begin{verbatim}
-    void *except_free(void *);\end{verbatim}
-
-    \description
-
-    The \verb|except_free| function releases memory that was allocated
-    using \verb|except_alloc|.  The deallocation is performed using the
-    default allocator or one installed by the program.
-
-    If an object is allocated by \verb|except_alloc|, then a 
-    different allocator is installed, and the object is freed using
-    \verb|except_free|, the behavior is undefined.
-
-\subsection{Implementation}
-\index{Exception component!reference implementation}
-
-Described here is a reference implementation of the exception handling
-interface that is covered in section \ref{section:exception_component}
-The reference implementation requires only a conforming ANSI C implementation.
-In particular, the actual mechanism for passing control from an exception throw
-to a catch handler is based on the standard C \verb|setjmp| macro and
-\verb|longjmp| function.
-
-\subsubsection{Overview}
-
-The core structure in the exception handling implementation is a stack that is
-composed of a mixture of two types of nodes: cleanup nodes and catch nodes.
-When an exception is thrown, the stack nodes are popped and processed starting
-with the topmost one. 
-
-The nodes are efficiently allocated in automatic storage by the macros
-\verb|except_cleanup_push| and \verb|except_try_push|. These macros
-open up a new statement block and declare the node information in automatic
-storage.  These objects are then pushed onto the stack. The corresponding macros
-\verb|except_cleanup_pop| and \verb|except_try_pop| pop the node off the stack
-and close the statement block.
-
-An static variable keeps track of the stack top. In the multi-threaded variant
-of the code which is based on the POSIX threading interface, there is a
-thread-specific stack top created using the thread-specific function
-pthread_key_create. Using global variables is a compromise that simplifies the
-interface; the throw functions simply ``know'' where the thread's exception
-stack is, so the context information doesn't have to be passed around.
-
-\subsubsection{Stack nodes}
-
-A node in the exception handling stack contains a pointer to the next
-node below, followed by a type field and a union which together keep
-track of the appropriate type-specific data:
-\begin{verbatim}
-    enum except_stacktype {
-        XCEPT_CLEANUP, XCEPT_CATCHER
-    };
-
-    struct except_stacknode {
-        struct except_stacknode *except_down;
-        enum except_stacktype except_type;
-        union {
-            struct except_catch *except_catcher;       
-            struct except_cleanup *except_cleanup;
-        } except_info;
-    };
-\end{verbatim}
-The union overlaps pointers to structures instead of structures in order to
-save space: there is a disparity in size between a cleanup node and a catch
-node, so making them both use the same amount of space would be wasteful.
-The space saving comes at a price, because the pointers themselves take up
-extra space and time is spent initializing them. Some casting trickery
-could be used to create a stack having two different kinds of structures
-without the use of unions.
-
-\paragraph{Cleanup nodes}
-
-Cleanup nodes act as placeholders for a pointer to a cleanup handler function
-and a context pointer to be passed to that function. The type-dependent
-component of the cleanup node is declared like this:
-\begin{verbatim}
-    struct except_cleanup {
-        void (*except_func)(void *);
-        void *except_context;
-    };
-\end{verbatim}
-The cleanup handler is invoked when the node is popped during exception
-processing. A cleanup handler may also be invoked when the cleanup node is
-removed by executing \verb|except_cleanup_pop| or
-\verb|except_checked_cleanup_pop|. Whether or not this happens depends on the
-integer parameter that is documented in section
-\ref{section:except_cleanup_pop}.
-
-\paragraph{Catch nodes}
-
-The catch node structure is more complicated than the cleanup node.
-Its definition depends on two additional types, \verb|except_id_t|
-and \verb|except_t|, both of which also make play a role in the exception
-component's interface.
-\begin{verbatim}
-    typedef struct {
-        unsigned long except_group;
-        unsigned long except_code;
-    } except_id_t;
-
-    typedef struct {
-        except_id_t except_id;
-        const char *except_message;
-        void *except_dyndata;
-    } except_t;
-
-    struct except_catch {
-        const except_id_t *except_id;
-        size_t except_size;
-        except_t except_obj;
-        jmp_buf except_jmp;
-    };
-\end{verbatim}
-The \verb|except_id| member of the \verb|except_catch| structure is a pointer to the
-array of \verb|except_id_t| objects which specify what exceptions the node
-catches. The \verb|except_size| member specifies the number of elements in the array.
-Both of these values are derived directly from the arguments of the
-\verb|except_try_push| macro (see section \ref{section:except_try_push}). The
-\verb|except_obj| member provides storage for the caught exception. This member is
-the means by which the thrown exception is communicated to the try-catch region
-where it is caught. It contains the group and code identifiers, the exception
-message and, optionally, the pointer to arbitrary exception data.  The
-\verb|except_jmp| member is the standard C \verb|jmp_buf|---a place for saving the
-execution context so that it's possible to pass control, via \verb|longjmp|
-from the place where an exception is thrown to the place where it is caught.
-
-If, during the search for an exception handler, a catch node is encountered
-which matches the thrown exception, the node remains the stack.  The exception
-information is stored into into the node's \verb|except_obj| member and a
-\verb|longjmp| is executed to return to the try-catch region in which the node
-was allocated and pushed. Because the node is still on the stack, it's possible
-to throw another exception which is caught again by the same node.  When an
-exception is thus caught, control resumes just after the \verb|except_throw|
-which placed the node onto the stack. The pointer passed into \verb|except_throw|
-is updated  to point to the \verb|except_obj| member of the catch structure.
-The program can then use the portable accessor functions such as
-\verb|except_code| to gain information about the caught exception and handle it
-accordingly.
-
-\index{external names|see {functions}}
-\index{reference implementation|see {implementation}}
-\index{names|see {symbols}}
-\index{identifiers|see {symbols}}
-\index{structure names|see{tags}}
-\index{preprocessor symbols|see{macros}}
-\index{defines|see{macros}}
-\index{reserved symbols|see{symbols}}
-\index{symbols!preprocessor|see{macros}}
-\index{symbols!type names|see{typedefs}}
-\index{symbols!function names|see{functions}}
-\printindex 
-
-\end{document}
diff --git a/libutil/kazlib/drivers/dict-main.c b/libutil/kazlib/drivers/dict-main.c
deleted file mode 100644
index 08f2e7a..0000000
--- a/libutil/kazlib/drivers/dict-main.c
+++ /dev/null
@@ -1,300 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdarg.h>
-
-typedef char input_t[256];
-
-static int tokenize(char *string, ...)
-{
-    char **tokptr; 
-    va_list arglist;
-    int tokcount = 0;
-
-    va_start(arglist, string);
-    tokptr = va_arg(arglist, char **);
-    while (tokptr) {
-	while (*string && isspace((unsigned char) *string))
-	    string++;
-	if (!*string)
-	    break;
-	*tokptr = string;
-	while (*string && !isspace((unsigned char) *string))
-	    string++;
-	tokptr = va_arg(arglist, char **);
-	tokcount++;
-	if (!*string)
-	    break;
-	*string++ = 0;
-    }
-    va_end(arglist);
-
-    return tokcount;
-}
-
-static int comparef(const void *key1, const void *key2)
-{
-    return strcmp(key1, key2);
-}
-
-static char *dupstring(char *str)
-{
-    int sz = strlen(str) + 1;
-    char *new = malloc(sz);
-    if (new)
-	memcpy(new, str, sz);
-    return new;
-}
-
-static dnode_t *new_node(void *c)
-{
-    static dnode_t few[5];
-    static int count;
-
-    if (count < 5)
-	return few + count++;
-
-    return NULL;
-}
-
-static void del_node(dnode_t *n, void *c)
-{
-}
-
-static int prompt = 0;
-
-static void construct(dict_t *d)
-{
-    input_t in;
-    int done = 0;
-    dict_load_t dl;
-    dnode_t *dn;
-    char *tok1, *tok2, *val;
-    const char *key;
-    char *help = 
-	"p                      turn prompt on\n"
-	"q                      finish construction\n"
-	"a <key> <val>          add new entry\n";
-
-    if (!dict_isempty(d))
-	puts("warning: dictionary not empty!");
-
-    dict_load_begin(&dl, d);
-
-    while (!done) {
-	if (prompt)
-	    putchar('>');
-	fflush(stdout);
-
-	if (!fgets(in, sizeof(input_t), stdin))
-	    break;
-
-	switch (in[0]) {
-	    case '?':
-		puts(help);
-		break;
-	    case 'p':
-		prompt = 1;
-		break;
-	    case 'q':
-		done = 1;
-		break;
-	    case 'a':
-		if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
-		    puts("what?");
-		    break;
-		}
-		key = dupstring(tok1);
-		val = dupstring(tok2);
-		dn = dnode_create(val);
-
-		if (!key || !val || !dn) {
-		    puts("out of memory");
-		    free((void *) key);
-		    free(val);
-		    if (dn)
-			dnode_destroy(dn);
-		}
-
-		dict_load_next(&dl, dn, key);
-		break;
-	    default:
-		putchar('?');
-		putchar('\n');
-		break;
-	}
-    }
-
-    dict_load_end(&dl);
-}
-
-int main(void)
-{
-    input_t in;
-    dict_t darray[10];
-    dict_t *d = &darray[0];
-    dnode_t *dn;
-    int i;
-    char *tok1, *tok2, *val;
-    const char *key;
-
-    char *help =
-	"a <key> <val>          add value to dictionary\n"
-	"d <key>                delete value from dictionary\n"
-	"l <key>                lookup value in dictionary\n"
-	"( <key>                lookup lower bound\n"
-	") <key>                lookup upper bound\n"
-	"# <num>                switch to alternate dictionary (0-9)\n"
-	"j <num> <num>          merge two dictionaries\n"
-	"f                      free the whole dictionary\n"
-	"k                      allow duplicate keys\n"
-	"c                      show number of entries\n"
-	"t                      dump whole dictionary in sort order\n"
-	"m                      make dictionary out of sorted items\n"
-	"p                      turn prompt on\n"
-	"s                      switch to non-functioning allocator\n"
-	"q                      quit";
-
-    for (i = 0; i < sizeof darray / sizeof *darray; i++)
-	dict_init(&darray[i], DICTCOUNT_T_MAX, comparef);
-
-    for (;;) {
-	if (prompt)
-	    putchar('>');
-	fflush(stdout);
-
-	if (!fgets(in, sizeof(input_t), stdin))
-	    break;
-
-	switch(in[0]) {
-	    case '?':
-		puts(help);
-		break;
-	    case 'a':
-		if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
-		    puts("what?");
-		    break;
-		}
-		key = dupstring(tok1);
-		val = dupstring(tok2);
-
-		if (!key || !val) {
-		    puts("out of memory");
-		    free((void *) key);
-		    free(val);
-		}
-
-		if (!dict_alloc_insert(d, key, val)) {
-		    puts("dict_alloc_insert failed");
-		    free((void *) key);
-		    free(val);
-		    break;
-		}
-		break;
-	    case 'd':
-		if (tokenize(in+1, &tok1, (char **) 0) != 1) {
-		    puts("what?");
-		    break;
-		}
-		dn = dict_lookup(d, tok1);
-		if (!dn) {
-		    puts("dict_lookup failed");
-		    break;
-		}
-		val = dnode_get(dn);
-		key = dnode_getkey(dn);
-		dict_delete_free(d, dn);
-
-		free(val);
-		free((void *) key);
-		break;
-	    case 'f':
-		dict_free(d);
-		break;
-	    case 'l':
-	    case '(':
-	    case ')':
-		if (tokenize(in+1, &tok1, (char **) 0) != 1) {
-		    puts("what?");
-		    break;
-		}
-		dn = 0;
-		switch (in[0]) {
-		case 'l':
-		    dn = dict_lookup(d, tok1);
-		    break;
-		case '(':
-		    dn = dict_lower_bound(d, tok1);
-		    break;
-		case ')':
-		    dn = dict_upper_bound(d, tok1);
-		    break;
-		}
-		if (!dn) {
-		    puts("lookup failed");
-		    break;
-		}
-		val = dnode_get(dn);
-		puts(val);
-		break;
-	    case 'm':
-		construct(d);
-		break;
-	    case 'k':
-		dict_allow_dupes(d);
-		break;
-	    case 'c':
-		printf("%lu\n", (unsigned long) dict_count(d));
-		break;
-	    case 't':
-		for (dn = dict_first(d); dn; dn = dict_next(d, dn)) {
-		    printf("%s\t%s\n", (char *) dnode_getkey(dn),
-			    (char *) dnode_get(dn));
-		}
-		break;
-	    case 'q':
-		exit(0);
-		break;
-	    case '\0':
-		break;
-	    case 'p':
-		prompt = 1;
-		break;
-	    case 's':
-		dict_set_allocator(d, new_node, del_node, NULL);
-		break;
-	    case '#':
-		if (tokenize(in+1, &tok1, (char **) 0) != 1) {
-		    puts("what?");
-		    break;
-		} else {
-		    int dictnum = atoi(tok1);
-		    if (dictnum < 0 || dictnum > 9) {
-			puts("invalid number");
-			break;
-		    }
-		    d = &darray[dictnum];
-		}
-		break;
-	    case 'j':
-		if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
-		    puts("what?");
-		    break;
-		} else {
-		    int dict1 = atoi(tok1), dict2 = atoi(tok2);
-		    if (dict1 < 0 || dict1 > 9 || dict2 < 0 || dict2 > 9) {
-			puts("invalid number");
-			break;
-		    }
-		    dict_merge(&darray[dict1], &darray[dict2]);
-		}
-		break;
-	    default:
-		putchar('?');
-		putchar('\n');
-		break;
-	}
-    }
-
-    return 0;
-}
diff --git a/libutil/kazlib/drivers/except-main.c b/libutil/kazlib/drivers/except-main.c
deleted file mode 100644
index fdb64db..0000000
--- a/libutil/kazlib/drivers/except-main.c
+++ /dev/null
@@ -1,57 +0,0 @@
-#include <stdio.h>
-#include <ctype.h>
-
-static void cleanup(void *arg)
-{
-    printf("cleanup(\"%s\") called\n", (char *) arg);
-}
-
-static void bottom_level(void)
-{
-    char buf[256];
-    printf("throw exception? "); fflush(stdout);
-    fgets(buf, sizeof buf, stdin);
-
-    if (buf[0] >= 0 && toupper(buf[0]) == 'Y')
-	except_throw(1, 1, "nasty exception");
-}
-
-static void top_level(void)
-{
-    except_cleanup_push(cleanup, "argument");
-    bottom_level();
-    except_cleanup_pop(0);
-}
-
-int main(int argc, char **argv)
-{
-    static const except_id_t catch[] = { { 1, 1 }, { 1, 2 } };
-    except_t *ex;
-
-    /*
-     * Nested exception ``try blocks''
-     */
-
-    /* outer */
-    except_try_push(catch, 2, &ex);
-    if (!ex) {
-	/* inner */
-	except_try_push(catch, 2, &ex);
-	if (!ex) {
-	    top_level();
-	} else {
-	    /* inner catch */
-	    printf("caught exception (inner): \"%s\", s=%ld, c=%ld\n",
-		    except_message(ex), except_group(ex), except_code(ex));
-	    except_rethrow(ex);
-	}
-	except_try_pop();
-    } else {
-	/* outer catch */
-	printf("caught exception (outer): \"%s\", s=%ld, c=%ld\n",
-		except_message(ex), except_group(ex), except_code(ex));
-    }
-    except_try_pop();
-    except_throw(99, 99, "exception in main");
-    return 0;
-}
diff --git a/libutil/kazlib/drivers/hash-main.c b/libutil/kazlib/drivers/hash-main.c
deleted file mode 100644
index 0a08542..0000000
--- a/libutil/kazlib/drivers/hash-main.c
+++ /dev/null
@@ -1,187 +0,0 @@
-#include <stdio.h>
-#include <ctype.h>
-#include <stdarg.h>
-
-typedef char input_t[256];
-
-static int tokenize(char *string, ...)
-{
-    char **tokptr; 
-    va_list arglist;
-    int tokcount = 0;
-
-    va_start(arglist, string);
-    tokptr = va_arg(arglist, char **);
-    while (tokptr) {
-	while (*string && isspace((unsigned char) *string))
-	    string++;
-	if (!*string)
-	    break;
-	*tokptr = string;
-	while (*string && !isspace((unsigned char) *string))
-	    string++;
-	tokptr = va_arg(arglist, char **);
-	tokcount++;
-	if (!*string)
-	    break;
-	*string++ = 0;
-    }
-    va_end(arglist);
-
-    return tokcount;
-}
-
-static char *dupstring(char *str)
-{
-    int sz = strlen(str) + 1;
-    char *new = malloc(sz);
-    if (new)
-	memcpy(new, str, sz);
-    return new;
-}
-
-static hnode_t *new_node(void *c)
-{
-    static hnode_t few[5];
-    static int count;
-
-    if (count < 5)
-	return few + count++;
-
-    return NULL;
-}
-
-static void del_node(hnode_t *n, void *c)
-{
-}
-
-int main(void)
-{
-    input_t in;
-    hash_t *h = hash_create(HASHCOUNT_T_MAX, 0, 0);
-    hnode_t *hn;
-    hscan_t hs;
-    char *tok1, *tok2, *val;
-    const char *key;
-    int prompt = 0;
-
-    char *help =
-	"a <key> <val>          add value to hash table\n"
-	"d <key>                delete value from hash table\n"
-	"l <key>                lookup value in hash table\n"
-	"n                      show size of hash table\n"
-	"c                      show number of entries\n"
-	"t                      dump whole hash table\n"
-	"+                      increase hash table (private func)\n"
-	"-                      decrease hash table (private func)\n"
-	"b                      print hash_t_bit value\n"
-	"p                      turn prompt on\n"
-	"s                      switch to non-functioning allocator\n"
-	"q                      quit";
-
-    if (!h)
-	puts("hash_create failed");
-
-    for (;;) {
-	if (prompt)
-	    putchar('>');
-	fflush(stdout);
-
-	if (!fgets(in, sizeof(input_t), stdin))
-	    break;
-
-	switch(in[0]) {
-	    case '?':
-		puts(help);
-		break;
-	    case 'b':
-		printf("%d\n", hash_val_t_bit);
-		break;
-	    case 'a':
-		if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
-		    puts("what?");
-		    break;
-		}
-		key = dupstring(tok1);
-		val = dupstring(tok2);
-
-		if (!key || !val) {
-		    puts("out of memory");
-		    free((void *) key);
-		    free(val);
-		}
-
-		if (!hash_alloc_insert(h, key, val)) {
-		    puts("hash_alloc_insert failed");
-		    free((void *) key);
-		    free(val);
-		    break;
-		}
-		break;
-	    case 'd':
-		if (tokenize(in+1, &tok1, (char **) 0) != 1) {
-		    puts("what?");
-		    break;
-		}
-		hn = hash_lookup(h, tok1);
-		if (!hn) {
-		    puts("hash_lookup failed");
-		    break;
-		}
-		val = hnode_get(hn);
-		key = hnode_getkey(hn);
-		hash_scan_delfree(h, hn);
-		free((void *) key);
-		free(val);
-		break;
-	    case 'l':
-		if (tokenize(in+1, &tok1, (char **) 0) != 1) {
-		    puts("what?");
-		    break;
-		}
-		hn = hash_lookup(h, tok1);
-		if (!hn) {
-		    puts("hash_lookup failed");
-		    break;
-		}
-		val = hnode_get(hn);
-		puts(val);
-		break;
-	    case 'n':
-		printf("%lu\n", (unsigned long) hash_size(h));
-		break;
-	    case 'c':
-		printf("%lu\n", (unsigned long) hash_count(h));
-		break;
-	    case 't':
-		hash_scan_begin(&hs, h);
-		while ((hn = hash_scan_next(&hs)))
-		    printf("%s\t%s\n", (char*) hnode_getkey(hn),
-			    (char*) hnode_get(hn));
-		break;
-	    case '+':
-		grow_table(h);		/* private function	*/
-		break;
-	    case '-':
-		shrink_table(h);	/* private function	*/
-		break;
-	    case 'q':
-		exit(0);
-		break;
-	    case '\0':
-		break;
-	    case 'p':
-		prompt = 1;
-		break;
-	    case 's':
-		hash_set_allocator(h, new_node, del_node, NULL);
-		break;
-	    default:
-		putchar('?');
-		putchar('\n');
-		break;
-	}
-    }
-
-    return 0;
-}
diff --git a/libutil/kazlib/drivers/list-main.c b/libutil/kazlib/drivers/list-main.c
deleted file mode 100644
index 6f462e4..0000000
--- a/libutil/kazlib/drivers/list-main.c
+++ /dev/null
@@ -1,152 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdarg.h>
-
-typedef char input_t[256];
-
-static int tokenize(char *string, ...)
-{
-    char **tokptr; 
-    va_list arglist;
-    int tokcount = 0;
-
-    va_start(arglist, string);
-    tokptr = va_arg(arglist, char **);
-    while (tokptr) {
-	while (*string && isspace((unsigned char) *string))
-	    string++;
-	if (!*string)
-	    break;
-	*tokptr = string;
-	while (*string && !isspace((unsigned char) *string))
-	    string++;
-	tokptr = va_arg(arglist, char **);
-	tokcount++;
-	if (!*string)
-	    break;
-	*string++ = 0;
-    }
-    va_end(arglist);
-
-    return tokcount;
-}
-
-static int comparef(const void *key1, const void *key2)
-{
-    return strcmp(key1, key2);
-}
-
-static char *dupstring(char *str)
-{
-    int sz = strlen(str) + 1;
-    char *new = malloc(sz);
-    if (new)
-	memcpy(new, str, sz);
-    return new;
-}
-
-int main(void)
-{
-    input_t in;
-    list_t *l = list_create(LISTCOUNT_T_MAX);
-    lnode_t *ln;
-    char *tok1, *val;
-    int prompt = 0;
-
-    char *help =
-	"a <val>                append value to list\n"
-	"d <val>                delete value from list\n"
-	"l <val>                lookup value in list\n"
-	"s                      sort list\n"
-	"c                      show number of entries\n"
-	"t                      dump whole list\n"
-	"p                      turn prompt on\n"
-	"q                      quit";
-
-    if (!l)
-	puts("list_create failed");
-
-    for (;;) {
-	if (prompt)
-	    putchar('>');
-	fflush(stdout);
-
-	if (!fgets(in, sizeof(input_t), stdin))
-	    break;
-
-	switch(in[0]) {
-	    case '?':
-		puts(help);
-		break;
-	    case 'a':
-		if (tokenize(in+1, &tok1, (char **) 0) != 1) {
-		    puts("what?");
-		    break;
-		}
-		val = dupstring(tok1);
-		ln = lnode_create(val);
-	
-		if (!val || !ln) {
-		    puts("allocation failure");
-		    if (ln)
-			lnode_destroy(ln);
-		    free(val);
-		    break;
-		}
-    
-		list_append(l, ln);
-		break;
-	    case 'd':
-		if (tokenize(in+1, &tok1, (char **) 0) != 1) {
-		    puts("what?");
-		    break;
-		}
-		ln = list_find(l, tok1, comparef);
-		if (!ln) {
-		    puts("list_find failed");
-		    break;
-		}
-		list_delete(l, ln);
-		val = lnode_get(ln);
-		lnode_destroy(ln);
-		free(val);
-		break;
-	    case 'l':
-		if (tokenize(in+1, &tok1, (char **) 0) != 1) {
-		    puts("what?");
-		    break;
-		}
-		ln = list_find(l, tok1, comparef);
-		if (!ln)
-		    puts("list_find failed");
-		else
-		    puts("found");
-		break;
-	    case 's':
-		list_sort(l, comparef);
-		break;
-	    case 'c':
-		printf("%lu\n", (unsigned long) list_count(l));
-		break;
-	    case 't':
-		for (ln = list_first(l); ln != 0; ln = list_next(l, ln))
-		    puts(lnode_get(ln));
-		break;
-	    case 'q':
-		exit(0);
-		break;
-	    case '\0':
-		break;
-	    case 'p':
-		prompt = 1;
-		break;
-	    default:
-		putchar('?');
-		putchar('\n');
-		break;
-	}
-    }
-
-    return 0;
-}
diff --git a/libutil/kazlib/drivers/sfx-main.c b/libutil/kazlib/drivers/sfx-main.c
deleted file mode 100644
index fda683b..0000000
--- a/libutil/kazlib/drivers/sfx-main.c
+++ /dev/null
@@ -1,41 +0,0 @@
-#include <stdlib.h>
-
-int main(int argc, char **argv)
-{
-    char expr_buf[256];
-    char *expr, *ptr;
-    sfx_rating_t eff;
-
-    for (;;) {
-	if (argc < 2) {
-	    expr = expr_buf;
-	    if (fgets(expr_buf, sizeof expr_buf, stdin) == 0)
-		break;
-	    if ((ptr = strchr(expr_buf, '\n')) != 0)
-		*ptr = 0;
-	} else {
-	    expr = (argv++)[1];
-	    if (!expr)
-		break;
-	}
-
-	if (!sfx_determine(expr, &eff)) {
-	    printf("expression '%s' has a syntax error\n", expr);
-	    return EXIT_FAILURE;
-	}
-
-	switch (eff) {
-	case sfx_none:
-	    printf("expression '%s' has no side effects\n", expr);
-	    break;
-	case sfx_potential:
-	    printf("expression '%s' may have side effects\n", expr);
-	    break;
-	case sfx_certain:
-	    printf("expression '%s' has side effects\n", expr);
-	    break;
-	}
-    }
-
-    return 0;
-}
diff --git a/libutil/kazlib/except.c b/libutil/kazlib/except.c
deleted file mode 100644
index c915dda..0000000
--- a/libutil/kazlib/except.c
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * Portable Exception Handling for ANSI C.
- * Copyright (C) 1999 Kaz Kylheku <kaz at ashi.footprints.net>
- *
- * Free Software License:
- *
- * All rights are reserved by the author, with the following exceptions:
- * Permission is granted to freely reproduce and distribute this software,
- * possibly in exchange for a fee, provided that this copyright notice appears
- * intact. Permission is also granted to adapt this software to produce
- * derivative works, as long as the modified versions carry this copyright
- * notice and additional notices stating that the work has been modified.
- * This source code may be translated into executable form and incorporated
- * into proprietary software; there is no requirement for such software to
- * contain a copyright notice related to this source.
- *
- */
-
-#include <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <limits.h>
-#include "except.h"
-
-#define XCEPT_BUFFER_SIZE	1024
-
-#define group except_group
-#define code except_code
-#define id except_id
-#define message except_message
-#define dyndata except_dyndata
-#define func except_func
-#define context except_context
-#define id except_id
-#define size except_size
-#define obj except_obj
-#define jmp except_jmp
-#define down except_down
-#define type except_type
-#define catcher except_catcher
-#define cleanup except_cleanup
-#define info except_info
-
-#ifdef KAZLIB_POSIX_THREADS
-
-#include <pthread.h>
-
-static pthread_mutex_t init_mtx = PTHREAD_MUTEX_INITIALIZER;
-static int init_counter;
-static pthread_key_t top_key;
-static pthread_key_t uh_key;
-static pthread_key_t alloc_key;
-static pthread_key_t dealloc_key;
-static void unhandled_catcher(except_t *);
-
-#define get_top() ((struct except_stacknode *) pthread_getspecific(top_key))
-#define set_top(T) (pthread_setspecific(top_key, (T)), (void)((T) == (struct except_stacknode *) 0))
-#define set_catcher(C) (pthread_setspecific(uh_key, (void *) (C)), (void)((C) == (void (*)(except_t *)) 0))
-#define set_alloc(A) (pthread_setspecific(alloc_key, (void *) (A)), (void)((A) == (void *(*)(size_t)) 0))
-#define set_dealloc(D) (pthread_setspecific(dealloc_key, (void *) (D)), (void)((D) == (void (*)(void *)) 0))
-
-static void (*get_catcher(void))(except_t *)
-{
-    void (*catcher)(except_t *) = (void (*)(except_t *)) pthread_getspecific(uh_key);
-    return (catcher == 0) ? unhandled_catcher : catcher;
-}
-
-static void *(*get_alloc(void))(size_t)
-{
-    void *(*alloc)(size_t) = (void *(*)(size_t)) pthread_getspecific(alloc_key);
-    return (alloc == 0) ? malloc : alloc;
-}
-
-static void (*get_dealloc(void))(void *)
-{
-    void (*dealloc)(void *) = (void (*)(void *)) pthread_getspecific(dealloc_key);
-    return (dealloc == 0) ? free : dealloc;
-}
-
-int except_init(void)
-{
-    int retval = 1;
-
-    pthread_mutex_lock(&init_mtx);
-
-    assert (init_counter < INT_MAX);
-
-    if (init_counter++ == 0) {
-	int top_ok = (pthread_key_create(&top_key, 0) == 0);
-	int uh_ok = (pthread_key_create(&uh_key, 0) == 0);
-	int alloc_ok = (pthread_key_create(&alloc_key, 0) == 0);
-	int dealloc_ok = (pthread_key_create(&dealloc_key, 0) == 0);
-       
-	if (!top_ok || !uh_ok || !alloc_ok || !dealloc_ok) {
-	    retval = 0;
-	    init_counter = 0;
-	    if (top_ok)
-		pthread_key_delete(top_key);
-	    if (uh_ok)
-		pthread_key_delete(uh_key);
-	    if (alloc_ok)
-		pthread_key_delete(alloc_key);
-	    if (dealloc_ok)
-		pthread_key_delete(dealloc_key);
-	}
-    }
-
-    pthread_mutex_unlock(&init_mtx);
-
-    return retval;
-}
-
-void except_deinit(void)
-{
-    pthread_mutex_lock(&init_mtx);
-
-    assert (init_counter > 0);
-
-    if (--init_counter == 0) {
-	pthread_key_delete(top_key);
-	pthread_key_delete(uh_key);
-	pthread_key_delete(alloc_key);
-	pthread_key_delete(dealloc_key);
-    }
-
-    pthread_mutex_unlock(&init_mtx);
-}
-
-#else	/* no thread support */
-
-static int init_counter;
-static void unhandled_catcher(except_t *);
-static void (*uh_catcher_ptr)(except_t *) = unhandled_catcher;
-static void *(*allocator)(size_t) = malloc;
-static void (*deallocator)(void *) = free;
-static struct except_stacknode *stack_top;
-
-#define get_top() (stack_top)
-#define set_top(T) (stack_top = (T))
-#define get_catcher() (uh_catcher_ptr)
-#define set_catcher(C) (uh_catcher_ptr = (C))
-#define get_alloc() (allocator)
-#define set_alloc(A) (allocator = (A))
-#define get_dealloc() (deallocator)
-#define set_dealloc(D) (deallocator = (D))
-
-int except_init(void)
-{
-    assert (init_counter < INT_MAX);
-    init_counter++;
-    return 1;
-}
-
-void except_deinit(void)
-{
-    assert (init_counter > 0);
-    init_counter--;
-}
-
-#endif
-
-
-static int match(const volatile except_id_t *thrown, const except_id_t *caught)
-{
-    int group_match = (caught->group == XCEPT_GROUP_ANY || caught->group == thrown->group);
-    int code_match = (caught->code == XCEPT_CODE_ANY || caught->code == thrown->code);
-
-    return group_match && code_match;
-}
-
-static void do_throw(except_t *except)
-{
-    struct except_stacknode *top;
-
-    assert (except->id.group != 0 && except->id.code != 0);
-
-    for (top = get_top(); top != 0; top = top->down) {
-	if (top->type == XCEPT_CLEANUP) {
-	    top->info.cleanup->func(top->info.cleanup->context);
-	} else {
-	    struct except_catch *catcher = top->info.catcher;
-	    const except_id_t *pi = catcher->id;
-	    size_t i;
-	
-	    assert (top->type == XCEPT_CATCHER);
-	    except_free(catcher->obj.dyndata);
-
-	    for (i = 0; i < catcher->size; pi++, i++) {
-		if (match(&except->id, pi)) {
-		    catcher->obj = *except;
-		    set_top(top);
-		    longjmp(catcher->jmp, 1);
-		}
-	    }
-	}
-    }
-
-    set_top(top);
-    get_catcher()(except);	/* unhandled exception */
-    abort();
-}
-
-static void unhandled_catcher(except_t *except)
-{
-    fprintf(stderr, "Unhandled exception (\"%s\", group=%ld, code=%ld)\n",
-	    except->message, except->id.group, except->id.code);
-    abort();
-}
-
-static void stack_push(struct except_stacknode *node)
-{
-    node->down = get_top();
-    set_top(node);
-}
-
-void except_setup_clean(struct except_stacknode *esn,
-	struct except_cleanup *ecl, void (*cleanf)(void *), void *context)
-{
-    esn->type = XCEPT_CLEANUP;
-    ecl->func = cleanf;
-    ecl->context = context;
-    esn->info.cleanup = ecl;
-    stack_push(esn);
-}
-
-void except_setup_try(struct except_stacknode *esn,
-	struct except_catch *ech, const except_id_t id[], size_t size)
-{
-   ech->id = id;
-   ech->size = size;
-   ech->obj.dyndata = 0;
-   esn->type = XCEPT_CATCHER;
-   esn->info.catcher = ech;
-   stack_push(esn);
-}
-
-struct except_stacknode *except_pop(void)
-{
-    struct except_stacknode *top = get_top();
-    set_top(top->down);
-    return top;
-}
-
-void except_rethrow(except_t *except)
-{
-    struct except_stacknode *top = get_top();
-    assert (top != 0);
-    assert (top->type == XCEPT_CATCHER);
-    assert (&top->info.catcher->obj == except);
-    set_top(top->down);
-    do_throw(except);
-}
-
-void except_throw(long group, long code, const char *msg)
-{
-    except_t except;
-
-    except.id.group = group;
-    except.id.code = code;
-    except.message = msg;
-    except.dyndata = 0;
-
-    do_throw(&except);
-}
-
-void except_throwd(long group, long code, const char *msg, void *data)
-{
-    except_t except;
-
-    except.id.group = group;
-    except.id.code = code;
-    except.message = msg;
-    except.dyndata = data;
-
-    do_throw(&except);
-}
-
-void except_throwf(long group, long code, const char *fmt, ...)
-{
-    char *buf = except_alloc(XCEPT_BUFFER_SIZE);
-    va_list vl;
-
-    va_start (vl, fmt);
-    vsprintf(buf, fmt, vl);
-    va_end (vl);
-    except_throwd(group, code, buf, buf);
-}
-
-void (*except_unhandled_catcher(void (*new_catcher)(except_t *)))(except_t *)
-{
-    void (*old_catcher)(except_t *) = get_catcher();
-    set_catcher(new_catcher);
-    return old_catcher;
-}
-
-#undef except_code
-#undef except_group
-#undef except_message
-#undef except_data
-
-unsigned long except_code(except_t *ex)
-{
-    return ex->id.code;
-}
-
-unsigned long except_group(except_t *ex)
-{
-    return ex->id.group;
-}
-
-const char *except_message(except_t *ex)
-{
-    return ex->message;
-}
-
-void *except_data(except_t *ex)
-{
-    return ex->dyndata;
-}
-
-void *except_take_data(except_t *ex)
-{
-    void *data = ex->dyndata;
-    ex->dyndata = 0;
-    return data;
-}
-
-void except_set_allocator(void *(*alloc)(size_t), void (*dealloc)(void *))
-{
-    set_alloc(alloc);
-    set_dealloc(dealloc);
-}
-
-void *except_alloc(size_t size)
-{
-    void *ptr = get_alloc()(size);
-
-    if (ptr == 0)
-	except_throw(XCEPT_BAD_ALLOC, 0, "out of memory");
-    return ptr;
-}
-
-void except_free(void *ptr)
-{
-    get_dealloc()(ptr);
-}
diff --git a/libutil/kazlib/except.h b/libutil/kazlib/except.h
deleted file mode 100644
index 3131fb9..0000000
--- a/libutil/kazlib/except.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Portable Exception Handling for ANSI C.
- * Copyright (C) 1999 Kaz Kylheku <kaz at ashi.footprints.net>
- *
- * Free Software License:
- *
- * All rights are reserved by the author, with the following exceptions:
- * Permission is granted to freely reproduce and distribute this software,
- * possibly in exchange for a fee, provided that this copyright notice appears
- * intact. Permission is also granted to adapt this software to produce
- * derivative works, as long as the modified versions carry this copyright
- * notice and additional notices stating that the work has been modified.
- * This source code may be translated into executable form and incorporated
- * into proprietary software; there is no requirement for such software to
- * contain a copyright notice related to this source.
- *
- */
-
-#ifndef XCEPT_H
-#define XCEPT_H
-
-#include <setjmp.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#define XCEPT_GROUP_ANY	0
-#define XCEPT_CODE_ANY	0
-#define XCEPT_BAD_ALLOC 1
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-enum { except_no_call, except_call };
-
-typedef struct {
-    unsigned long except_group;
-    unsigned long except_code;
-} except_id_t;
-
-typedef struct {
-    except_id_t volatile except_id;
-    const char *volatile except_message;
-    void *volatile except_dyndata;
-} except_t;
-
-struct except_cleanup {
-    void (*except_func)(void *);
-    void *except_context;
-};
-
-struct except_catch {
-    const except_id_t *except_id;
-    size_t except_size;
-    except_t except_obj;
-    jmp_buf except_jmp;
-};
-
-enum except_stacktype {
-    XCEPT_CLEANUP, XCEPT_CATCHER
-};
-
-struct except_stacknode {
-    struct except_stacknode *except_down;
-    enum except_stacktype except_type;
-    union {
-	struct except_catch *except_catcher;	
-	struct except_cleanup *except_cleanup;
-    } except_info;
-};
-
-/* private functions made external so they can be used in macros */
-void except_setup_clean(struct except_stacknode *,
-	struct except_cleanup *, void (*)(void *), void *);
-void except_setup_try(struct except_stacknode *,
-	struct except_catch *, const except_id_t [], size_t);
-struct except_stacknode *except_pop(void);
-
-/* public interface functions */
-int except_init(void);
-void except_deinit(void);
-void except_rethrow(except_t *);
-void except_throw(long, long, const char *);
-void except_throwd(long, long, const char *, void *);
-void except_throwf(long, long, const char *, ...);
-void (*except_unhandled_catcher(void (*)(except_t *)))(except_t *);
-unsigned long except_code(except_t *);
-unsigned long except_group(except_t *);
-const char *except_message(except_t *);
-void *except_data(except_t *);
-void *except_take_data(except_t *);
-void except_set_allocator(void *(*)(size_t), void (*)(void *));
-void *except_alloc(size_t);
-void except_free(void *);
-
-#define except_code(E) ((E)->except_id.except_code)
-#define except_group(E) ((E)->except_id.except_group)
-#define except_message(E) ((E)->except_message)
-#define except_data(E) ((E)->except_dyndata)
-
-#ifdef __cplusplus
-}
-#endif
-
-/*
- * void except_cleanup_push(void (*)(void *), void *); 
- * void except_cleanup_pop(int);
- * void except_checked_cleanup_pop(void (*)(void *), int);
- * void except_try_push(const except_id_t [], size_t, except_t **);
- * void except_try_pop(void);
- */
-
-#define except_cleanup_push(F, C) 				\
-    {								\
-	struct except_stacknode except_sn;			\
-	struct except_cleanup except_cl;			\
-	except_setup_clean(&except_sn, &except_cl, F, C)
-
-#define except_cleanup_pop(E)					\
-	except_pop();						\
-	if (E)							\
-	    except_cl.except_func(except_cl.except_context);	\
-    }
-
-#define except_checked_cleanup_pop(F, E)			\
-    	except_pop();						\
-	assert (except_cl.except_func == (F));			\
-	if (E)							\
-	    except_cl.except_func(except_cl.except_context);	\
-    }
-	
-#define except_try_push(ID, NUM, PPE)				\
-     {								\
-	struct except_stacknode except_sn;			\
-	struct except_catch except_ch;				\
-	except_setup_try(&except_sn, &except_ch, ID, NUM);	\
-	if (setjmp(except_ch.except_jmp))			\
-	    *(PPE) = &except_ch.except_obj;			\
-	else							\
-	    *(PPE) = 0
-
-#define except_try_pop()					\
-	except_free(except_ch.except_obj.except_dyndata);	\
-	except_pop();						\
-    } 
-
-#endif
diff --git a/libutil/kazlib/hash.c b/libutil/kazlib/hash.c
deleted file mode 100644
index 2140e66..0000000
--- a/libutil/kazlib/hash.c
+++ /dev/null
@@ -1,837 +0,0 @@
-/*
- * Hash Table Data Type
- * Copyright (C) 1997 Kaz Kylheku <kaz at ashi.footprints.net>
- *
- * Free Software License:
- *
- * All rights are reserved by the author, with the following exceptions:
- * Permission is granted to freely reproduce and distribute this software,
- * possibly in exchange for a fee, provided that this copyright notice appears
- * intact. Permission is also granted to adapt this software to produce
- * derivative works, as long as the modified versions carry this copyright
- * notice and additional notices stating that the work has been modified.
- * This source code may be translated into executable form and incorporated
- * into proprietary software; there is no requirement for such software to
- * contain a copyright notice related to this source.
- *
- */
-
-#include <stdlib.h>
-#include <stddef.h>
-#include <assert.h>
-#include <string.h>
-#define HASH_IMPLEMENTATION
-#include "hash.h"
-
-#define INIT_BITS	6
-#define INIT_SIZE	(1UL << (INIT_BITS))	/* must be power of two		*/
-#define INIT_MASK	((INIT_SIZE) - 1)
-
-#define next hash_next
-#define key hash_key
-#define data hash_data
-#define hkey hash_hkey
-
-#define table hash_table
-#define nchains hash_nchains
-#define nodecount hash_nodecount
-#define maxcount hash_maxcount
-#define highmark hash_highmark
-#define lowmark hash_lowmark
-#define compare hash_compare
-#define function hash_function
-#define allocnode hash_allocnode
-#define freenode hash_freenode
-#define context hash_context
-#define mask hash_mask
-#define dynamic hash_dynamic
-
-#define table hash_table
-#define chain hash_chain
-
-static hnode_t *hnode_alloc(void *context);
-static void hnode_free(hnode_t *node, void *context);
-static hash_val_t hash_fun_default(const void *key);
-static int hash_comp_default(const void *key1, const void *key2);
-
-int hash_val_t_bit;
-
-/*
- * Compute the number of bits in the hash_val_t type.  We know that hash_val_t
- * is an unsigned integral type. Thus the highest value it can hold is a
- * Mersenne number (power of two, less one). We initialize a hash_val_t
- * object with this value and then shift bits out one by one while counting.
- * Notes:
- * 1. HASH_VAL_T_MAX is a Mersenne number---one that is one less than a power
- *    of two. This means that its binary representation consists of all one
- *    bits, and hence ``val'' is initialized to all one bits.
- * 2. While bits remain in val, we increment the bit count and shift it to the
- *    right, replacing the topmost bit by zero.
- */
-
-static void compute_bits(void)
-{
-    hash_val_t val = HASH_VAL_T_MAX;	/* 1 */
-    int bits = 0;
-
-    while (val) {	/* 2 */
-	bits++;
-	val >>= 1;
-    }
-
-    hash_val_t_bit = bits;
-}
-
-/*
- * Verify whether the given argument is a power of two.
- */
-
-static int is_power_of_two(hash_val_t arg)
-{
-    if (arg == 0)
-	return 0;
-    while ((arg & 1) == 0)
-	arg >>= 1;
-    return (arg == 1);
-}
-
-/*
- * Compute a shift amount from a given table size 
- */
-
-static hash_val_t compute_mask(hashcount_t size)
-{
-    assert (is_power_of_two(size));
-    assert (size >= 2);
-
-    return size - 1;
-}
-
-/*
- * Initialize the table of pointers to null.
- */
-
-static void clear_table(hash_t *hash)
-{
-    hash_val_t i;
-
-    for (i = 0; i < hash->nchains; i++)
-	hash->table[i] = NULL;
-}
-
-/*
- * Double the size of a dynamic table. This works as follows. Each chain splits
- * into two adjacent chains.  The shift amount increases by one, exposing an
- * additional bit of each hashed key. For each node in the original chain, the
- * value of this newly exposed bit will decide which of the two new chains will
- * receive the node: if the bit is 1, the chain with the higher index will have
- * the node, otherwise the lower chain will receive the node. In this manner,
- * the hash table will continue to function exactly as before without having to
- * rehash any of the keys.
- * Notes:
- * 1.  Overflow check.
- * 2.  The new number of chains is twice the old number of chains.
- * 3.  The new mask is one bit wider than the previous, revealing a
- *     new bit in all hashed keys.
- * 4.  Allocate a new table of chain pointers that is twice as large as the
- *     previous one.
- * 5.  If the reallocation was successful, we perform the rest of the growth
- *     algorithm, otherwise we do nothing.
- * 6.  The exposed_bit variable holds a mask with which each hashed key can be
- *     AND-ed to test the value of its newly exposed bit.
- * 7.  Now loop over each chain in the table and sort its nodes into two
- *     chains based on the value of each node's newly exposed hash bit.
- * 8.  The low chain replaces the current chain.  The high chain goes
- *     into the corresponding sister chain in the upper half of the table.
- * 9.  We have finished dealing with the chains and nodes. We now update
- *     the various bookeeping fields of the hash structure.
- */
-
-static void grow_table(hash_t *hash)
-{
-    hnode_t **newtable;
-
-    assert (2 * hash->nchains > hash->nchains);	/* 1 */
-
-    newtable = realloc(hash->table,
-	    sizeof *newtable * hash->nchains * 2);	/* 4 */
-
-    if (newtable) {	/* 5 */
-	hash_val_t mask = (hash->mask << 1) | 1;	/* 3 */
-	hash_val_t exposed_bit = mask ^ hash->mask;	/* 6 */
-	hash_val_t chain;
-
-	assert (mask != hash->mask);
-
-	for (chain = 0; chain < hash->nchains; chain++) { /* 7 */
-	    hnode_t *low_chain = 0, *high_chain = 0, *hptr, *next;
-
-	    for (hptr = newtable[chain]; hptr != 0; hptr = next) {
-		next = hptr->next;
-
-		if (hptr->hkey & exposed_bit) {
-		    hptr->next = high_chain;
-		    high_chain = hptr;
-		} else {
-		    hptr->next = low_chain;
-		    low_chain = hptr;
-		}
-	    }
-
-	    newtable[chain] = low_chain; 	/* 8 */
-	    newtable[chain + hash->nchains] = high_chain;
-	}
-
-	hash->table = newtable;			/* 9 */
-	hash->mask = mask;
-	hash->nchains *= 2;
-	hash->lowmark *= 2;
-	hash->highmark *= 2;
-    }
-    assert (hash_verify(hash));
-}
-
-/*
- * Cut a table size in half. This is done by folding together adjacent chains
- * and populating the lower half of the table with these chains. The chains are
- * simply spliced together. Once this is done, the whole table is reallocated
- * to a smaller object.
- * Notes:
- * 1.  It is illegal to have a hash table with one slot. This would mean that
- *     hash->shift is equal to hash_val_t_bit, an illegal shift value.
- *     Also, other things could go wrong, such as hash->lowmark becoming zero.
- * 2.  Looping over each pair of sister chains, the low_chain is set to
- *     point to the head node of the chain in the lower half of the table, 
- *     and high_chain points to the head node of the sister in the upper half.
- * 3.  The intent here is to compute a pointer to the last node of the
- *     lower chain into the low_tail variable. If this chain is empty,
- *     low_tail ends up with a null value.
- * 4.  If the lower chain is not empty, we simply tack the upper chain onto it.
- *     If the upper chain is a null pointer, nothing happens.
- * 5.  Otherwise if the lower chain is empty but the upper one is not,
- *     If the low chain is empty, but the high chain is not, then the
- *     high chain is simply transferred to the lower half of the table.
- * 6.  Otherwise if both chains are empty, there is nothing to do.
- * 7.  All the chain pointers are in the lower half of the table now, so
- *     we reallocate it to a smaller object. This, of course, invalidates
- *     all pointer-to-pointers which reference into the table from the
- *     first node of each chain.
- * 8.  Though it's unlikely, the reallocation may fail. In this case we
- *     pretend that the table _was_ reallocated to a smaller object.
- * 9.  Finally, update the various table parameters to reflect the new size.
- */
-
-static void shrink_table(hash_t *hash)
-{
-    hash_val_t chain, nchains;
-    hnode_t **newtable, *low_tail, *low_chain, *high_chain;
-
-    assert (hash->nchains >= 2);			/* 1 */
-    nchains = hash->nchains / 2;
-
-    for (chain = 0; chain < nchains; chain++) {
-	low_chain = hash->table[chain];		/* 2 */
-	high_chain = hash->table[chain + nchains];
-	for (low_tail = low_chain; low_tail && low_tail->next; low_tail = low_tail->next)
-	    ;	/* 3 */
-	if (low_chain != 0)				/* 4 */
-	    low_tail->next = high_chain;
-	else if (high_chain != 0)			/* 5 */
-	    hash->table[chain] = high_chain;
-	else
-	    assert (hash->table[chain] == NULL);	/* 6 */
-    }
-    newtable = realloc(hash->table,
-	    sizeof *newtable * nchains);		/* 7 */
-    if (newtable)					/* 8 */
-	hash->table = newtable;
-    hash->mask >>= 1;			/* 9 */
-    hash->nchains = nchains;
-    hash->lowmark /= 2;
-    hash->highmark /= 2;
-    assert (hash_verify(hash));
-}
-
-
-/*
- * Create a dynamic hash table. Both the hash table structure and the table
- * itself are dynamically allocated. Furthermore, the table is extendible in
- * that it will automatically grow as its load factor increases beyond a
- * certain threshold.
- * Notes:
- * 1. If the number of bits in the hash_val_t type has not been computed yet,
- *    we do so here, because this is likely to be the first function that the
- *    user calls.
- * 2. Allocate a hash table control structure.
- * 3. If a hash table control structure is successfully allocated, we
- *    proceed to initialize it. Otherwise we return a null pointer.
- * 4. We try to allocate the table of hash chains.
- * 5. If we were able to allocate the hash chain table, we can finish
- *    initializing the hash structure and the table. Otherwise, we must
- *    backtrack by freeing the hash structure.
- * 6. INIT_SIZE should be a power of two. The high and low marks are always set
- *    to be twice the table size and half the table size respectively. When the
- *    number of nodes in the table grows beyond the high size (beyond load
- *    factor 2), it will double in size to cut the load factor down to about
- *    about 1. If the table shrinks down to or beneath load factor 0.5,
- *    it will shrink, bringing the load up to about 1. However, the table
- *    will never shrink beneath INIT_SIZE even if it's emptied.
- * 7. This indicates that the table is dynamically allocated and dynamically
- *    resized on the fly. A table that has this value set to zero is
- *    assumed to be statically allocated and will not be resized.
- * 8. The table of chains must be properly reset to all null pointers.
- */
-
-hash_t *hash_create(hashcount_t maxcount, hash_comp_t compfun,
-	hash_fun_t hashfun)
-{
-    hash_t *hash;
-
-    if (hash_val_t_bit == 0)	/* 1 */
-	compute_bits();
-
-    hash = malloc(sizeof *hash);	/* 2 */
-
-    if (hash) {		/* 3 */
-	hash->table = malloc(sizeof *hash->table * INIT_SIZE);	/* 4 */
-	if (hash->table) {	/* 5 */
-	    hash->nchains = INIT_SIZE;		/* 6 */
-	    hash->highmark = INIT_SIZE * 2;
-	    hash->lowmark = INIT_SIZE / 2;
-	    hash->nodecount = 0;
-	    hash->maxcount = maxcount;
-	    hash->compare = compfun ? compfun : hash_comp_default;
-	    hash->function = hashfun ? hashfun : hash_fun_default;
-	    hash->allocnode = hnode_alloc;
-	    hash->freenode = hnode_free;
-	    hash->context = NULL;
-	    hash->mask = INIT_MASK;
-	    hash->dynamic = 1;			/* 7 */
-	    clear_table(hash);			/* 8 */
-	    assert (hash_verify(hash));
-	    return hash;
-	} 
-	free(hash);
-    }
-
-    return NULL;
-}
-
-/*
- * Select a different set of node allocator routines.
- */
-
-void hash_set_allocator(hash_t *hash, hnode_alloc_t al,
-	hnode_free_t fr, void *context)
-{
-    assert (hash_count(hash) == 0);
-    assert ((al == 0 && fr == 0) || (al != 0 && fr != 0));
-
-    hash->allocnode = al ? al : hnode_alloc;
-    hash->freenode = fr ? fr : hnode_free;
-    hash->context = context;
-}
-
-/*
- * Free every node in the hash using the hash->freenode() function pointer, and
- * cause the hash to become empty.
- */
-
-void hash_free_nodes(hash_t *hash)
-{
-    hscan_t hs;
-    hnode_t *node;
-    hash_scan_begin(&hs, hash);
-    while ((node = hash_scan_next(&hs))) {
-	hash_scan_delete(hash, node);
-	hash->freenode(node, hash->context);
-    }
-    hash->nodecount = 0;
-    clear_table(hash);
-}
-
-/*
- * Obsolescent function for removing all nodes from a table,
- * freeing them and then freeing the table all in one step.
- */
-
-void hash_free(hash_t *hash)
-{
-#ifdef KAZLIB_OBSOLESCENT_DEBUG
-    assert ("call to obsolescent function hash_free()" && 0);
-#endif
-    hash_free_nodes(hash);
-    hash_destroy(hash);
-}
-
-/*
- * Free a dynamic hash table structure.
- */
-
-void hash_destroy(hash_t *hash)
-{
-    assert (hash_val_t_bit != 0);
-    assert (hash_isempty(hash));
-    free(hash->table);
-    free(hash);
-}
-
-/*
- * Initialize a user supplied hash structure. The user also supplies a table of
- * chains which is assigned to the hash structure. The table is static---it
- * will not grow or shrink.
- * 1. See note 1. in hash_create().
- * 2. The user supplied array of pointers hopefully contains nchains nodes.
- * 3. See note 7. in hash_create().
- * 4. We must dynamically compute the mask from the given power of two table
- *    size. 
- * 5. The user supplied table can't be assumed to contain null pointers,
- *    so we reset it here.
- */
-
-hash_t *hash_init(hash_t *hash, hashcount_t maxcount,
-	hash_comp_t compfun, hash_fun_t hashfun, hnode_t **table,
-	hashcount_t nchains)
-{
-    if (hash_val_t_bit == 0)	/* 1 */
-	compute_bits();
-
-    assert (is_power_of_two(nchains));
-
-    hash->table = table;	/* 2 */
-    hash->nchains = nchains;
-    hash->nodecount = 0;
-    hash->maxcount = maxcount;
-    hash->compare = compfun ? compfun : hash_comp_default;
-    hash->function = hashfun ? hashfun : hash_fun_default;
-    hash->dynamic = 0;		/* 3 */
-    hash->mask = compute_mask(nchains);	/* 4 */
-    clear_table(hash);		/* 5 */
-
-    assert (hash_verify(hash));
-
-    return hash;
-}
-
-/*
- * Reset the hash scanner so that the next element retrieved by
- * hash_scan_next() shall be the first element on the first non-empty chain. 
- * Notes:
- * 1. Locate the first non empty chain.
- * 2. If an empty chain is found, remember which one it is and set the next
- *    pointer to refer to its first element.
- * 3. Otherwise if a chain is not found, set the next pointer to NULL
- *    so that hash_scan_next() shall indicate failure.
- */
-
-void hash_scan_begin(hscan_t *scan, hash_t *hash)
-{
-    hash_val_t nchains = hash->nchains;
-    hash_val_t chain;
-
-    scan->table = hash;
-
-    /* 1 */
-
-    for (chain = 0; chain < nchains && hash->table[chain] == 0; chain++)
-	;
-
-    if (chain < nchains) {	/* 2 */
-	scan->chain = chain;
-	scan->next = hash->table[chain];
-    } else {			/* 3 */
-	scan->next = NULL;
-    }
-}
-
-/*
- * Retrieve the next node from the hash table, and update the pointer
- * for the next invocation of hash_scan_next(). 
- * Notes:
- * 1. Remember the next pointer in a temporary value so that it can be
- *    returned.
- * 2. This assertion essentially checks whether the module has been properly
- *    initialized. The first point of interaction with the module should be
- *    either hash_create() or hash_init(), both of which set hash_val_t_bit to
- *    a non zero value.
- * 3. If the next pointer we are returning is not NULL, then the user is
- *    allowed to call hash_scan_next() again. We prepare the new next pointer
- *    for that call right now. That way the user is allowed to delete the node
- *    we are about to return, since we will no longer be needing it to locate
- *    the next node.
- * 4. If there is a next node in the chain (next->next), then that becomes the
- *    new next node, otherwise ...
- * 5. We have exhausted the current chain, and must locate the next subsequent
- *    non-empty chain in the table.
- * 6. If a non-empty chain is found, the first element of that chain becomes
- *    the new next node. Otherwise there is no new next node and we set the
- *    pointer to NULL so that the next time hash_scan_next() is called, a null
- *    pointer shall be immediately returned.
- */
-
-
-hnode_t *hash_scan_next(hscan_t *scan)
-{
-    hnode_t *next = scan->next;		/* 1 */
-    hash_t *hash = scan->table;
-    hash_val_t chain = scan->chain + 1;
-    hash_val_t nchains = hash->nchains;
-
-    assert (hash_val_t_bit != 0);	/* 2 */
-
-    if (next) {			/* 3 */
-	if (next->next) {	/* 4 */
-	    scan->next = next->next;
-	} else {
-	    while (chain < nchains && hash->table[chain] == 0)	/* 5 */
-	    	chain++;
-	    if (chain < nchains) {	/* 6 */
-		scan->chain = chain;
-		scan->next = hash->table[chain];
-	    } else {
-		scan->next = NULL;
-	    }
-	}
-    }
-    return next;
-}
-
-/*
- * Insert a node into the hash table.
- * Notes:
- * 1. It's illegal to insert more than the maximum number of nodes. The client
- *    should verify that the hash table is not full before attempting an
- *    insertion.
- * 2. The same key may not be inserted into a table twice.
- * 3. If the table is dynamic and the load factor is already at >= 2,
- *    grow the table.
- * 4. We take the bottom N bits of the hash value to derive the chain index,
- *    where N is the base 2 logarithm of the size of the hash table. 
- */
-
-void hash_insert(hash_t *hash, hnode_t *node, const void *key)
-{
-    hash_val_t hkey, chain;
-
-    assert (hash_val_t_bit != 0);
-    assert (node->next == NULL);
-    assert (hash->nodecount < hash->maxcount);	/* 1 */
-    assert (hash_lookup(hash, key) == NULL);	/* 2 */
-
-    if (hash->dynamic && hash->nodecount >= hash->highmark)	/* 3 */
-	grow_table(hash);
-
-    hkey = hash->function(key);
-    chain = hkey & hash->mask;	/* 4 */
-
-    node->key = key;
-    node->hkey = hkey;
-    node->next = hash->table[chain];
-    hash->table[chain] = node;
-    hash->nodecount++;
-
-    assert (hash_verify(hash));
-}
-
-/*
- * Find a node in the hash table and return a pointer to it.
- * Notes:
- * 1. We hash the key and keep the entire hash value. As an optimization, when
- *    we descend down the chain, we can compare hash values first and only if
- *    hash values match do we perform a full key comparison. 
- * 2. To locate the chain from among 2^N chains, we look at the lower N bits of
- *    the hash value by anding them with the current mask.
- * 3. Looping through the chain, we compare the stored hash value inside each
- *    node against our computed hash. If they match, then we do a full
- *    comparison between the unhashed keys. If these match, we have located the
- *    entry.
- */
-
-hnode_t *hash_lookup(hash_t *hash, const void *key)
-{
-    hash_val_t hkey, chain;
-    hnode_t *nptr;
-
-    hkey = hash->function(key);		/* 1 */
-    chain = hkey & hash->mask;		/* 2 */
-
-    for (nptr = hash->table[chain]; nptr; nptr = nptr->next) {	/* 3 */
-	if (nptr->hkey == hkey && hash->compare(nptr->key, key) == 0)
-	    return nptr;
-    }
-
-    return NULL;
-}
-
-/*
- * Delete the given node from the hash table.  Since the chains
- * are singly linked, we must locate the start of the node's chain
- * and traverse.
- * Notes:
- * 1. The node must belong to this hash table, and its key must not have
- *    been tampered with.
- * 2. If this deletion will take the node count below the low mark, we
- *    shrink the table now. 
- * 3. Determine which chain the node belongs to, and fetch the pointer
- *    to the first node in this chain.
- * 4. If the node being deleted is the first node in the chain, then
- *    simply update the chain head pointer.
- * 5. Otherwise advance to the node's predecessor, and splice out
- *    by updating the predecessor's next pointer.
- * 6. Indicate that the node is no longer in a hash table.
- */
-
-hnode_t *hash_delete(hash_t *hash, hnode_t *node)
-{
-    hash_val_t chain;
-    hnode_t *hptr;
-
-    assert (hash_lookup(hash, node->key) == node);	/* 1 */
-    assert (hash_val_t_bit != 0);
-
-    if (hash->dynamic && hash->nodecount <= hash->lowmark
-	    && hash->nodecount > INIT_SIZE)
-	shrink_table(hash);				/* 2 */
-
-    chain = node->hkey & hash->mask;			/* 3 */
-    hptr = hash->table[chain];
-
-    if (hptr == node) {					/* 4 */
-	hash->table[chain] = node->next;
-    } else {
-	while (hptr->next != node) {			/* 5 */
-	    assert (hptr != 0);
-	    hptr = hptr->next;
-	}
-	assert (hptr->next == node);
-	hptr->next = node->next;
-    }
-	
-    hash->nodecount--;
-    assert (hash_verify(hash));
-
-    node->next = NULL;					/* 6 */
-    return node;
-}
-
-int hash_alloc_insert(hash_t *hash, const void *key, void *data)
-{
-    hnode_t *node = hash->allocnode(hash->context);
-
-    if (node) {
-	hnode_init(node, data);
-	hash_insert(hash, node, key);
-	return 1;
-    }
-    return 0;
-}
-
-void hash_delete_free(hash_t *hash, hnode_t *node)
-{
-    hash_delete(hash, node);
-    hash->freenode(node, hash->context);
-}
-
-/*
- *  Exactly like hash_delete, except does not trigger table shrinkage. This is to be
- *  used from within a hash table scan operation. See notes for hash_delete.
- */
-
-hnode_t *hash_scan_delete(hash_t *hash, hnode_t *node)
-{
-    hash_val_t chain;
-    hnode_t *hptr;
-
-    assert (hash_lookup(hash, node->key) == node);
-    assert (hash_val_t_bit != 0);
-
-    chain = node->hkey & hash->mask;
-    hptr = hash->table[chain];
-
-    if (hptr == node) {
-	hash->table[chain] = node->next;
-    } else {
-	while (hptr->next != node) 
-	    hptr = hptr->next;
-	hptr->next = node->next;
-    }
-	
-    hash->nodecount--;
-    assert (hash_verify(hash));
-    node->next = NULL;
-
-    return node;
-}
-
-/*
- * Like hash_delete_free but based on hash_scan_delete.
- */
-
-void hash_scan_delfree(hash_t *hash, hnode_t *node)
-{
-    hash_scan_delete(hash, node);
-    hash->freenode(node, hash->context);
-}
-
-/*
- * Verify whether the given object is a valid hash table. This means
- * Notes:
- * 1. If the hash table is dynamic, verify whether the high and
- *    low expansion/shrinkage thresholds are powers of two.
- * 2. Count all nodes in the table, and test each hash value
- *    to see whether it is correct for the node's chain.
- */
-
-int hash_verify(hash_t *hash)
-{
-    hashcount_t count = 0;
-    hash_val_t chain;
-    hnode_t *hptr;
-
-    if (hash->dynamic) {	/* 1 */
-	if (hash->lowmark >= hash->highmark)
-	    return 0;
-	if (!is_power_of_two(hash->highmark))
-	    return 0;
-	if (!is_power_of_two(hash->lowmark))
-	    return 0;
-    }
-
-    for (chain = 0; chain < hash->nchains; chain++) {	/* 2 */
-	for (hptr = hash->table[chain]; hptr != 0; hptr = hptr->next) {
-	    if ((hptr->hkey & hash->mask) != chain)
-		return 0;
-	    count++;
-	}
-    }
-
-    if (count != hash->nodecount)
-	return 0;
-
-    return 1;
-}
-
-/*
- * Test whether the hash table is full and return 1 if this is true,
- * 0 if it is false.
- */
-
-#undef hash_isfull
-int hash_isfull(hash_t *hash)
-{
-    return hash->nodecount == hash->maxcount;
-}
-
-/*
- * Test whether the hash table is empty and return 1 if this is true,
- * 0 if it is false.
- */
-
-#undef hash_isempty
-int hash_isempty(hash_t *hash)
-{
-    return hash->nodecount == 0;
-}
-
-static hnode_t *hnode_alloc(void *context)
-{
-    return malloc(sizeof *hnode_alloc(NULL));
-}
-
-static void hnode_free(hnode_t *node, void *context)
-{
-    free(node);
-}
-
-
-/*
- * Create a hash table node dynamically and assign it the given data.
- */
-
-hnode_t *hnode_create(void *data)
-{
-    hnode_t *node = malloc(sizeof *node);
-    if (node) {
-	node->data = data;
-	node->next = NULL;
-    }
-    return node;
-}
-
-/*
- * Initialize a client-supplied node 
- */
-
-hnode_t *hnode_init(hnode_t *hnode, void *data)
-{
-    hnode->data = data;
-    hnode->next = NULL;
-    return hnode;
-}
-
-/*
- * Destroy a dynamically allocated node.
- */
-
-void hnode_destroy(hnode_t *hnode)
-{
-    free(hnode);
-}
-
-#undef hnode_put
-void hnode_put(hnode_t *node, void *data)
-{
-    node->data = data;
-}
-
-#undef hnode_get
-void *hnode_get(hnode_t *node)
-{
-    return node->data;
-}
-
-#undef hnode_getkey
-const void *hnode_getkey(hnode_t *node)
-{
-    return node->key;
-}
-
-#undef hash_count
-hashcount_t hash_count(hash_t *hash)
-{
-    return hash->nodecount;
-}
-
-#undef hash_size
-hashcount_t hash_size(hash_t *hash)
-{
-    return hash->nchains;
-}
-
-static hash_val_t hash_fun_default(const void *key)
-{
-    static unsigned long randbox[] = {
-	0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U,
-	0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU,
-	0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU,
-	0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU,
-    };
-
-    const unsigned char *str = key;
-    hash_val_t acc = 0;
-
-    while (*str) {
-	acc ^= randbox[(*str + acc) & 0xf];
-	acc = (acc << 1) | (acc >> 31);
-	acc &= 0xffffffffU;
-	acc ^= randbox[((*str++ >> 4) + acc) & 0xf];
-	acc = (acc << 2) | (acc >> 30);
-	acc &= 0xffffffffU;
-    }
-    return acc;
-}
-
-static int hash_comp_default(const void *key1, const void *key2)
-{
-    return strcmp(key1, key2);
-}
diff --git a/libutil/kazlib/hash.h b/libutil/kazlib/hash.h
deleted file mode 100644
index e8213f7..0000000
--- a/libutil/kazlib/hash.h
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Hash Table Data Type
- * Copyright (C) 1997 Kaz Kylheku <kaz at ashi.footprints.net>
- *
- * Free Software License:
- *
- * All rights are reserved by the author, with the following exceptions:
- * Permission is granted to freely reproduce and distribute this software,
- * possibly in exchange for a fee, provided that this copyright notice appears
- * intact. Permission is also granted to adapt this software to produce
- * derivative works, as long as the modified versions carry this copyright
- * notice and additional notices stating that the work has been modified.
- * This source code may be translated into executable form and incorporated
- * into proprietary software; there is no requirement for such software to
- * contain a copyright notice related to this source.
- *
- */
-
-#ifndef HASH_H
-#define HASH_H
-
-#include <limits.h>
-#ifdef KAZLIB_SIDEEFFECT_DEBUG
-#include "sfx.h"
-#endif
-
-/*
- * Blurb for inclusion into C++ translation units
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef unsigned long hashcount_t;
-#define HASHCOUNT_T_MAX ULONG_MAX
-
-typedef unsigned long hash_val_t;
-#define HASH_VAL_T_MAX ULONG_MAX
-
-extern int hash_val_t_bit;
-
-#ifndef HASH_VAL_T_BIT
-#define HASH_VAL_T_BIT ((int) hash_val_t_bit)
-#endif
-
-/*
- * Hash chain node structure.
- * Notes:
- * 1. This preprocessing directive is for debugging purposes.  The effect is
- *    that if the preprocessor symbol KAZLIB_OPAQUE_DEBUG is defined prior to the
- *    inclusion of this header,  then the structure shall be declared as having
- *    the single member   int __OPAQUE__.   This way, any attempts by the
- *    client code to violate the principles of information hiding (by accessing
- *    the structure directly) can be diagnosed at translation time. However,
- *    note the resulting compiled unit is not suitable for linking.
- * 2. This is a pointer to the next node in the chain. In the last node of a
- *    chain, this pointer is null.
- * 3. The key is a pointer to some user supplied data that contains a unique
- *    identifier for each hash node in a given table. The interpretation of
- *    the data is up to the user. When creating or initializing a hash table,
- *    the user must supply a pointer to a function for comparing two keys,
- *    and a pointer to a function for hashing a key into a numeric value.
- * 4. The value is a user-supplied pointer to void which may refer to
- *    any data object. It is not interpreted in any way by the hashing
- *    module.
- * 5. The hashed key is stored in each node so that we don't have to rehash
- *    each key when the table must grow or shrink.
- */
-
-typedef struct hnode_t {
-#if defined(HASH_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)	/* 1 */
-    struct hnode_t *hash_next;		/* 2 */
-    const void *hash_key;		/* 3 */
-    void *hash_data;			/* 4 */
-    hash_val_t hash_hkey;		/* 5 */
-#else
-    int hash_dummy;
-#endif
-} hnode_t;
-
-/*
- * The comparison function pointer type. A comparison function takes two keys
- * and produces a value of -1 if the left key is less than the right key, a
- * value of 0 if the keys are equal, and a value of 1 if the left key is
- * greater than the right key.
- */
-
-typedef int (*hash_comp_t)(const void *, const void *);
-
-/*
- * The hashing function performs some computation on a key and produces an
- * integral value of type hash_val_t based on that key. For best results, the
- * function should have a good randomness properties in *all* significant bits
- * over the set of keys that are being inserted into a given hash table. In
- * particular, the most significant bits of hash_val_t are most significant to
- * the hash module. Only as the hash table expands are less significant bits
- * examined. Thus a function that has good distribution in its upper bits but
- * not lower is preferrable to one that has poor distribution in the upper bits
- * but not the lower ones.
- */
-
-typedef hash_val_t (*hash_fun_t)(const void *);
-
-/*
- * allocator functions
- */
-
-typedef hnode_t *(*hnode_alloc_t)(void *);
-typedef void (*hnode_free_t)(hnode_t *, void *);
-
-/*
- * This is the hash table control structure. It keeps track of information
- * about a hash table, as well as the hash table itself.
- * Notes:
- * 1.  Pointer to the hash table proper. The table is an array of pointers to
- *     hash nodes (of type hnode_t). If the table is empty, every element of
- *     this table is a null pointer. A non-null entry points to the first
- *     element of a chain of nodes.
- * 2.  This member keeps track of the size of the hash table---that is, the
- *     number of chain pointers.
- * 3.  The count member maintains the number of elements that are presently
- *     in the hash table.
- * 4.  The maximum count is the greatest number of nodes that can populate this
- *     table. If the table contains this many nodes, no more can be inserted,
- *     and the hash_isfull() function returns true.
- * 5.  The high mark is a population threshold, measured as a number of nodes,
- *     which, if exceeded, will trigger a table expansion. Only dynamic hash
- *     tables are subject to this expansion.
- * 6.  The low mark is a minimum population threshold, measured as a number of
- *     nodes. If the table population drops below this value, a table shrinkage
- *     will occur. Only dynamic tables are subject to this reduction.  No table
- *     will shrink beneath a certain absolute minimum number of nodes.
- * 7.  This is the a pointer to the hash table's comparison function. The
- *     function is set once at initialization or creation time.
- * 8.  Pointer to the table's hashing function, set once at creation or
- *     initialization time.
- * 9.  The current hash table mask. If the size of the hash table is 2^N,
- *     this value has its low N bits set to 1, and the others clear. It is used
- *     to select bits from the result of the hashing function to compute an
- *     index into the table.
- * 10. A flag which indicates whether the table is to be dynamically resized. It
- *     is set to 1 in dynamically allocated tables, 0 in tables that are
- *     statically allocated.
- */
-
-typedef struct hash_t {
-#if defined(HASH_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
-    struct hnode_t **hash_table;		/* 1 */
-    hashcount_t hash_nchains;			/* 2 */
-    hashcount_t hash_nodecount;			/* 3 */
-    hashcount_t hash_maxcount;			/* 4 */
-    hashcount_t hash_highmark;			/* 5 */
-    hashcount_t hash_lowmark;			/* 6 */
-    hash_comp_t hash_compare;			/* 7 */
-    hash_fun_t hash_function;			/* 8 */
-    hnode_alloc_t hash_allocnode;
-    hnode_free_t hash_freenode;
-    void *hash_context;
-    hash_val_t hash_mask;			/* 9 */
-    int hash_dynamic;				/* 10 */
-#else
-    int hash_dummy;
-#endif
-} hash_t;
-
-/*
- * Hash scanner structure, used for traversals of the data structure.
- * Notes:
- * 1. Pointer to the hash table that is being traversed.
- * 2. Reference to the current chain in the table being traversed (the chain
- *    that contains the next node that shall be retrieved).
- * 3. Pointer to the node that will be retrieved by the subsequent call to
- *    hash_scan_next().
- */
-
-typedef struct hscan_t {
-#if defined(HASH_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
-    hash_t *hash_table;		/* 1 */
-    hash_val_t hash_chain;	/* 2 */
-    hnode_t *hash_next;		/* 3 */
-#else
-    int hash_dummy;
-#endif
-} hscan_t;
-
-extern hash_t *hash_create(hashcount_t, hash_comp_t, hash_fun_t);
-extern void hash_set_allocator(hash_t *, hnode_alloc_t, hnode_free_t, void *);
-extern void hash_destroy(hash_t *);
-extern void hash_free_nodes(hash_t *);
-extern void hash_free(hash_t *);
-extern hash_t *hash_init(hash_t *, hashcount_t, hash_comp_t,
-	hash_fun_t, hnode_t **, hashcount_t);
-extern void hash_insert(hash_t *, hnode_t *, const void *);
-extern hnode_t *hash_lookup(hash_t *, const void *);
-extern hnode_t *hash_delete(hash_t *, hnode_t *);
-extern int hash_alloc_insert(hash_t *, const void *, void *);
-extern void hash_delete_free(hash_t *, hnode_t *);
-
-extern void hnode_put(hnode_t *, void *);
-extern void *hnode_get(hnode_t *);
-extern const void *hnode_getkey(hnode_t *);
-extern hashcount_t hash_count(hash_t *);
-extern hashcount_t hash_size(hash_t *);
-
-extern int hash_isfull(hash_t *);
-extern int hash_isempty(hash_t *);
-
-extern void hash_scan_begin(hscan_t *, hash_t *);
-extern hnode_t *hash_scan_next(hscan_t *);
-extern hnode_t *hash_scan_delete(hash_t *, hnode_t *);
-extern void hash_scan_delfree(hash_t *, hnode_t *);
-
-extern int hash_verify(hash_t *);
-
-extern hnode_t *hnode_create(void *);
-extern hnode_t *hnode_init(hnode_t *, void *);
-extern void hnode_destroy(hnode_t *);
-
-#if defined(HASH_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
-#ifdef KAZLIB_SIDEEFFECT_DEBUG
-#define hash_isfull(H) (SFX_CHECK(H)->hash_nodecount == (H)->hash_maxcount)
-#else
-#define hash_isfull(H) ((H)->hash_nodecount == (H)->hash_maxcount)
-#endif
-#define hash_isempty(H) ((H)->hash_nodecount == 0)
-#define hash_count(H) ((H)->hash_nodecount)
-#define hash_size(H) ((H)->hash_nchains)
-#define hnode_get(N) ((N)->hash_data)
-#define hnode_getkey(N) ((N)->hash_key)
-#define hnode_put(N, V) ((N)->hash_data = (V))
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/libutil/kazlib/list.c b/libutil/kazlib/list.c
deleted file mode 100644
index 818b427..0000000
--- a/libutil/kazlib/list.c
+++ /dev/null
@@ -1,766 +0,0 @@
-/*
- * List Abstract Data Type
- * Copyright (C) 1997 Kaz Kylheku <kaz at ashi.footprints.net>
- *
- * Free Software License:
- *
- * All rights are reserved by the author, with the following exceptions:
- * Permission is granted to freely reproduce and distribute this software,
- * possibly in exchange for a fee, provided that this copyright notice appears
- * intact. Permission is also granted to adapt this software to produce
- * derivative works, as long as the modified versions carry this copyright
- * notice and additional notices stating that the work has been modified.
- * This source code may be translated into executable form and incorporated
- * into proprietary software; there is no requirement for such software to
- * contain a copyright notice related to this source.
- *
- */
-
-
-#include <stdlib.h>
-#include <stddef.h>
-#include <assert.h>
-#define LIST_IMPLEMENTATION
-#include "list.h"
-
-#define next list_next
-#define prev list_prev
-#define data list_data
-
-#define pool list_pool
-#define fre list_free
-#define size list_size
-
-#define nilnode list_nilnode
-#define nodecount list_nodecount
-#define maxcount list_maxcount
-
-#define list_nil(L)		(&(L)->nilnode)
-#define list_first_priv(L)	((L)->nilnode.next)
-#define list_last_priv(L)	((L)->nilnode.prev)
-#define lnode_next(N)		((N)->next)
-#define lnode_prev(N)		((N)->prev)
-
-/*
- * Initialize a list object supplied by the client such that it becomes a valid
- * empty list. If the list is to be ``unbounded'', the maxcount should be
- * specified as LISTCOUNT_T_MAX, or, alternately, as -1. The value zero
- * is not permitted.
- */
-
-list_t *list_init(list_t *list, listcount_t maxcount)
-{
-    assert (maxcount != 0);
-    list->nilnode.next = &list->nilnode;
-    list->nilnode.prev = &list->nilnode;
-    list->nodecount = 0;
-    list->maxcount = maxcount;
-    return list;
-}
-
-/*
- * Dynamically allocate a list object using malloc(), and initialize it so that
- * it is a valid empty list. If the list is to be ``unbounded'', the maxcount
- * should be specified as LISTCOUNT_T_MAX, or, alternately, as -1.
- */
-
-list_t *list_create(listcount_t maxcount)
-{
-    list_t *new = malloc(sizeof *new);
-    if (new) {
-	assert (maxcount != 0);
-	new->nilnode.next = &new->nilnode;
-	new->nilnode.prev = &new->nilnode;
-	new->nodecount = 0;
-	new->maxcount = maxcount;
-    }
-    return new;
-}
-
-/*
- * Destroy a dynamically allocated list object.
- * The client must remove the nodes first.
- */
-
-void list_destroy(list_t *list)
-{
-    assert (list_isempty(list));
-    free(list);
-}
-
-/*
- * Free all of the nodes of a list. The list must contain only 
- * dynamically allocated nodes. After this call, the list
- * is empty.
- */
-
-void list_destroy_nodes(list_t *list)
-{
-    lnode_t *lnode = list_first_priv(list), *nil = list_nil(list), *tmp;
-
-    while (lnode != nil) {
-	tmp = lnode->next;
-	lnode->next = NULL;
-	lnode->prev = NULL;
-	lnode_destroy(lnode);
-	lnode = tmp;
-    }
-
-    list_init(list, list->maxcount);
-}
-
-/*
- * Return all of the nodes of a list to a node pool. The nodes in
- * the list must all have come from the same pool.
- */
-
-void list_return_nodes(list_t *list, lnodepool_t *pool)
-{
-    lnode_t *lnode = list_first_priv(list), *tmp, *nil = list_nil(list);
-
-    while (lnode != nil) {
-	tmp = lnode->next;
-	lnode->next = NULL;
-	lnode->prev = NULL;
-	lnode_return(pool, lnode);
-	lnode = tmp;
-    }
-
-    list_init(list, list->maxcount);
-}
-
-/*
- * Insert the node ``new'' into the list immediately after ``this'' node.
- */
-
-void list_ins_after(list_t *list, lnode_t *new, lnode_t *this)
-{
-    lnode_t *that = this->next;
-
-    assert (new != NULL);
-    assert (!list_contains(list, new));
-    assert (!lnode_is_in_a_list(new));
-    assert (this == list_nil(list) || list_contains(list, this));
-    assert (list->nodecount + 1 > list->nodecount);
-
-    new->prev = this;
-    new->next = that;
-    that->prev = new;
-    this->next = new;
-    list->nodecount++;
-
-    assert (list->nodecount <= list->maxcount);
-}
-
-/*
- * Insert the node ``new'' into the list immediately before ``this'' node.
- */
-
-void list_ins_before(list_t *list, lnode_t *new, lnode_t *this)
-{
-    lnode_t *that = this->prev;
-
-    assert (new != NULL);
-    assert (!list_contains(list, new));
-    assert (!lnode_is_in_a_list(new));
-    assert (this == list_nil(list) || list_contains(list, this));
-    assert (list->nodecount + 1 > list->nodecount);
-
-    new->next = this;
-    new->prev = that;
-    that->next = new;
-    this->prev = new;
-    list->nodecount++;
-
-    assert (list->nodecount <= list->maxcount);
-}
-
-/*
- * Delete the given node from the list.
- */
-
-lnode_t *list_delete(list_t *list, lnode_t *del)
-{
-    lnode_t *next = del->next;
-    lnode_t *prev = del->prev;
-
-    assert (list_contains(list, del));
-
-    prev->next = next;
-    next->prev = prev;
-    list->nodecount--;
-
-    del->next = del->prev = NULL;
-
-    return del;
-}
-
-/*
- * For each node in the list, execute the given function. The list,
- * current node and the given context pointer are passed on each
- * call to the function.
- */
-
-void list_process(list_t *list, void *context,
-	void (* function)(list_t *list, lnode_t *lnode, void *context))
-{
-    lnode_t *node = list_first_priv(list), *next, *nil = list_nil(list);
-
-    while (node != nil) {
-	/* check for callback function deleting	*/
-	/* the next node from under us		*/
-	assert (list_contains(list, node));
-	next = node->next;
-	function(list, node, context);
-	node = next;
-    }
-}
-
-/*
- * Dynamically allocate a list node and assign it the given piece of data.
- */
-
-lnode_t *lnode_create(void *data)
-{
-    lnode_t *new = malloc(sizeof *new);
-    if (new) {
-	new->data = data;
-	new->next = NULL;
-	new->prev = NULL;
-    }
-    return new;
-}
-
-/*
- * Initialize a user-supplied lnode.
- */
-
-lnode_t *lnode_init(lnode_t *lnode, void *data)
-{
-    lnode->data = data;
-    lnode->next = NULL;
-    lnode->prev = NULL;
-    return lnode;
-}
-
-/*
- * Destroy a dynamically allocated node.
- */
-
-void lnode_destroy(lnode_t *lnode)
-{
-    assert (!lnode_is_in_a_list(lnode));
-    free(lnode);
-}
-
-/*
- * Initialize a node pool object to use a user-supplied set of nodes.
- * The ``nodes'' pointer refers to an array of lnode_t objects, containing
- * ``n'' elements.
- */
-
-lnodepool_t *lnode_pool_init(lnodepool_t *pool, lnode_t *nodes, listcount_t n)
-{
-    listcount_t i;
-
-    assert (n != 0);
-
-    pool->pool = nodes;
-    pool->fre = nodes;
-    pool->size = n;
-    for (i = 0; i < n - 1; i++) {
-	nodes[i].next = nodes + i + 1;
-    }
-    nodes[i].next = NULL;
-    nodes[i].prev = nodes;	/* to make sure node is marked ``on list'' */
-    return pool;
-}
-
-/*
- * Create a dynamically allocated pool of n nodes.
- */
-
-lnodepool_t *lnode_pool_create(listcount_t n)
-{
-    lnodepool_t *pool;
-    lnode_t *nodes;
-
-    assert (n != 0);
-
-    pool = malloc(sizeof *pool);
-    if (!pool)
-	return NULL;
-    nodes = malloc(n * sizeof *nodes);
-    if (!nodes) {
-	free(pool);
-	return NULL;
-    }
-    lnode_pool_init(pool, nodes, n);
-    return pool;
-}
-
-/*
- * Determine whether the given pool is from this pool.
- */
-
-int lnode_pool_isfrom(lnodepool_t *pool, lnode_t *node)
-{
-    listcount_t i;
-
-    /* this is carefully coded this way because ANSI C forbids pointers
-       to different objects from being subtracted or compared other
-       than for exact equality */
-
-    for (i = 0; i < pool->size; i++) {
-	if (pool->pool + i == node)
-	    return 1;
-    }
-    return 0;
-}
-
-/*
- * Destroy a dynamically allocated pool of nodes.
- */
-
-void lnode_pool_destroy(lnodepool_t *p)
-{
-    free(p->pool);
-    free(p);
-}
-
-/*
- * Borrow a node from a node pool. Returns a null pointer if the pool
- * is exhausted. 
- */
-
-lnode_t *lnode_borrow(lnodepool_t *pool, void *data)
-{
-    lnode_t *new = pool->fre;
-    if (new) {
-	pool->fre = new->next;
-	new->data = data;
-	new->next = NULL;
-	new->prev = NULL;
-    }
-    return new;
-}
-
-/*
- * Return a node to a node pool. A node must be returned to the pool
- * from which it came.
- */
-
-void lnode_return(lnodepool_t *pool, lnode_t *node)
-{
-    assert (lnode_pool_isfrom(pool, node));
-    assert (!lnode_is_in_a_list(node));
-
-    node->next = pool->fre;
-    node->prev = node;
-    pool->fre = node;
-}
-
-/*
- * Determine whether the given list contains the given node.
- * According to this function, a list does not contain its nilnode.
- */
-
-int list_contains(list_t *list, lnode_t *node)
-{
-    lnode_t *n, *nil = list_nil(list);
-
-    for (n = list_first_priv(list); n != nil; n = lnode_next(n)) {
-	if (node == n)
-	    return 1;
-    }
-
-    return 0;
-}
-
-/*
- * A more generalized variant of list_transfer. This one removes a
- * ``slice'' from the source list and appends it to the destination
- * list.
- */
-
-void list_extract(list_t *dest, list_t *source, lnode_t *first, lnode_t *last)
-{
-    listcount_t moved = 1;
-
-    assert (first == NULL || list_contains(source, first));
-    assert (last == NULL || list_contains(source, last));
-
-    if (first == NULL || last == NULL)
-	return;
-
-    /* adjust the destination list so that the slice is spliced out */
-
-    first->prev->next = last->next;
-    last->next->prev = first->prev;
-
-    /* graft the splice at the end of the dest list */
-
-    last->next = &dest->nilnode;
-    first->prev = dest->nilnode.prev;
-    dest->nilnode.prev->next = first;
-    dest->nilnode.prev = last;
-
-    while (first != last) {
-	first = first->next;
-	assert (first != list_nil(source));	/* oops, last before first! */
-	moved++;
-    }
-    
-    /* assert no overflows */
-    assert (source->nodecount - moved <= source->nodecount);
-    assert (dest->nodecount + moved >= dest->nodecount);
-
-    /* assert no weirdness */
-    assert (moved <= source->nodecount);
-
-    source->nodecount -= moved;
-    dest->nodecount += moved;
-
-    /* assert list sanity */
-    assert (list_verify(source));
-    assert (list_verify(dest));
-}
-
-
-/*
- * Split off a trailing sequence of nodes from the source list and relocate
- * them to the tail of the destination list. The trailing sequence begins
- * with node ``first'' and terminates with the last node of the source
- * list. The nodes are added to the end of the new list in their original
- * order.
- */
-
-void list_transfer(list_t *dest, list_t *source, lnode_t *first)
-{
-    listcount_t moved = 1;
-    lnode_t *last;
-
-    assert (first == NULL || list_contains(source, first));
-
-    if (first == NULL)
-	return;
-
-    last = source->nilnode.prev;
-
-    source->nilnode.prev = first->prev;
-    first->prev->next = &source->nilnode;
-
-    last->next = &dest->nilnode;
-    first->prev = dest->nilnode.prev;
-    dest->nilnode.prev->next = first;
-    dest->nilnode.prev = last;
-
-    while (first != last) {
-	first = first->next;
-	moved++;
-    }
-    
-    /* assert no overflows */
-    assert (source->nodecount - moved <= source->nodecount);
-    assert (dest->nodecount + moved >= dest->nodecount);
-
-    /* assert no weirdness */
-    assert (moved <= source->nodecount);
-
-    source->nodecount -= moved;
-    dest->nodecount += moved;
-
-    /* assert list sanity */
-    assert (list_verify(source));
-    assert (list_verify(dest));
-}
-
-void list_merge(list_t *dest, list_t *sour,
-	int compare (const void *, const void *))
-{
-    lnode_t *dn, *sn, *tn;
-    lnode_t *d_nil = list_nil(dest), *s_nil = list_nil(sour);
-
-    /* Nothing to do if source and destination list are the same. */
-    if (dest == sour)
-	return;
-
-    /* overflow check */
-    assert (list_count(sour) + list_count(dest) >= list_count(sour));
-
-    /* lists must be sorted */
-    assert (list_is_sorted(sour, compare));
-    assert (list_is_sorted(dest, compare));
-
-    dn = list_first_priv(dest);
-    sn = list_first_priv(sour);
-
-    while (dn != d_nil && sn != s_nil) {
-	if (compare(lnode_get(dn), lnode_get(sn)) >= 0) {
-	    tn = lnode_next(sn);
-	    list_delete(sour, sn);
-	    list_ins_before(dest, sn, dn);
-	    sn = tn;
-	} else {
-	    dn = lnode_next(dn);
-	}
-    }
-
-    if (dn != d_nil)
-	return;
-
-    if (sn != s_nil)
-	list_transfer(dest, sour, sn);
-}
-
-void list_sort(list_t *list, int compare(const void *, const void *))
-{
-    list_t extra;
-    listcount_t middle;
-    lnode_t *node;
-
-    if (list_count(list) > 1) {
-	middle = list_count(list) / 2;
-	node = list_first_priv(list);
-
-	list_init(&extra, list_count(list) - middle);
-
-	while (middle--)
-	    node = lnode_next(node);
-	
-	list_transfer(&extra, list, node);
-	list_sort(list, compare);
-	list_sort(&extra, compare);
-	list_merge(list, &extra, compare);
-    } 
-    assert (list_is_sorted(list, compare));
-}
-
-lnode_t *list_find(list_t *list, const void *key, int compare(const void *, const void *))
-{
-    lnode_t *node;
-
-    for (node = list_first_priv(list); node != list_nil(list); node = node->next) {
-	if (compare(lnode_get(node), key) == 0)
-	    return node;
-    }
-    
-    return 0;
-}
-
-
-/*
- * Return 1 if the list is in sorted order, 0 otherwise
- */
-
-int list_is_sorted(list_t *list, int compare(const void *, const void *))
-{
-    lnode_t *node, *next, *nil;
-
-    next = nil = list_nil(list);
-    node = list_first_priv(list);
-
-    if (node != nil)
-	next = lnode_next(node);
-
-    for (; next != nil; node = next, next = lnode_next(next)) {
-	if (compare(lnode_get(node), lnode_get(next)) > 0)
-	    return 0;
-    }
-
-    return 1;
-}
-
-/*
- * Get rid of macro functions definitions so they don't interfere
- * with the actual definitions
- */
-
-#undef list_isempty
-#undef list_isfull
-#undef lnode_pool_isempty
-#undef list_append
-#undef list_prepend
-#undef list_first
-#undef list_last
-#undef list_next
-#undef list_prev
-#undef list_count
-#undef list_del_first
-#undef list_del_last
-#undef lnode_put
-#undef lnode_get
-
-/*
- * Return 1 if the list is empty, 0 otherwise
- */
-
-int list_isempty(list_t *list)
-{
-    return list->nodecount == 0;
-}
-
-/*
- * Return 1 if the list is full, 0 otherwise
- * Permitted only on bounded lists. 
- */
-
-int list_isfull(list_t *list)
-{
-    return list->nodecount == list->maxcount;
-}
-
-/*
- * Check if the node pool is empty.
- */
-
-int lnode_pool_isempty(lnodepool_t *pool)
-{
-    return (pool->fre == NULL);
-}
-
-/*
- * Add the given node at the end of the list
- */
-
-void list_append(list_t *list, lnode_t *node)
-{
-    list_ins_before(list, node, &list->nilnode);
-}
-
-/*
- * Add the given node at the beginning of the list.
- */
-
-void list_prepend(list_t *list, lnode_t *node)
-{
-    list_ins_after(list, node, &list->nilnode);
-}
-
-/*
- * Retrieve the first node of the list
- */
-
-lnode_t *list_first(list_t *list)
-{
-    if (list->nilnode.next == &list->nilnode)
-	return NULL;
-    return list->nilnode.next;
-}
-
-/*
- * Retrieve the last node of the list
- */
-
-lnode_t *list_last(list_t *list)
-{
-    if (list->nilnode.prev == &list->nilnode)
-	return NULL;
-    return list->nilnode.prev;
-}
-
-/*
- * Retrieve the count of nodes in the list
- */
-
-listcount_t list_count(list_t *list)
-{
-    return list->nodecount;
-}
-
-/*
- * Remove the first node from the list and return it.
- */
-
-lnode_t *list_del_first(list_t *list)
-{
-    return list_delete(list, list->nilnode.next);
-}
-
-/*
- * Remove the last node from the list and return it.
- */
-
-lnode_t *list_del_last(list_t *list)
-{
-    return list_delete(list, list->nilnode.prev);
-}
-
-
-/*
- * Associate a data item with the given node.
- */
-
-void lnode_put(lnode_t *lnode, void *data)
-{
-    lnode->data = data;
-}
-
-/*
- * Retrieve the data item associated with the node.
- */
-
-void *lnode_get(lnode_t *lnode)
-{
-    return lnode->data;
-}
-
-/*
- * Retrieve the node's successor. If there is no successor, 
- * NULL is returned.
- */
-
-lnode_t *list_next(list_t *list, lnode_t *lnode)
-{
-    assert (list_contains(list, lnode));
-
-    if (lnode->next == list_nil(list))
-	return NULL;
-    return lnode->next;
-}
-
-/*
- * Retrieve the node's predecessor. See comment for lnode_next().
- */
-
-lnode_t *list_prev(list_t *list, lnode_t *lnode)
-{
-    assert (list_contains(list, lnode));
-
-    if (lnode->prev == list_nil(list))
-	return NULL;
-    return lnode->prev;
-}
-
-/*
- * Return 1 if the lnode is in some list, otherwise return 0.
- */
-
-int lnode_is_in_a_list(lnode_t *lnode)
-{
-    return (lnode->next != NULL || lnode->prev != NULL);
-}
-
-
-int list_verify(list_t *list)
-{
-    lnode_t *node = list_first_priv(list), *nil = list_nil(list);
-    listcount_t count = list_count(list);
-
-    if (node->prev != nil)
-	return 0;
-
-    if (count > list->maxcount)
-	return 0;
-
-    while (node != nil && count--) {
-	if (node->next->prev != node)
-	    return 0;
-	node = node->next;
-    }
-
-    if (count != 0 || node != nil)
-	return 0;
-    
-    return 1;
-}
diff --git a/libutil/kazlib/list.h b/libutil/kazlib/list.h
deleted file mode 100644
index 97abc2f..0000000
--- a/libutil/kazlib/list.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * List Abstract Data Type
- * Copyright (C) 1997 Kaz Kylheku <kaz at ashi.footprints.net>
- *
- * Free Software License:
- *
- * All rights are reserved by the author, with the following exceptions:
- * Permission is granted to freely reproduce and distribute this software,
- * possibly in exchange for a fee, provided that this copyright notice appears
- * intact. Permission is also granted to adapt this software to produce
- * derivative works, as long as the modified versions carry this copyright
- * notice and additional notices stating that the work has been modified.
- * This source code may be translated into executable form and incorporated
- * into proprietary software; there is no requirement for such software to
- * contain a copyright notice related to this source.
- *
- */
-
-#ifndef LIST_H
-#define LIST_H
-
-#include <limits.h>
-
-#ifdef KAZLIB_SIDEEFFECT_DEBUG
-#include "sfx.h"
-#define LIST_SFX_CHECK(E) SFX_CHECK(E)
-#else
-#define LIST_SFX_CHECK(E) (E)
-#endif
-
-/*
- * Blurb for inclusion into C++ translation units
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef unsigned long listcount_t;
-#define LISTCOUNT_T_MAX ULONG_MAX
-
-typedef struct lnode_t {
-#if defined(LIST_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
-    struct lnode_t *list_next;
-    struct lnode_t *list_prev;
-    void *list_data;
-#else
-    int list_dummy;
-#endif
-} lnode_t;
-
-typedef struct lnodepool_t {
-#if defined(LIST_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
-    struct lnode_t *list_pool;
-    struct lnode_t *list_free;
-    listcount_t list_size;
-#else
-    int list_dummy;
-#endif
-} lnodepool_t;
-
-typedef struct list_t {
-#if defined(LIST_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
-    lnode_t list_nilnode;
-    listcount_t list_nodecount;
-    listcount_t list_maxcount;
-#else
-    int list_dummy;
-#endif
-} list_t;
-
-lnode_t *lnode_create(void *);
-lnode_t *lnode_init(lnode_t *, void *);
-void lnode_destroy(lnode_t *);
-void lnode_put(lnode_t *, void *);
-void *lnode_get(lnode_t *);
-int lnode_is_in_a_list(lnode_t *);
-
-#if defined(LIST_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
-#define lnode_put(N, D)		((N)->list_data = (D))
-#define lnode_get(N)		((N)->list_data)
-#endif
-
-lnodepool_t *lnode_pool_init(lnodepool_t *, lnode_t *, listcount_t);
-lnodepool_t *lnode_pool_create(listcount_t);
-void lnode_pool_destroy(lnodepool_t *);
-lnode_t *lnode_borrow(lnodepool_t *, void *);
-void lnode_return(lnodepool_t *, lnode_t *);
-int lnode_pool_isempty(lnodepool_t *);
-int lnode_pool_isfrom(lnodepool_t *, lnode_t *);
-
-list_t *list_init(list_t *, listcount_t);
-list_t *list_create(listcount_t);
-void list_destroy(list_t *);
-void list_destroy_nodes(list_t *);
-void list_return_nodes(list_t *, lnodepool_t *);
-
-listcount_t list_count(list_t *);
-int list_isempty(list_t *);
-int list_isfull(list_t *);
-int list_contains(list_t *, lnode_t *);
-
-void list_append(list_t *, lnode_t *);
-void list_prepend(list_t *, lnode_t *);
-void list_ins_before(list_t *, lnode_t *, lnode_t *);
-void list_ins_after(list_t *, lnode_t *, lnode_t *);
-
-lnode_t *list_first(list_t *);
-lnode_t *list_last(list_t *);
-lnode_t *list_next(list_t *, lnode_t *);
-lnode_t *list_prev(list_t *, lnode_t *);
-
-lnode_t *list_del_first(list_t *);
-lnode_t *list_del_last(list_t *);
-lnode_t *list_delete(list_t *, lnode_t *);
-
-void list_process(list_t *, void *, void (*)(list_t *, lnode_t *, void *));
-
-int list_verify(list_t *);
-
-#if defined(LIST_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
-#define lnode_pool_isempty(P)	((P)->list_free == 0)
-#define list_count(L)		((L)->list_nodecount)
-#define list_isempty(L)		((L)->list_nodecount == 0)
-#define list_isfull(L)		(LIST_SFX_CHECK(L)->list_nodecount == (L)->list_maxcount)
-#define list_next(L, N)		(LIST_SFX_CHECK(N)->list_next == &(L)->list_nilnode ? NULL : (N)->list_next)
-#define list_prev(L, N)		(LIST_SFX_CHECK(N)->list_prev == &(L)->list_nilnode ? NULL : (N)->list_prev)
-#define list_first(L)		list_next(LIST_SFX_CHECK(L), &(L)->list_nilnode)
-#define list_last(L)		list_prev(LIST_SFX_CHECK(L), &(L)->list_nilnode)
-#endif
-
-#if defined(LIST_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
-#define list_append(L, N)	list_ins_before(LIST_SFX_CHECK(L), N, &(L)->list_nilnode)
-#define list_prepend(L, N)	list_ins_after(LIST_SFX_CHECK(L), N, &(L)->list_nilnode)
-#define list_del_first(L)	list_delete(LIST_SFX_CHECK(L), list_first(L))
-#define list_del_last(L)	list_delete(LIST_SFX_CHECK(L), list_last(L))
-#endif
-
-/* destination list on the left, source on the right */
-
-void list_extract(list_t *, list_t *, lnode_t *, lnode_t *);
-void list_transfer(list_t *, list_t *, lnode_t *first);
-void list_merge(list_t *, list_t *, int (const void *, const void *));
-void list_sort(list_t *, int (const void *, const void *));
-lnode_t *list_find(list_t *, const void *, int (const void *, const void *));
-int list_is_sorted(list_t *, int (const void *, const void *));
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/libutil/kazlib/sfx.c b/libutil/kazlib/sfx.c
deleted file mode 100644
index 829a53d..0000000
--- a/libutil/kazlib/sfx.c
+++ /dev/null
@@ -1,1138 +0,0 @@
-/*
- * SFX---A utility which tries to determine whether a given C expression
- * is free of side effects. This can be used for verifying that macros which
- * expand their arguments more than once are not being accidentally misused.
- *
- * Copyright (C) 1999 Kaz Kylheku <kaz at ashi.footprints.net>
- *
- * Free Software License:
- *
- * All rights are reserved by the author, with the following exceptions:
- * Permission is granted to freely reproduce and distribute this software,
- * possibly in exchange for a fee, provided that this copyright notice appears
- * intact. Permission is also granted to adapt this software to produce
- * derivative works, as long as the modified versions carry this copyright
- * notice and additional notices stating that the work has been modified.
- * This source code may be translated into executable form and incorporated
- * into proprietary software; there is no requirement for such software to
- * contain a copyright notice related to this source.
- *
- */
-
-#include <ctype.h>
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-#include "except.h"
-#include "sfx.h"
-#include "hash.h"
-#ifdef KAZLIB_POSIX_THREADS
-#include <pthread.h>
-#endif
-
-/*
- * Exceptions
- */
-
-#define SFX_EX		0x34DB9C4A
-#define SFX_SYNERR	1
-
-/*
- * Cache entry
- */
-
-typedef struct {
-    hnode_t node;
-    const char *expr;
-    sfx_rating_t eff;
-} sfx_entry_t;
-
-/*
- * Parsing context structure
- */
-
-typedef struct {
-    const unsigned char *start;
-    const unsigned char *input;
-    size_t size;
-    sfx_rating_t eff;
-} context_t;
-
-/*
- * Declarator type: abstract, concrete or both
- */
-
-typedef enum {
-    decl_abstract, decl_concrete, decl_both
-} decl_t;
-
-static void init_context(context_t *ctx, const unsigned char *expr)
-{
-    ctx->input = ctx->start = expr;
-    ctx->size = strlen((const char *) expr) + 1;
-    ctx->eff = sfx_none;
-}
-
-static void assign_context(context_t *copy, context_t *orig)
-{
-    *copy = *orig;
-}
-
-static void set_effect(context_t *ctx, sfx_rating_t eff)
-{
-    assert (eff == sfx_none || eff == sfx_potential || eff == sfx_certain);
-
-    if (eff > ctx->eff)
-	ctx->eff = eff;
-}
-
-static void reset_effect(context_t *ctx)
-{
-    ctx->eff = sfx_none;
-}
-
-static sfx_rating_t get_effect(context_t *ctx)
-{
-    return ctx->eff;
-}
-
-static int skip_ws(context_t *expr)
-{
-    while (*expr->input != 0 && isspace(*expr->input))
-	expr->input++;
-
-    return (*expr->input == 0);
-}
-
-static int get_next(context_t *expr)
-{
-    int ret = *expr->input;
-    if (ret)
-	expr->input++;
-    return ret;
-}
-
-static int get_next_skip_ws(context_t *expr)
-{
-    if (!skip_ws(expr))
-	return *expr->input++;
-    return 0;
-}
-
-static const unsigned char *get_ptr(context_t *expr)
-{
-    return expr->input;
-}
-
-static void skip_n(context_t *ctx, size_t n)
-{
-    assert ((size_t) (ctx->input - ctx->start) <= ctx->size - n);
-    ctx->input += n;
-}
-
-static void put_back(context_t *expr, int ch)
-{
-    if (ch)
-	expr->input--;
-}
-
-static int peek_next(context_t *expr)
-{
-    return *expr->input;
-}
-
-static void syntax_error(void)
-{
-    except_throw(SFX_EX, SFX_SYNERR, "syntax_error");
-}
-
-static void match_hard(context_t *expr, int match)
-{
-    int ch = get_next(expr);
-    if (ch != match)
-	syntax_error();
-}
-
-static void chk_comma(context_t *);
-
-static void skip_ident(context_t *expr)
-{
-    int ch = get_next(expr);
-
-    if (!isalpha(ch) && ch != '_')
-	syntax_error();
-
-    do {
-	ch = get_next(expr);
-    } while (isalnum(ch) || ch == '_');
-
-    put_back(expr, ch);
-}
-
-static void skip_constant(context_t *expr)
-{
-    int ch = get_next(expr);
-
-    assert (isdigit(ch) || ch == '.');
-
-    do {
-	ch = get_next(expr);
-	if (ch == 'e' || ch == 'E') {
-	    ch = get_next(expr);
-	    if (ch == '+' || ch == '-') {
-		ch = get_next(expr);
-		if (!isdigit(ch))
-		    syntax_error();
-	    }
-	}
-    } while (ch != 0 && (isalnum(ch) || ch == '.'));
-
-    put_back(expr, ch);
-}
-
-static void skip_strlit(context_t *expr)
-{
-    int ch = get_next(expr);
-
-    assert (ch == '"');
-
-    do {
-	ch = get_next(expr);
-	if (ch == '\\') {
-	    get_next(expr);
-	    continue;
-	}
-    } while (ch != 0 && ch != '"');
-
-    if (ch != '"')
-	syntax_error();
-}
-
-static void skip_charlit(context_t *expr)
-{
-    int ch = get_next(expr);
-
-    assert (ch == '\'');
-
-    do {
-	ch = get_next(expr);
-	if (ch == '\\') {
-	    get_next(expr);
-	    continue;
-	}
-    } while (ch != 0 && ch != '\'');
-
-    if (ch != '\'')
-	syntax_error();
-}
-
-static void chk_spec_qual_list(context_t *expr)
-{
-    skip_ws(expr);
-    skip_ident(expr);
-
-    for (;;) {
-	int ch;
-
-	skip_ws(expr);
-	ch = peek_next(expr);
-
-	if (!isalpha(ch) && ch != '_')
-	    break;
-
-	skip_ident(expr);
-    }
-}
-
-static int speculate(void (*chk_func)(context_t *), context_t *expr, context_t *copy, int nextchar)
-{
-    static const except_id_t catch[] = { { SFX_EX, XCEPT_CODE_ANY } };
-    except_t *ex;
-    volatile int result = 0;
-    assign_context(copy, expr);
-
-    except_try_push(catch, 1, &ex);
-
-    if (ex == 0) {
-	chk_func(copy);
-	if (nextchar) {
-	    skip_ws(copy);
-	    match_hard(copy, nextchar);
-	}
-	result = 1;
-    } 
-
-    except_try_pop();
-
-    return result;
-}
-
-static void chk_pointer_opt(context_t *expr)
-{
-    for (;;) {
-	int ch = get_next_skip_ws(expr);
-
-	if (ch != '*') {
-	    put_back(expr, ch);
-	    break;
-	}
-
-	skip_ws(expr);
-
-	ch = peek_next(expr);
-
-	if (ch == '*')
-	    continue;
-	if (!isalpha(ch) && ch != '_')
-	    break;
-
-	skip_ident(expr);
-    }
-}
-
-static void chk_decl(context_t *, decl_t);
-
-static void chk_parm_decl(context_t *expr)
-{
-    chk_spec_qual_list(expr);
-    chk_decl(expr, decl_both);
-}
-
-static void chk_parm_type_list(context_t *expr)
-{
-    for (;;) {
-	int ch;
-
-	chk_parm_decl(expr);
-
-	ch = get_next_skip_ws(expr);
-
-	if (ch != ',') {
-	    put_back(expr, ch);
-	    break;
-	}
-
-	ch = get_next_skip_ws(expr);
-
-	if (ch == '.') {
-	    match_hard(expr, '.');
-	    match_hard(expr, '.');
-	    break;
-	}
-
-	put_back(expr, ch);
-    }
-}
-
-static void chk_conditional(context_t *);
-
-static void chk_direct_decl(context_t *expr, decl_t type)
-{
-    for (;;) {
-	int ch = get_next_skip_ws(expr);
-
-	if (ch == '(') {
-	    skip_ws(expr);
-	    ch = peek_next(expr);
-	    if (ch == '*' || ch == '(' || ch == '[')
-		chk_decl(expr, type);
-	    else if (isalpha(ch) || ch == '_')
-		chk_parm_type_list(expr);
-	    match_hard(expr, ')');
-	} else if (ch == '[') {
-	    skip_ws(expr);
-	    ch = peek_next(expr);
-	    if (ch != ']')
-		chk_conditional(expr);
-	    match_hard(expr, ']');		
-	} else if ((type == decl_concrete || type == decl_both) && (isalpha(ch) || ch == '_')) {
-	    put_back(expr, ch);
-	    skip_ident(expr);
-	    break;
-	} else {
-	    put_back(expr, ch);
-	    break;
-	}
-    }
-}
-
-static void chk_decl(context_t *expr, decl_t type)
-{
-    int ch;
-    chk_pointer_opt(expr);
-    skip_ws(expr);
-    ch = peek_next(expr);
-    if (ch == '[' || ch == '(' || ((type == decl_concrete || type == decl_both) && (isalpha(ch) || ch == '_'))) {
-	chk_direct_decl(expr, type);
-    } 
-}
-
-static void chk_typename(context_t *expr)
-{
-    chk_spec_qual_list(expr);
-    chk_decl(expr, decl_abstract);
-}
-
-static void chk_primary(context_t *expr)
-{
-    int ch = peek_next(expr);
-
-    if (ch == 'L') {
-	get_next(expr);
-	ch = peek_next(expr);
-
-	if (ch == '\'') {
-	    skip_charlit(expr);
-	    return;
-	}
-
-	if (ch == '"') {
-	    skip_strlit(expr);
-	    return;
-	}
-
-	put_back(expr, 'L');
-	ch = 'L';
-    }
-
-    if (isalpha(ch) || ch == '_') {
-    	skip_ident(expr);
-	return;
-    }
-
-    if (isdigit(ch) || ch == '.') {
-	skip_constant(expr);
-	return;
-    }
-
-    if (ch == '(') {
-	get_next(expr);
-	chk_comma(expr);
-	match_hard(expr, ')');
-	return;
-    }
-
-    if (ch == '\'') {
-	skip_charlit(expr);
-	return;
-    }
-
-    if (ch == '"') {
-	skip_strlit(expr);
-	return;
-    }
-
-    syntax_error();
-}
-
-static void chk_postfix(context_t *expr)
-{
-    chk_primary(expr);
-
-    for (;;) {
-	int ch = get_next_skip_ws(expr);
-
-	switch (ch) {
-	case '[':
-	    chk_comma(expr);
-	    skip_ws(expr);
-	    match_hard(expr, ']');
-	    continue;
-	case '(':
-	    set_effect(expr, sfx_potential);
-	    ch = get_next_skip_ws(expr);
-
-	    if (ch != ')') {
-		put_back(expr, ch);
-		/* clever hack: parse non-empty argument list as comma expression */
-		chk_comma(expr);
-		ch = get_next_skip_ws(expr);
-	    }
-
-	    if (ch != ')')
-		syntax_error();
-
-	    continue;
-	case '.':
-	    skip_ws(expr);
-	    skip_ident(expr);
-	    continue;
-	case '-':
-	    ch = get_next(expr);
-
-	    if (ch != '-' && ch != '>') {
-		put_back(expr, ch);
-		put_back(expr, '-');
-		break;
-	    }
-
-	    if (ch == '>') {
-		skip_ws(expr);
-		skip_ident(expr);
-		continue;
-	    }
-
-	    set_effect(expr, sfx_certain);
-	    continue;
-	case '+':
-	    ch = get_next(expr);
-	    if (ch != '+') {
-		put_back(expr, ch);
-		put_back(expr, '+');
-		break;
-	    }
-
-	    set_effect(expr, sfx_certain);
-	    continue;
-	default:
-	    put_back(expr, ch);
-	    break;
-	}
-	break;
-    }
-}
-
-static void chk_cast(context_t *);
-
-static void chk_unary(context_t *expr)
-{
-    for (;;) {
-	int nscan, ch = get_next_skip_ws(expr);
-
-	switch (ch) {
-	case '+':
-	    ch = get_next(expr);
-	    if (ch == '+')
-		set_effect(expr, sfx_certain);
-	    else
-		put_back(expr, ch);
-	    chk_cast(expr);
-	    break;
-	case '-':
-	    ch = get_next(expr);
-	    if (ch == '-')
-		set_effect(expr, sfx_certain);
-	    else
-		put_back(expr, ch);
-	    chk_cast(expr);
-	    break;
-	case '&': case '*': case '~': case '!':
-	    chk_cast(expr);
-	    break;
-	case 's':
-	    put_back(expr, ch);
-	    nscan = 0;
-	    sscanf((const char *) get_ptr(expr), "sizeof%*1[^a-z0-9_]%n", &nscan);
-
-	    if (nscan == 7 || strcmp((const char *) get_ptr(expr), "sizeof") == 0) {
-		sfx_rating_t eff = get_effect(expr);
-
-	    	skip_n(expr, 6);
-
-		ch = get_next_skip_ws(expr);
-
-		if (ch == '(') {
-		    context_t comma, type;
-		    int iscomma = speculate(chk_comma, expr, &comma, ')');
-		    int istype = speculate(chk_typename, expr, &type, ')');
-
-		    if (!iscomma && !istype)
-			syntax_error();
-
-		    if (iscomma) {
-			context_t unary;
-			put_back(expr, ch);
-			if (speculate(chk_unary, expr, &unary, 0)) {
-			    assign_context(expr, &unary);
-			    istype = 0;
-			}
-		    }
-
-		    if (istype)
-			assign_context(expr, &type);
-		} else {
-		    put_back(expr, ch);
-		    chk_unary(expr);
-		}
-
-		reset_effect(expr);
-		set_effect(expr, eff);
-		break;
-	    }
-	    chk_postfix(expr);
-	    break;
-	default:
-	    put_back(expr, ch);
-	    chk_postfix(expr);
-	    break;
-	}
-
-	break;
-    }
-}
-
-static void chk_cast(context_t *expr)
-{
-    enum {
-	parexpr,	/* parenthesized expression */
-	partype,	/* parenthesized type name */
-	parambig,	/* ambiguity between paren expr and paren type name */
-	unary,		/* unary expression */
-	plunary,	/* unary expression with leading plus or minus */
-	other		/* none of the above, or even end of input */
-    } curr = partype, old = partype, peek = partype;
-
-    /* history for backtracking: two cast expression elements back */
-    context_t old_expr = { 0 }, cur_expr = { 0 };
-
-    for (;;) {
-	context_t type, comma, unr;
-	int ch = get_next_skip_ws(expr);
-
-	/*
-	 * Determine what the next bit of input is: parenthesized type name,
-	 * expression, unary expression or what?  Speculative parsing is used
-	 * to test several hypotheses.  For example,  something like
-	 * (X)(Y) ^ 1 is seen, it will be turned, by subsequent iterations of
-	 * this loop, into the codes: parambig, parambig, other.
-	 */
-
-	if (ch == '(') {
-	    int istype = speculate(chk_typename, expr, &type, ')');
-	    int iscomma = speculate(chk_comma, expr, &comma, ')');
-
-	    switch (istype << 1 | iscomma) {
-	    case 0:
-		ch = get_next_skip_ws(expr);
-		if (ch == ')')
-		    peek = other; /* empty parentheses */
-		else
-		    syntax_error();
-		break;
-	    case 1:
-		peek = parexpr;
-		break;
-	    case 2:
-		peek = partype;
-		break;
-	    case 3:
-		peek = parambig;
-		break;
-	    }
-	    put_back(expr, ch);
-	} else if (ch == 0) {
-	    peek = other;
-	} else {
-	    put_back(expr, ch);
-	    if (speculate(chk_unary, expr, &unr, 0)) {
-		peek = (ch == '+' || ch == '-' || ch == '*' || ch == '&') ? plunary : unary;
-	    } else {
-		peek = other;
-	    }
-	}
-
-	/*
-	 * Okay, now we have an idea what is coming in the input. We make some
-	 * sensible decision based on this and the thing we parsed previously.
-	 * Either the parsing continues to grab more parenthesized things, or
-	 * some decision is made to parse out the suffix material sensibly and
-	 * terminate.  Backtracking is used up to two elements back. For
-	 * example in the case of (X)(Y) ^ 1 (parambig, parambig, other) it's
-	 * necessary, upon seeing ^ 1 (other) to go back to second to last
-	 * ambigous parenthesized element (X) and terminate by parsing the
-	 * (X)(Y) as a postfix expression. It cannot be a cast, because ^1
-	 * isn't an expression.  Unary expressions that start with + or -
-	 * create an interesting ambiguity.  Is (X)(Y) + 1 the addition of 1 to
-	 * the result of the call to function X with parameter Y? Or is it the
-	 * unary expression + 1 cast to type Y and X? The safer assumption is
-	 * to go with the function call hypothesis, since that's the
-	 * interpretation that may have side effects. 
-	 */
-
-	switch (curr) {
-	case parexpr:		/* impossible cases */
-	case other:
-	case unary:
-	case plunary:
-	    assert (0);
-	    syntax_error();
-	    /* notreached */
-	case partype:
-	    switch (peek) {
-	    case parexpr:	/* cast in front of parenthesized expression */
-		chk_postfix(expr);
-		return;
-	    case partype:	/* compounding cast: keep looping */
-		break;
-	    case parambig:	/* type or expr: keep looping */
-		break;
-	    case unary:
-	    case plunary:
-		chk_unary(expr);
-		return;
-	    case other:		/* cast in front of non-expression! */
-		syntax_error();
-		/* notreached */
-	    }
-	    break;
-	case parambig:
-	    switch (peek) {
-	    case parexpr:	/* function call */
-		assign_context(expr, &cur_expr);
-		chk_postfix(expr);
-		return;
-	    case partype:	/* compounding cast: keep looping */
-		break;
-	    case parambig:	/* type or expr: keep looping */
-		break;
-	    case unary:
-		chk_unary(expr);
-		return;
-	    case plunary:	/* treat unary expr with + or - as additive */
-	    case other:
-		if (old == parambig) {
-		    /* reparse two expression-like things in a row as call */
-		    assign_context(expr, &old_expr);
-		    chk_postfix(expr);
-		    return;
-		}
-		/* reparse expression followed by non-parenthesized 
-		   stuff as postfix expression */
-		assign_context(expr, &cur_expr);
-		chk_postfix(expr);
-		return;		/* need more context */
-	    }
-	    break;
-	}
-
-	old = curr;
-	curr = peek;
-	assign_context(&old_expr, &cur_expr);
-	assign_context(&cur_expr, expr);
-	assign_context(expr, &type);
-    }
-}
-
-static void chk_multiplicative(context_t *expr)
-{
-    for (;;) {
-	int ch;
-
-	chk_cast(expr);
-	ch = get_next_skip_ws(expr);
-
-	if ((ch != '*' && ch != '/' && ch != '%') || peek_next(expr) == '=') {
-	    put_back(expr, ch);
-	    break;
-	}
-    }
-}
-
-static void chk_additive(context_t *expr)
-{
-    for (;;) {
-	int ch;
-
-	chk_multiplicative(expr);
-	ch = get_next_skip_ws(expr);
-
-	if ((ch != '+' && ch != '-') || peek_next(expr) == '=') {
-	    put_back(expr, ch);
-	    break;
-	}
-    }
-}
-
-static void chk_shift(context_t *expr)
-{
-    for (;;) {
-	int ch;
-
-	chk_additive(expr);
-	ch = get_next_skip_ws(expr);
-
-	if (ch != '<' && ch != '>') {
-	    put_back(expr, ch);
-	    break;
-	}
-
-	if (ch == '<' && peek_next(expr) != '<') {
-	    put_back(expr, ch);
-	    break;
-	}
-
-	if (ch == '>' && peek_next(expr) != '>') {
-	    put_back(expr, ch);
-	    break;
-	}
-
-	get_next(expr);
-
-	if (peek_next(expr) == '=') {
-	    put_back(expr, ch);
-	    put_back(expr, ch);
-	    break;
-	}
-    }
-}
-
-static void chk_relational(context_t *expr)
-{
-    for (;;) {
-	int ch;
-
-	chk_shift(expr);
-	ch = get_next_skip_ws(expr);
-
-	
-	if (ch != '<' && ch != '>') {
-	    put_back(expr, ch);
-	    break;
-	}
-
-	if (ch == '<' && peek_next(expr) == '<') {
-	    put_back(expr, ch);
-	    break;
-	}
-
-	if (ch == '>' && peek_next(expr) == '>') {
-	    put_back(expr, ch);
-	    break;
-	}
-
-	if (peek_next(expr) == '=')
-	    get_next(expr);
-    }
-}
-
-static void chk_equality(context_t *expr)
-{
-    for (;;) {
-	int ch;
-
-	chk_relational(expr);
-	ch = get_next_skip_ws(expr);
-
-	if ((ch != '!' && ch != '=') || peek_next(expr) != '=') {
-	    put_back(expr, ch);
-	    break;
-	}
-
-	match_hard(expr, '=');
-    }
-}
-
-static void chk_and(context_t *expr)
-{
-    for (;;) {
-	int ch;
-
-	chk_equality(expr);
-	ch = get_next_skip_ws(expr);
-
-	if (ch != '&' || peek_next(expr) == '&' || peek_next(expr) == '=') {
-	    put_back(expr, ch);
-	    break;
-	}
-    }
-}
-
-static void chk_exclusive_or(context_t *expr)
-{
-    for (;;) {
-	int ch;
-
-	chk_and(expr);
-	ch = get_next_skip_ws(expr);
-
-	if (ch != '^' || peek_next(expr) == '=') {
-	    put_back(expr, ch);
-	    break;
-	}
-    }
-}
-
-static void chk_inclusive_or(context_t *expr)
-{
-    for (;;) {
-	int ch;
-
-	chk_exclusive_or(expr);
-	ch = get_next_skip_ws(expr);
-
-	if (ch != '|' || peek_next(expr) == '|' || peek_next(expr) == '=') {
-	    put_back(expr, ch);
-	    break;
-	}
-    }
-}
-
-static void chk_logical_and(context_t *expr)
-{
-    for (;;) {
-	int ch;
-
-	chk_inclusive_or(expr);
-	ch = get_next_skip_ws(expr);
-
-	if (ch != '&' || peek_next(expr) != '&') {
-	    put_back(expr, ch);
-	    break;
-	}
-
-	match_hard(expr, '&');
-    }
-}
-
-static void chk_logical_or(context_t *expr)
-{
-    for (;;) {
-	int ch;
-
-	chk_logical_and(expr);
-	ch = get_next_skip_ws(expr);
-
-	if (ch != '|' || peek_next(expr) != '|') {
-	    put_back(expr, ch);
-	    break;
-	}
-
-	match_hard(expr, '|');
-    }
-}
-
-static void chk_conditional(context_t *expr)
-{
-    for (;;) {
-	int ch;
-
-	chk_logical_or(expr);
-	ch = get_next_skip_ws(expr);
-
-	if (ch != '?') {
-	    put_back(expr, ch);
-	    break;
-	}
-
-	chk_comma(expr);
-	
-	skip_ws(expr);
-	match_hard(expr, ':');
-    }
-}
-
-static void chk_assignment(context_t *expr)
-{
-    for (;;) {
-	int ch;
-
-	chk_conditional(expr);
-	ch = get_next_skip_ws(expr);
-
-	switch (ch) {
-	case '=':
-	    break;
-	case '*': case '/': case '%':
-	case '+': case '-': case '&':
-	case '^': case '|':
-	    match_hard(expr, '=');
-	    break;
-	case '<':
-	    match_hard(expr, '<');
-	    match_hard(expr, '=');
-	    break;
-	case '>':
-	    match_hard(expr, '>');
-	    match_hard(expr, '=');
-	    break;
-	case 0:
-	default:
-	    put_back(expr, ch);
-	    return;
-	}
-	set_effect(expr, sfx_certain);
-    }
-}
-
-static void chk_comma(context_t *expr)
-{
-    for (;;) {
-	int ch;
-
-	chk_assignment(expr);
-	ch = get_next_skip_ws(expr);
-
-	if (ch != ',') {
-	    put_back(expr, ch);
-	    break;
-	}
-    }
-}
-
-/*
- * This function returns 1 if the expression is successfully parsed,
- * or 0 if there is a syntax error.
- * 
- * The object pointed to by eff is set to indicate the side effect ranking of
- * the parsed expression: sfx_none, sfx_potential and sfx_certain.  These
- * rankins mean, respectively, that there are no side effects, that there are
- * potential side effects, or that there certainly are side effects.
- */
-
-int sfx_determine(const char *expr, sfx_rating_t *eff)
-{
-    static const except_id_t catch[] = { { SFX_EX, XCEPT_CODE_ANY } };
-    except_t *ex;
-    context_t ctx;
-    volatile int retval = 1;
-
-    if (!except_init())
-	return 0;
-
-    init_context(&ctx, (const unsigned char *) expr);
-
-    except_try_push(catch, 1, &ex);
-
-    if (ex == 0) {
-	chk_comma(&ctx);
-	skip_ws(&ctx);
-	if (peek_next(&ctx) != 0)
-	    syntax_error();
-    } else {
-	/* exception caught */
-	retval = 0;
-    }
-
-    except_try_pop();
-
-    *eff = ctx.eff;
-
-    except_deinit();
-
-    return retval;
-}
-
-
-#ifdef KAZLIB_POSIX_THREADS
-
-static pthread_once_t cache_init;
-static pthread_mutex_t cache_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-#define init_once(X, Y) pthread_once(X, Y)
-#define lock_cache() pthread_mutex_lock(&cache_mutex)
-#define unlock_cache() pthread_mutex_unlock(&cache_mutex)
-
-#else
-static int cache_init;
-
-static void init_once(int *once, void (*func)(void))
-{
-    if (*once == 0) {
-	func();
-	*once = 1;
-    }
-}
-
-#define lock_cache()
-#define unlock_cache()
-#endif
-
-static hash_t *cache;
-
-extern hash_t *hash_create(hashcount_t, hash_comp_t, hash_fun_t);
-
-static void init_cache(void)
-{
-    cache = hash_create(HASHCOUNT_T_MAX, 0, 0);
-}
-
-static int lookup_cache(const char *expr, sfx_rating_t *rating)
-{
-    hnode_t *cache_node;
-    init_once(&cache_init, init_cache);
-
-    lock_cache();
-
-    cache_node = hash_lookup(cache, expr);
-
-    unlock_cache();
-
-    if (cache_node != 0) {
-	sfx_entry_t *cache_entry = hnode_get(cache_node);
-	*rating = cache_entry->eff;
-	return 1;
-    }
-
-    return 0;
-}
-
-static int cache_result(const char *expr, sfx_rating_t rating)
-{
-    int result = 0;
-    hnode_t *cache_node;
-
-    init_once(&cache_init, init_cache);
-
-    if (cache == 0)
-	goto bail;
-
-    lock_cache();
-
-    cache_node = hash_lookup(cache, expr);
-
-    if (!cache_node) {
-	sfx_entry_t *cache_entry = malloc(sizeof *cache_entry);
-
-	if (cache_entry == 0)
-	    goto bail_unlock;
-
-	hnode_init(&cache_entry->node, cache_entry);
-	cache_entry->expr = expr;
-	cache_entry->eff = rating;
-	hash_insert(cache, &cache_entry->node, expr);
-    } else {
-	sfx_entry_t *cache_entry = hnode_get(cache_node);
-	cache_entry->eff = rating;
-	result = 1;
-    }
-
-    result = 1;
-
-    
-bail_unlock:
-    unlock_cache();
-
-bail:
-    return result;
-}
-
-
-void sfx_check(const char *expr, const char *file, unsigned long line)
-{
-    sfx_rating_t eff;
-    int success = lookup_cache(expr, &eff);
-
-    if (!success) {
-	success = sfx_determine(expr, &eff);
-	cache_result(expr, eff);
-    }
-
-    if (!success) {
-	fprintf(stderr, "%s:%ld: syntax error in expression \"%s\"\n",
-		file, line, expr);
-    } else if (eff == sfx_potential) {
-	fprintf(stderr, "%s:%ld: expression \"%s\" may have side effects\n",
-		file, line, expr);
-    } else if (eff == sfx_certain) {
-	fprintf(stderr, "%s:%ld: expression \"%s\" has side effects\n",
-		file, line, expr);
-    } else {
-	return;
-    }
-}
-
-int sfx_declare(const char *expr, sfx_rating_t eff)
-{
-    return cache_result(expr, eff);
-}
-
diff --git a/libutil/kazlib/sfx.h b/libutil/kazlib/sfx.h
deleted file mode 100644
index b2a485c..0000000
--- a/libutil/kazlib/sfx.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SideChk---A utility which tries to determine whether a given C expression
- * is free of side effects. This can be used for verifying that macros which
- * expand their arguments more than once are not being accidentally misused.
- *
- * Copyright (C) 1999 Kaz Kylheku <kaz at ashi.footprints.net>
- *
- * Free Software License:
- *
- * All rights are reserved by the author, with the following exceptions:
- * Permission is granted to freely reproduce and distribute this software,
- * possibly in exchange for a fee, provided that this copyright notice appears
- * intact. Permission is also granted to adapt this software to produce
- * derivative works, as long as the modified versions carry this copyright
- * notice and additional notices stating that the work has been modified.
- * This source code may be translated into executable form and incorporated
- * into proprietary software; there is no requirement for such software to
- * contain a copyright notice related to this source.
- *
- */
-
-#ifndef SFX_H
-#define SFX_H
-
-#include <assert.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum {
-    sfx_none, sfx_potential, sfx_certain
-} sfx_rating_t;
-
-int sfx_determine(const char *, sfx_rating_t *);
-int sfx_declare(const char *, sfx_rating_t);
-void sfx_check(const char *, const char *, unsigned long);
-
-#ifdef __cplusplus
-}
-#endif
-
-#define SFX_CHECK(E) (sfx_check(#E, __FILE__, __LINE__), (E))
-#define SFX_STRING(E) #E
-
-#endif
diff --git a/meryl/Make.include b/meryl/Make.include
index 494d4a2..205d1b9 100644
--- a/meryl/Make.include
+++ b/meryl/Make.include
@@ -19,24 +19,19 @@ merylsrc := $/args.C \
 
 #  meryl.H is exported only for celera-assembler.
 
-$/.CXX_SRCS   := ${merylsrc} $/meryl.C $/mervin.C $/asmMerQC.C $/mapMers.C $/mapMers-depth.C $/maskMers.C $/compare-counts.C $/simple.C
+$/.CXX_SRCS   := ${merylsrc} $/meryl.C $/simple.C $/mapMers.C $/mapMers-depth.C $/kmer-mask.C
 $/.CXX_INCS   := $/meryl.H
 $/.CXX_LIBS   := $/libmerylguts.a
-$/.CXX_EXES   := $/meryl $/mervin $/simple $/asmMerQC $/mapMers $/mapMers-depth $/testPositionBias $/maskMers $/compare-counts
+$/.CXX_EXES   := $/meryl $/simple $/mapMers $/mapMers-depth $/kmer-mask
 $/.CLEAN      := $/*.o
 
 $/libmerylguts.a : ${merylsrc:.C=.o}
 
-$/meryl            : $/meryl.o      $/libmerylguts.a            ${LIBMERYL/}libmeryl.a ${LIBSEQ/}libseq.a ${LIBBIO/}libbio.a ${LIBUTL/}libutil.a
-$/mervin           : $/mervin.o                                 ${LIBMERYL/}libmeryl.a ${LIBSEQ/}libseq.a ${LIBBIO/}libbio.a ${LIBUTL/}libutil.a
-$/simple           : $/simple.o                                 ${LIBMERYL/}libmeryl.a ${LIBSEQ/}libseq.a ${LIBBIO/}libbio.a ${LIBUTL/}libutil.a
-$/asmMerQC         : $/asmMerQC.o                               ${LIBMERYL/}libmeryl.a ${LIBSEQ/}libseq.a ${LIBBIO/}libbio.a ${LIBUTL/}libutil.a
-$/mapMers          : $/mapMers.o           ${LIBKMER/}libkmer.a ${LIBMERYL/}libmeryl.a ${LIBSEQ/}libseq.a ${LIBBIO/}libbio.a ${LIBUTL/}libutil.a
-$/mapMers-depth    : $/mapMers-depth.o     ${LIBKMER/}libkmer.a ${LIBMERYL/}libmeryl.a ${LIBSEQ/}libseq.a ${LIBBIO/}libbio.a ${LIBUTL/}libutil.a
-$/m                : $/m.o                 ${LIBKMER/}libkmer.a ${LIBMERYL/}libmeryl.a ${LIBSEQ/}libseq.a ${LIBBIO/}libbio.a ${LIBUTL/}libutil.a
-$/testPositionBias : $/testPositionBias.o  ${LIBKMER/}libkmer.a ${LIBMERYL/}libmeryl.a ${LIBSEQ/}libseq.a ${LIBBIO/}libbio.a ${LIBUTL/}libutil.a
-$/maskMers         : $/maskMers.o          ${LIBKMER/}libkmer.a ${LIBMERYL/}libmeryl.a ${LIBSEQ/}libseq.a ${LIBBIO/}libbio.a ${LIBUTL/}libutil.a
-$/compare-counts   : $/compare-counts.o    ${LIBKMER/}libkmer.a ${LIBMERYL/}libmeryl.a ${LIBSEQ/}libseq.a ${LIBBIO/}libbio.a ${LIBUTL/}libutil.a
+$/meryl:         $/meryl.o             $/libmerylguts.a     ${LIBMERYL/}libmeryl.a ${LIBSEQ/}libseq.a ${LIBBIO/}libbio.a ${LIBUTL/}libutil.a
+$/simple:        $/simple.o                                 ${LIBMERYL/}libmeryl.a ${LIBSEQ/}libseq.a ${LIBBIO/}libbio.a ${LIBUTL/}libutil.a
+$/mapMers:       $/mapMers.o           ${LIBKMER/}libkmer.a ${LIBMERYL/}libmeryl.a ${LIBSEQ/}libseq.a ${LIBBIO/}libbio.a ${LIBUTL/}libutil.a
+$/mapMers-depth: $/mapMers-depth.o     ${LIBKMER/}libkmer.a ${LIBMERYL/}libmeryl.a ${LIBSEQ/}libseq.a ${LIBBIO/}libbio.a ${LIBUTL/}libutil.a
+$/kmer-mask:     $/kmer-mask.o         ${LIBKMER/}libkmer.a ${LIBMERYL/}libmeryl.a ${LIBSEQ/}libseq.a ${LIBBIO/}libbio.a ${LIBUTL/}libutil.a 
 
 $(eval $/%.d $/%.o:  CXXFLAGS+=-I${LIBMERYL/} -I${LIBKMER/} -I${LIBBIO/} -I${LIBSEQ/} -I${LIBUTL/})
 
diff --git a/meryl/asmMerQC.C b/meryl/asmMerQC.C
deleted file mode 100644
index 35bdfbb..0000000
--- a/meryl/asmMerQC.C
+++ /dev/null
@@ -1,396 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "libmeryl.H"
-
-//  The categories depend on the type of input (fragments or contigs):
-//
-//  0 -- no count, mer not present
-//  1 -- single copy
-//  2 --   2 ->  10 copies (contigs) --    2 ->   2mode copies (frags)
-//  3 --  11 -> 100 copies (contigs) --      ->  10mode copies (frags)
-//  4 -- 101+ copies (contigs)       --      -> 100mode copies (frags)
-//  5                                --      -> infinity copies (frags)
-
-//  You'll also need to modify compare() and output() if you change this.
-#define NUMCATEGORIES  6
-
-//  The output files are global for convenience.  Otherwise, we'd be passing
-//  them to compare() for every single mer.
-//
-bool   dumpFlag = false;
-FILE  *dumpSCZF = 0L;
-FILE  *dumpMCZF = 0L;
-FILE  *dumpMCSF = 0L;
-FILE  *dumpMCMF = 0L;
-char   merstring[1024];
-
-uint32
-findMode(char *name) {
-  merylStreamReader  *M = new merylStreamReader(name);
-  uint32             *H = new uint32 [16384];
-
-  fprintf(stderr, "Finding mode of '%s'\n", name);
-
-  for (uint32 i=0; i<16384; i++)
-    H[i] = 0;
-
-  while (M->validMer()) {
-    if (M->theCount() < 16384)
-      H[M->theCount()]++;
-    M->nextMer();
-  }
-
-  uint32  mi = 2;
-  for (uint32 i=2; i<16384; i++)
-    if (H[i] > H[mi])
-      mi = i;
-
-  fprintf(stderr, "Mode of '%s' is "uint32FMT"\n", name, mi);
-
-  return(mi);
-}
-
-
-void
-compare(merylStreamReader *F,
-        merylStreamReader *C,
-        kMer              &minmer,
-        uint32             mode,
-        uint32             R[NUMCATEGORIES][NUMCATEGORIES]) {
-  uint32  Ftype = 0;
-  uint32  Ctype = 0;
-  kMer    Fmer  = F->theFMer();
-  kMer    Cmer  = C->theFMer();
-  uint32  Fcnt  = F->theCount();
-  uint32  Ccnt  = C->theCount();
-
-  if (Fcnt == 0)
-    Ftype = 0;
-  else if (Fcnt == 1)
-    Ftype = 1;
-  else if (Fcnt <= 2*mode)
-    Ftype = 2;
-  else if (Fcnt <= 10*mode)
-    Ftype = 3;
-  else if (Fcnt <= 100*mode)
-    Ftype = 4;
-  else
-    Ftype = 5;
-
-  if (Ccnt == 0)
-    Ctype = 0;
-  else if (Ccnt == 1)
-    Ctype = 1;
-  else if (Ccnt <= 10)
-    Ctype = 2;
-  else if (Ccnt <= 100)
-    Ctype = 3;
-  else
-    Ctype = 4;
-
-  //  If the mer isn't valid, we hit the end of the file, and the mer
-  //  thus (obviously) isn't in the file.
-  //
-  if (F->validMer() == false)
-    Ftype = 0;
-  if (C->validMer() == false)
-    Ctype = 0;
-
-  //  If either type is 0, we're done, but only increment the count if
-  //  this mer is the minmer.
-  //
-  if ((Ftype == 0) || (Ctype == 0)) {
-    if (((Ftype == 0) && (Cmer == minmer)) ||
-        ((Ctype == 0) && (Fmer == minmer))) {
-      R[Ftype][Ctype]++;
-
-      //  Save the mer if it's in contigs, but not fragments.
-      if (dumpFlag)
-        if (Ftype == 0)
-          if (Ctype == 1)
-            fprintf(dumpSCZF, ">"uint32FMT"\n%s\n", Ccnt, Cmer.merToString(merstring));
-          else
-            fprintf(dumpMCZF, ">"uint32FMT"\n%s\n", Ccnt, Cmer.merToString(merstring));
-    }
-    return;
-  }
-
-  //  If the mers don't agree, we're also done.  If either is the
-  //  minmer, note that we saw it.
-  //
-  if (Fmer != Cmer) {
-    if (Fmer == minmer)
-      R[Ftype][0]++;
-    if (Cmer == minmer) {
-      R[0][Ctype]++;
-
-      //  Again, save the mer since it's in contigs, but not fragments.
-      if (dumpFlag)
-        if (Ctype == 1)
-          fprintf(dumpSCZF, ">"uint32FMT"\n%s\n", Ccnt, Cmer.merToString(merstring));
-        else
-          fprintf(dumpMCZF, ">"uint32FMT"\n%s\n", Ccnt, Cmer.merToString(merstring));
-    }
-
-    return;
-  }
-
-  //  If we're not the minmer, we're done.
-  if (Fmer != minmer)
-    return;
-
-  //  Otherwise, the mers are in both inputs
-  R[Ftype][Ctype]++;
-
-  //  Save the mer if it's in contigs "more" than if in fragments.
-  if (dumpFlag) {
-    if (Ftype < Ctype)
-      if (Ctype == 2)
-        fprintf(dumpMCSF, ">"uint32FMT"\n%s\n", Ccnt, Cmer.merToString(merstring));
-      else
-        fprintf(dumpMCMF, ">"uint32FMT"\n%s\n", Ccnt, Cmer.merToString(merstring));
-
-    if ((Ftype == 0) && (Ctype == 1))
-      fprintf(dumpSCZF, ">"uint32FMT"\n%s\n", Ccnt, Cmer.merToString(merstring));
-  }
-}
-
-
-void
-output(char              *title,
-       uint32             mode,
-       uint32             R[NUMCATEGORIES][NUMCATEGORIES]) {
-
-  fprintf(stdout, "\n\n%s\n", title);
-  fprintf(stdout, "(frags)    |      zero |       one |     <= 10 |    <= 100 |    <= inf | (contigs)\n");
-
-  for (uint32 i=0; i<6; i++) {
-    switch (i) {
-      case 0:  fprintf(stdout, "zero       ");  break;
-      case 1:  fprintf(stdout, "one        ");  break;
-      case 2:  fprintf(stdout, "<= 2mode   ");  break;
-      case 3:  fprintf(stdout, "<= 10mode  ");  break;
-      case 4:  fprintf(stdout, "<= 100mode ");  break;
-      case 5:  fprintf(stdout, "<= inf     ");  break;
-      default: fprintf(stdout, "?????????  ");  break;
-    }
-    for (uint32 j=0; j<5; j++)
-      fprintf(stdout, uint32FMTW(12), R[i][j]);
-    fprintf(stdout, "\n");
-  }
-}
-
-
-
-
-int
-main(int argc, char **argv) {
-  merylStreamReader  *AF = 0L;
-  merylStreamReader  *TF = 0L;
-  merylStreamReader  *AC = 0L;
-  merylStreamReader  *DC = 0L;
-  merylStreamReader  *CO = 0L;
-
-  uint32              AFmode = 0;
-  uint32              TFmode = 0;
-
-  char                dumpSCZFname[1024] = {0};  //  single contig, zero frags
-  char                dumpMCZFname[1024] = {0};  //  low contig, zero frags
-  char                dumpMCSFname[1024] = {0};  //  medium contig, low frags
-  char                dumpMCMFname[1024] = {0};  //  everything else, contig > frags
-
-  bool                beVerbose = false;
-
-  //fprintf(stderr, "using cached modes for testing!\n");
-
-  int arg=1;
-  while (arg < argc) {
-    if        (strcmp(argv[arg], "-af") == 0) {  //  All frags
-      ++arg;
-      AFmode = findMode(argv[arg]);
-      //AFmode = 8;
-      AF = new merylStreamReader(argv[arg]);
-      AF->nextMer();
-    } else if (strcmp(argv[arg], "-tf") == 0) {  //  Trimmed frags
-      ++arg;
-      TFmode = findMode(argv[arg]);
-      //TFmode = 8;
-      TF = new merylStreamReader(argv[arg]);
-      TF->nextMer();
-    } else if (strcmp(argv[arg], "-ac") == 0) {  //  All contigs
-      AC = new merylStreamReader(argv[++arg]);
-      AC->nextMer();
-    } else if (strcmp(argv[arg], "-dc") == 0) {  //  Degenerate contigs
-      DC = new merylStreamReader(argv[++arg]);
-      DC->nextMer();
-    } else if (strcmp(argv[arg], "-co") == 0) {  //  Contigs
-      CO = new merylStreamReader(argv[++arg]);
-      CO->nextMer();
-    } else if (strcmp(argv[arg], "-dump") == 0) {
-      arg++;
-      dumpFlag = true;
-      sprintf(dumpSCZFname, "%s.0.singlecontig.zerofrag.fasta",       argv[arg]);
-      sprintf(dumpMCZFname, "%s.1.multiplecontig.zerofrag.fasta",     argv[arg]);
-      sprintf(dumpMCSFname, "%s.2.multiplecontig.lowfrag.fasta",      argv[arg]);
-      sprintf(dumpMCMFname, "%s.3.multiplecontig.multiplefrag.fasta", argv[arg]);
-    } else if (strcmp(argv[arg], "-v") == 0) {
-      beVerbose = true;
-    } else {
-      fprintf(stderr, "unknown option '%s'\n", argv[arg]);
-    }
-    arg++;
-  }
-
-  if ((AF == 0L) && (TF == 0L) && (AC == 0L) && (DC == 0L) && (CO == 0L)) {
-    fprintf(stderr, "usage: %s [opts] [-v] [-dump prefix]\n", argv[0]);
-    fprintf(stderr, "At least one fragcounts and one contigcounts are needed.\n");
-    fprintf(stderr, "          -af | -tf        fragcounts\n");
-    fprintf(stderr, "          -ac | -dc | -co  contigcounts \n");
-    fprintf(stderr, "Dumping is probably only useful with exactly one frag and\n");
-    fprintf(stderr, "one contig, but I'll let you do it with any number.\n");
-    exit(1);
-  }
-  if ((AF == 0L) && (TF == 0L)) {
-    fprintf(stderr, "ERROR - need at least one of -af, -tf\n");
-    exit(1);
-  }
-  if ((AC == 0L) && (DC == 0L) && (CO == 0L)) {
-    fprintf(stderr, "ERROR - need at least one of -ac, -dc, -co\n");
-    exit(1);
-  }
-
-  //  Check mersizes.
-  //
-  uint32  merSize = 0;
-  uint32  ms[5] = { 0 };
-
-  if (AF)  merSize = ms[0] = AF->merSize();
-  if (TF)  merSize = ms[1] = TF->merSize();
-  if (AC)  merSize = ms[2] = AC->merSize();
-  if (DC)  merSize = ms[3] = DC->merSize();
-  if (CO)  merSize = ms[4] = CO->merSize();
-
-  bool  differ = false;
-
-  if ((ms[0] > 0) && (ms[0] != merSize))  differ = true;
-  if ((ms[1] > 0) && (ms[1] != merSize))  differ = true;
-  if ((ms[2] > 0) && (ms[2] != merSize))  differ = true;
-  if ((ms[3] > 0) && (ms[3] != merSize))  differ = true;
-  if ((ms[4] > 0) && (ms[4] != merSize))  differ = true;
-  
-  if (differ) {
-    fprintf(stderr, "error:  mer size differ.\n");
-    fprintf(stderr, "        AF - "uint32FMT"\n", ms[0]);
-    fprintf(stderr, "        TF - "uint32FMT"\n", ms[1]);
-    fprintf(stderr, "        AC - "uint32FMT"\n", ms[2]);
-    fprintf(stderr, "        DC - "uint32FMT"\n", ms[3]);
-    fprintf(stderr, "        CO - "uint32FMT"\n", ms[4]);
-    exit(1);
-  }
-
-  if (dumpFlag) {
-    errno = 0;
-    dumpSCZF = fopen(dumpSCZFname, "w");
-    dumpMCZF = fopen(dumpMCZFname, "w");
-    dumpMCSF = fopen(dumpMCSFname, "w");
-    dumpMCMF = fopen(dumpMCMFname, "w");
-    if (errno)
-      fprintf(stderr, "Failed to open the dump files: %s\n", strerror(errno)), exit(1);
-  }
-
-  uint32   AFvsAC[NUMCATEGORIES][NUMCATEGORIES];
-  uint32   AFvsDC[NUMCATEGORIES][NUMCATEGORIES];
-  uint32   AFvsCO[NUMCATEGORIES][NUMCATEGORIES];
-  uint32   TFvsAC[NUMCATEGORIES][NUMCATEGORIES];
-  uint32   TFvsDC[NUMCATEGORIES][NUMCATEGORIES];
-  uint32   TFvsCO[NUMCATEGORIES][NUMCATEGORIES];
-  for (uint32 i=0; i<NUMCATEGORIES; i++)
-    for (uint32 j=0; j<NUMCATEGORIES; j++) {
-      AFvsAC[i][j] = 0;
-      AFvsDC[i][j] = 0;
-      AFvsCO[i][j] = 0;
-      TFvsAC[i][j] = 0;
-      TFvsDC[i][j] = 0;
-      TFvsCO[i][j] = 0;
-    }
-
-  //  The default constructor for kMer sets the mer to size 0, all A.
-  //  We need it to be the proper size, and all T.
-  kMer   minmer(merSize);
-
-  //  Don't care what we pick, as long as it's a mer in the set.
-  //
-  if (AF && AF->validMer())  minmer = AF->theFMer();
-  if (TF && TF->validMer())  minmer = TF->theFMer();
-  if (AC && AC->validMer())  minmer = AC->theFMer();
-  if (DC && DC->validMer())  minmer = DC->theFMer();
-  if (CO && CO->validMer())  minmer = CO->theFMer();
-
-  speedCounter *C = new speedCounter(" Examining: %7.2f Mmers -- %5.2f Mmers/second\r", 1000000.0, 0x1fffff, beVerbose);
-
-  bool  morestuff = true;
-  while (morestuff) {
-
-    //  Find any mer in our set
-    if (AF && AF->validMer())  minmer = AF->theFMer();
-    if (TF && TF->validMer())  minmer = TF->theFMer();
-    if (AC && AC->validMer())  minmer = AC->theFMer();
-    if (DC && DC->validMer())  minmer = DC->theFMer();
-    if (CO && CO->validMer())  minmer = CO->theFMer();
-
-    //  Find the smallest mer in our set
-    if (AF && AF->validMer() && (AF->theFMer() < minmer))  minmer = AF->theFMer();
-    if (TF && TF->validMer() && (TF->theFMer() < minmer))  minmer = TF->theFMer();
-    if (AC && AC->validMer() && (AC->theFMer() < minmer))  minmer = AC->theFMer();
-    if (DC && DC->validMer() && (DC->theFMer() < minmer))  minmer = DC->theFMer();
-    if (CO && CO->validMer() && (CO->theFMer() < minmer))  minmer = CO->theFMer();
-
-    //  We need to do up to six comparisons here.
-    if (AF && AC)   compare(AF, AC, minmer, AFmode, AFvsAC);
-    if (AF && DC)   compare(AF, DC, minmer, AFmode, AFvsDC);
-    if (AF && CO)   compare(AF, CO, minmer, AFmode, AFvsCO);
-    if (TF && AC)   compare(TF, AC, minmer, TFmode, TFvsAC);
-    if (TF && DC)   compare(TF, DC, minmer, TFmode, TFvsDC);
-    if (TF && CO)   compare(TF, CO, minmer, TFmode, TFvsCO);
-
-    C->tick();
-#if 0
-    if (C->tick()) {
-      char stringjunk[256];
-      fprintf(stderr, "\nMM %s\n", minmer.merToString(stringjunk));
-      if (AF) fprintf(stderr, "AF %s\n", AF->theFMer().merToString(stringjunk));
-      if (TF) fprintf(stderr, "TF %s\n", TF->theFMer().merToString(stringjunk));
-      if (AC) fprintf(stderr, "AC %s\n", AC->theFMer().merToString(stringjunk));
-      if (DC) fprintf(stderr, "DC %s\n", DC->theFMer().merToString(stringjunk));
-      if (CO) fprintf(stderr, "CO %s\n", CO->theFMer().merToString(stringjunk));
-    }
-#endif
-
-    //  Advance to the next mer, if we were just used
-    morestuff = false;
-    if ((AF) && (AF->theFMer() == minmer))   morestuff |= AF->nextMer();
-    if ((TF) && (TF->theFMer() == minmer))   morestuff |= TF->nextMer();
-    if ((AC) && (AC->theFMer() == minmer))   morestuff |= AC->nextMer();
-    if ((DC) && (DC->theFMer() == minmer))   morestuff |= DC->nextMer();
-    if ((CO) && (CO->theFMer() == minmer))   morestuff |= CO->nextMer();
-  }
-
-  delete C;
-
-  //  output
-
-  if ((AF) && (AC))   output("all frags vs all contigs",          AFmode, AFvsAC);
-  if ((AF) && (DC))   output("all frags vs deg. contigs",         AFmode, AFvsDC);
-  if ((AF) && (CO))   output("all frags vs non-deg. contigs",     AFmode, AFvsCO);
-  if ((TF) && (AC))   output("trimmed frags vs all contigs",      TFmode, TFvsAC);
-  if ((TF) && (DC))   output("trimmed frags vs deg. contigs",     TFmode, TFvsDC);
-  if ((TF) && (CO))   output("trimmed frags vs non-deg. contigs", TFmode, TFvsCO);
-
-  delete AF;
-  delete TF;
-  delete AC;
-  delete DC;
-  delete CO;
-}
diff --git a/libkmer/kmer-mask.C b/meryl/kmer-mask.C
similarity index 100%
rename from libkmer/kmer-mask.C
rename to meryl/kmer-mask.C
diff --git a/meryl/m-heap.H b/meryl/m-heap.H
deleted file mode 100644
index 3202450..0000000
--- a/meryl/m-heap.H
+++ /dev/null
@@ -1,152 +0,0 @@
-#ifndef M_HEAP_H
-#define M_HEAP_H
-
-#include "util++.H"
-#include "bio++.H"
-
-//
-//  This is a bit packed heap, derived from bitPackedHeap.  It is
-//  customized to decode a kmer from a merStream, given the location
-//  of the kmer in the stream.  This kmer is used for the value of the
-//  data item in the heap, instead of the value stored in the heap.
-//
-
-class bitPackedMerHeap {
-public:
-  bitPackedMerHeap(seqStore *SS, uint32 width, uint64 size=16) {
-    _array    = new bitPackedArray(width, size);
-    _array->set(0, 0);
-    _lastVal  = 0;
-    _mers     = SS;
-  };
-
-  ~bitPackedMerHeap() {
-    delete _array;
-  };
-
-  //  Get the mer with index idx in the merStream
-  //
-  kMer const  &getMer(uint64 idx) {
-    _mers->setIterationStart(idx);
-    _mers->nextMer();
-    if (_mers->theRMer() < _mers->theFMer())
-      return(_mers->theRMer());
-    return(_mers->theFMer());
-  }
-
-  uint64       get(kMer &mer) {
-    uint64  pos = ~uint64ZERO;
-
-    if (_lastVal == 0)
-      return(pos);
-
-    pos = _array->get(0);
-    mer = getMer(pos);
-
-    if (--_lastVal == 0)
-      return(pos);
-
-    //  Rebalance the heap
-
-    uint64  tval = _array->get(_lastVal);
-    kMer    tmer;
-
-    _array->set(0, tval);
-
-    uint64  pidx = 0;
-    uint64  pval = tval;
-    kMer    pmer = getMer(pval);
-    uint64  cidx = 1;
-    uint64  cval = 0;  //  set below
-    kMer    cmer;
-
-    while (cidx < _lastVal) {
-      //  Set cval here, so we can first test if cidx is in range.
-      cval = _array->get(cidx);
-      cmer = getMer(cval);
-
-      //  Pick the smallest of the two kids
-      if (cidx+1 < _lastVal) {
-        tval = _array->get(cidx+1);
-        tmer = getMer(tval);
-
-        if (cmer > tmer) {
-          cidx++;
-          cval = tval;
-          cmer = tmer;
-        }
-      }
-
-      if (cmer < pmer) {
-
-        //  Swap p and c
-        _array->set(pidx, cval);
-        _array->set(cidx, pval);
-
-        //  Move down the tree -- pval doesn't change, we moved it into cidx!
-        pidx = cidx;
-
-        cidx = cidx * 2 + 1;
-      } else {
-        cidx = _lastVal;
-      }
-    }
-
-    return(pos);
-  };
-
-  void      add(uint64 value) {
-    uint64  cidx = _lastVal++;
-    uint64  cval = value;
-    kMer    cmer;
-    uint64  pidx = 0;
-    uint64  pval = 0;
-    kMer    pmer;
-    bool    more = true;
-
-    _array->set(cidx, cval);
-
-    if (cidx == 0)
-      return;
-
-    cmer = getMer(cval);
-
-    while (more) {
-      pidx = (cidx-1) / 2;
-      pval = _array->get(pidx);
-      pmer = getMer(pval);
-
-      if (pmer > cmer) {
-
-        //  Swap p and c
-        _array->set(cidx, pval);
-        _array->set(pidx, cval);
-
-        //  Move up the tree -- cval doesn't change, we moved it into pidx!
-        cidx = pidx;
-      } else {
-        more = false;
-      }
-      if (cidx == 0)
-        more = false;
-    }
-  };
-
-  void      dump(void) {
-    for (uint32 i=0; i<_lastVal; i++)
-      fprintf(stderr, "HEAP["uint32FMT"]="uint64FMT"\n", i, _array->get(i));
-  }
-
-  void      clear(void) {
-    _array->clear();
-    _lastVal = 0;
-  };
-
-private:
-  bitPackedArray       *_array;
-  uint64                _lastVal;
-  seqStore             *_mers;
-};
-
-
-#endif  //  M_HEAP_H
diff --git a/meryl/m.C b/meryl/m.C
deleted file mode 100644
index 1167436..0000000
--- a/meryl/m.C
+++ /dev/null
@@ -1,118 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "util++.H"
-#include "bio++.H"
-#include "meryl.H"
-
-#include "m-heap.H"
-
-int
-main(int argc, char **argv) {
-  bool     beVerbose   = false;
-  uint64   merSize     = 20;
-  uint64   memLimit    = 768;
-  char    *inName      = 0L;
-  char    *outName     = 0L;
-
-  int arg=1;
-  while (arg < argc) {
-    if        (strncmp(argv[arg], "-verbose", 2) == 0) {
-      beVerbose = true;
-    } else if (strncmp(argv[arg], "-mersize", 4) == 0) {
-      merSize = strtouint64(argv[++arg], 0L);
-    } else if (strncmp(argv[arg], "-memory", 4) == 0) {
-      memLimit = strtouint64(argv[++arg], 0L) * 1024 * 1024;
-    } else if (strncmp(argv[arg], "-sequence", 2) == 0) {
-      inName = argv[++arg];
-    } else {
-      fprintf(stderr, "unknown option '%s'\n", argv[arg]);
-    }
-    arg++;
-  }
-
-  if (inName == 0L) {
-    fprintf(stderr, "usage: %s [-v] [-m mersize] [-memory Nmb] [-s seq.fasta]\n", argv[0]);
-    exit(1);
-  }
-
-  outName = new char [strlen(inName) + 1];
-  strcpy(outName, inName);
-
-  seqStream  *seqstr = new seqStream(inName);
-  seqStore   *seqsto = new seqStore(outName, seqstr);
-
-  uint64      memUsed = seqsto->loadStoreInCore();
-  uint64      numMers = seqsto->numberOfACGT();
-
-#warning needed exact number of mers here
-
-  fprintf(stderr, "Found "uint64FMT" mers in file of size "uint64FMT"\n", numMers, memUsed);
-
-  if (memUsed > memLimit) {
-    fprintf(stderr, "ERROR:  two-bit encoded sequence file is bigger than allowed memory usage.\n");
-    exit(1);
-  }
-
-  //  Allocate a heap to fill up the rest of space
-
-  //  Allocate a bitPackedHeap to store N merSize*2 integeers.
-  //  N = (memLimit - memUsed) * 8 / (merSize * 2)
-  //
-  //  The bitPackedHeap doesn't care about the maximum size, only
-  //  about the block size.
-  //
-  uint64   pointerWidth = logBaseTwo64(numMers);
-  bitPackedMerHeap  *heap = new bitPackedMerHeap(seqsto, pointerWidth, 8 * 1024);
-
-  speedCounter *S;
-
-  uint64 N = (memLimit - memUsed) * 8 / pointerWidth;
-  uint64 M = 0;
-
-  fprintf(stderr, "Can store "uint64FMT" mer pointers of size "uint64FMT" in the heap.\n", N, pointerWidth);
-
-  kMer mer;
-
-  if (N > numMers)
-    N = numMers;
-
-  //  Initialize the heap with some numbers
-  //
-  S = new speedCounter(" Loading heap: %7.2f Mmers -- %8.1f mers/second\r", 1.0, 0x1ffff, beVerbose);
-  while (M < N) {
-
-#if 0
-    heap->add(M);
-    heap->get(mer);
-    fprintf(stdout, "ADD "uint64FMT" -- %s\n", M, mer.merToString(str));
-#endif
-
-    heap->add(M++);
-    S->tick();
-  }
-  delete S;
-
-  //  Until we run out of mers, write things out of the heap.
-  //
-  S = new speedCounter(" Cycling heap: %7.2f Mmers -- %8.1f Mmers/second\r", 1.0, 0x1fff, beVerbose);
-  while (M < numMers) {
-    heap->add(M++);
-    heap->get(mer);
-    //fprintf(stdout, "GOT "uint64FMT" -- %s\n", M, mer.merToString(str));
-    S->tick();
-  }
-  delete S;
-
-  //  And finally, flush the heap.
-  //
-  S = new speedCounter(" Dumping heap: %7.2f Mmers -- %8.1f Mmers/second\r", 1.0, 0x1fff, beVerbose);
-  uint64 idx = heap->get(mer);
-  while (idx != ~uint64ZERO) {
-    //fprintf(stdout, "OUT "uint64FMT" -- %s\n", idx, mer.merToString(str));
-    idx = heap->get(mer);
-    S->tick();
-  }
-  delete S;
-}
diff --git a/meryl/mapMers-depth.C b/meryl/mapMers-depth.C
index 4a0b8f5..40f6e49 100644
--- a/meryl/mapMers-depth.C
+++ b/meryl/mapMers-depth.C
@@ -8,126 +8,182 @@
 #include "libmeryl.H"
 #include "existDB.H"
 
-#warning this code might not work due to intervalList changes
+//  Three outputs:
+//
+//  1) Number of kmers that span this position.  Count of each kmer is ignored.
+//  2) Count of the kmer that begins at this position.
+//  3) Stats of the counts of the kmers that span this position (e.g., ave, min, max, stddev).
 
 int
 main(int argc, char **argv) {
-  uint32    merSize    = 16;
-  char     *merylFile  = 0L;
-  char     *fastaFile  = 0L;
-  bool      beVerbose  = false;
-  uint32    loCount    = 0;
-  uint32    hiCount    = ~uint32ZERO;
-  uint32    windowsize = 0;
-  uint32    skipsize   = 0;
+  uint32    merSize      = 0;
+  char     *merylFile    = 0L;
+
+  char     *fastaFile    = 0L;
+
+  bool      outputCount  = false;
+  bool      outputDepth  = false;
+  bool      outputStats  = false;
 
   int arg=1;
+  int err=0;
   while (arg < argc) {
-    if        (strcmp(argv[arg], "-m") == 0) {
+
+    if      (strcmp(argv[arg], "-m") == 0)
       merSize = strtouint32(argv[++arg], 0L);
-    } else if (strcmp(argv[arg], "-mers") == 0) {
+
+    else if (strcmp(argv[arg], "-mers") == 0)
       merylFile = argv[++arg];
-    } else if (strcmp(argv[arg], "-seq") == 0) {
+
+    else if (strcmp(argv[arg], "-seq") == 0)
       fastaFile = argv[++arg];
-    } else if (strcmp(argv[arg], "-v") == 0) {
-      beVerbose = true;
-    } else if (strcmp(argv[arg], "-lo") == 0) {
-      loCount = strtouint32(argv[++arg], 0L);
-    } else if (strcmp(argv[arg], "-hi") == 0) {
-      hiCount = strtouint32(argv[++arg], 0L);
-    } else if (strcmp(argv[arg], "-w") == 0) {
-      windowsize = strtouint32(argv[++arg], 0L);
-    } else if (strcmp(argv[arg], "-s") == 0) {
-      skipsize = strtouint32(argv[++arg], 0L);
-    } else {
+
+    else if (strcmp(argv[arg], "-count") == 0)
+      outputCount = true;
+    else if (strcmp(argv[arg], "-depth") == 0)
+      outputDepth = true;
+    else if (strcmp(argv[arg], "-stats") == 0)
+      outputStats = true;
+
+    else {
       fprintf(stderr, "unknown option '%s'\n", argv[arg]);
+      err++;
     }
+
     arg++;
   }
 
-  if ((merylFile == 0L) || (fastaFile == 0L)) {
-    fprintf(stderr, "usage: %s -m mersize -mers mers -seq fasta > output\n", argv[0]);
+  if (merSize == 0)
+    err++;
+  if (fastaFile == 0L)
+    err++;
+  if (merylFile == 0L)
+    err++;
+  if (outputCount + outputDepth + outputStats != 1)
+    err++;
+
+  if (err) {
+    fprintf(stderr, "usage: %s -mers MERYL -m MERSIZE -seq IN.FASTA [-count | -depth | -stats] > output\n", argv[0]);
+    fprintf(stderr, "\n");
+    fprintf(stderr, "For sequence ordinal 's' and position in that sequence 'p':\n");
+    fprintf(stderr, "\n");
+    fprintf(stderr, "  -count   - report the count (c) of the single kmer that starts at position (p).\n");
+    fprintf(stderr, "             Format: 's p c'\n");
+    fprintf(stderr, "  -depth   - report the number (n) of kmers that span position (p).  Format: 's p n'\n");
+    fprintf(stderr, "  -stats   - report the min (m), max (M), ave (a) count of all mers that span\n");
+    fprintf(stderr, "             position (p).  Format: 's p m M a t n'\n");
+    fprintf(stderr, "             (also reports total count (t) and number of kmers (n))\n");
+    fprintf(stderr, "\n");
+
+    if (merSize == 0)
+      fprintf(stderr, "ERROR:  No mer size (-m) suppled.\n");
+    if (fastaFile == 0L)
+      fprintf(stderr, "ERROR:  No fasta input (-seq) suppled.\n");
+    if (merylFile == 0L)
+      fprintf(stderr, "ERROR:  No meryl database (-mers) suppled.\n");
+    if (outputCount + outputDepth + outputStats != 1)
+      fprintf(stderr, "ERROR:  Exactly one of -count, -depth and -stats may be supplied.\n");
+
     exit(1);
   }
 
-  existDB       *E = new existDB(merylFile, merSize, existDBcounts | existDBcompressCounts | existDBcompressBuckets, loCount, hiCount);
+  //  Open the input sequences
+
   seqCache      *F = new seqCache(fastaFile);
 
+  //  Load kmer counts from a meryl database.  existDBcompressBuckets is broken.
+
+  existDB       *E = new existDB(merylFile, merSize, existDBcounts | existDBcompressCounts, 0, UINT32_MAX);
+
+  //  For each sequence...
+
   for (uint32 Sid=0; Sid < F->getNumberOfSequences(); Sid++) {
     seqInCore  *S  = F->getSequenceInCore(Sid);
     merStream  *MS = new merStream(new kMerBuilder(merSize),
                                    new seqStream(S->sequence(), S->sequenceLength()),
                                    true, true);
 
-    uint32                         idlen = 0;
-    intervalDepthRegions<uint64>  *id    = new intervalDepthRegions<uint64> [S->sequenceLength() * 2 + 2];
+    //  Build a lists of the min, max and total count at each position.
 
-    while (MS->nextMer()) {
-      int32   cnt = (int32)E->count(MS->theFMer()) + (int32)E->count(MS->theRMer());
-
-      //  Old intervalDepth was to add 'cnt' in the first and subtract 'cnt' in the second.
-      //  Then to use the 'ct' field below.
-      //  New intervalDepth is the same, but uses the value field.
-      //  Count is now the number of intervals that are represented in this block.
-
-      id[idlen].pos     = MS->thePositionInSequence();
-      id[idlen].change  = cnt;
-      id[idlen].open    = true;
-      idlen++;
-
-      id[idlen].pos     = MS->thePositionInSequence() + merSize;
-      id[idlen].change  = cnt;
-      id[idlen].open    = false;
-      idlen++;
+    uint32  *mincount = new uint32 [S->sequenceLength() + 1];
+    uint32  *maxcount = new uint32 [S->sequenceLength() + 1];
+    uint32  *totcount = new uint32 [S->sequenceLength() + 1];
+    uint32  *numcount = new uint32 [S->sequenceLength() + 1];
+
+    for (uint32 xx=0; xx<S->sequenceLength() + 1; xx++) {
+      mincount[xx] = UINT32_MAX;
+      maxcount[xx] = 0;
+      totcount[xx] = 0;
+      numcount[xx] = 0;
     }
 
-    intervalList<uint64>  ID(id, idlen);
-    uint32                x = 0;
+    //  Scan the sequence, find the count.
 
-    uint32                len = S->sequenceLength();
+    while (MS->nextMer()) {
+      uint32   pos = MS->thePositionInSequence();
+      uint32   cnt = E->count(MS->theFMer()) + E->count(MS->theRMer());
+
+      if (cnt == 0)
+        //  Mer doesn't exist in the database.
+        continue;
 
-    //  Default case, report un-averaged depth at every single location.
-    //
-    if ((windowsize == 0) && (skipsize == 0)) {
-      for (uint32 i=0; i < ID.numberOfIntervals(); i++) {
-        for (; x < ID.lo(i); x++)
-          fprintf(stdout, uint32FMTW(7)"\t"uint32FMTW(6)"\n", x, 0);
-        for (; x < ID.hi(i); x++)
-          fprintf(stdout, uint32FMTW(7)"\t"uint32FMTW(6)"\n", x, ID.value(i));
-      }
-      for (; x < len; x++)
-        fprintf(stdout, uint32FMTW(7)"\t"uint32FMTW(6)"\n", x, 0);
+      if (outputCount)
+        totcount[pos] = cnt;
 
-    } else {
-      uint32  *depth = new uint32 [len];
-      for (x=0; x < len; x++)
-        depth[x] = 0;
+      if (outputDepth)
+        for (uint32 xx=pos; xx<pos+merSize; xx++)
+          numcount[xx]++;
 
-      for (uint32 i=0; i < ID.numberOfIntervals(); i++)
-        for (x=ID.lo(i); x < ID.hi(i); x++)
-          depth[x] = ID.count(i);
+      if (outputStats)
+        for (uint32 xx=pos; xx<pos+merSize; xx++) {
+          totcount[xx] += cnt;
+          numcount[xx]++;
 
-      uint32   avedepth = 0;
+          if (cnt < mincount[xx])
+            mincount[xx] = cnt;
 
-      for (x=0; x < windowsize; x++)
-        avedepth += depth[x];
+          if (maxcount[xx] < cnt)
+            maxcount[xx] = cnt;
+        }
+    }
 
-      while (x < len) {
-        uint32  avepos = (x - 1) - (windowsize - 1) / 2;
-        if ((avepos % skipsize) == 0)
-          fprintf(stdout, uint32FMT"\t%.4f\n",
-                  avepos,
-                  (double)avedepth / (double)windowsize);
+    //  If there is no coverage, the min is still set to UINT32_MAX.
 
-        avedepth = avedepth + depth[x] - depth[x-windowsize];
+    for (uint32 x=0; x < S->sequenceLength(); x++)
+      if (numcount[x] == 0)
+        mincount[x] = 0;
 
-        x++;
-      }
+    //  Report the single kmer count?
+
+    if (outputCount) {
+      for (uint32 x=0; x < S->sequenceLength(); x++)
+        fprintf(stdout, "%u\t%u\t%u\n", Sid, x, totcount[x]);
+    }
+
+    //  Report the depth?
+
+    if (outputDepth) {
+      for (uint32 x=0; x < S->sequenceLength(); x++)
+        fprintf(stdout, "%u\t%u\t%u\n", Sid, x, numcount[x]);
+    }
 
-      delete [] depth;
+    //  Report the min/max/ave count?
+
+    if (outputStats) {
+      for (uint32 x=0; x < S->sequenceLength(); x++)
+        fprintf(stdout, "%u\t%u\t%u\t%u\t%u\t%u\t%u\n",
+                Sid, x,
+                mincount[x],
+                maxcount[x],
+                (numcount[x] > 0) ? totcount[x] / numcount[x] : 0,
+                totcount[x],
+                numcount[x]);
     }
 
-    delete [] id;
+    delete [] mincount;
+    delete [] maxcount;
+    delete [] totcount;
+    delete [] numcount;
 
     delete MS;
     delete S;
diff --git a/meryl/maskMers.C b/meryl/maskMers.C
index a717054..fb27172 100644
--- a/meryl/maskMers.C
+++ b/meryl/maskMers.C
@@ -11,6 +11,13 @@
 
 #define MAX_COVERAGE 51
 
+//  Wed May 20 02:39:41 EDT 2015
+//
+//  This appears to be an analysis of the repeat/unique kmer content of a genome.  From 2008.
+//
+//  The 'mate rescue' appears to be measuring if mates from a library of some size would
+//  anchor a repeat to a unique.  I think.
+
 class mateRescueData {
 public:
   mateRescueData() {
diff --git a/meryl/testPositionBias.C b/meryl/testPositionBias.C
deleted file mode 100644
index b49d8e2..0000000
--- a/meryl/testPositionBias.C
+++ /dev/null
@@ -1,117 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "bio++.H"
-#include "libmeryl.H"
-
-
-uint32 *
-collectCounts(char *name, uint32 base) {
-  merylStreamReader   *A = new merylStreamReader(name);
-  uint32              *C = new uint32 [4*4*4];
-  char                 S[32];
-  uint32               code = 0;
-
-  for (uint32 i=0; i<4*4*4; i++)
-    C[i] = 0;
-
-  while (A->nextMer()) {
-    A->theFMer().merToString(S);
-
-    code   = 0;
-    code  |= letterToBits[S[base]];
-    code <<= 2;
-    code  |= letterToBits[S[base+1]];
-    code <<= 2;
-    code  |= letterToBits[S[base+2]];
-
-    C[code] += A->theCount();
-
-    kMer R = A->theFMer();
-    R.reverseComplement();
-    R.merToString(S);
-
-    code   = 0;
-    code  |= letterToBits[S[base]];
-    code <<= 2;
-    code  |= letterToBits[S[base+1]];
-    code <<= 2;
-    code  |= letterToBits[S[base+2]];
-
-    C[code] += A->theCount();
-  }
-
-  delete A;
-
-  return(C);
-}
-
-
-void
-showBias(uint32 base=5) {
-  uint32  *A = collectCounts("CNPT3", base);
-  uint32  *B = collectCounts("25.errorless", base);
-  uint32  *C = collectCounts("25.errorless.simulated", base);
-
-  for (uint32 i=0; i<4*4*4; i++) {
-    double   bp = 0.0;
-    double   cp = 0.0;
-
-    if (A[i] > 0) {
-      bp = (double)B[i] / (double)A[i];
-      cp = (double)C[i] / (double)A[i];
-    }
-
-    fprintf(stdout, "%c%c%c "uint32FMTW(3)" A "uint32FMTW(6)" B "uint32FMTW(6)" %.5f C "uint32FMTW(6)" %.5f\n",
-            bitsToLetter[(i >> 4) & 0x00000003],
-            bitsToLetter[(i >> 2) & 0x00000003],
-            bitsToLetter[(i >> 0) & 0x00000003],
-            i,
-            A[i],
-            B[i],
-            bp,
-            C[i],
-            cp);
-  }
-}
-
-
-double
-computeRMSD(uint32 base) {
-  uint32  *A = collectCounts("CNPT3", base);
-  uint32  *B = collectCounts("25.errorless", base);
-  uint32  *C = collectCounts("25.errorless.simulated", base);
-
-  double rmsd = 0;
-
-  for (uint32 i=0; i<4*4*4; i++) {
-    double   bp = 0.0;
-    double   cp = 0.0;
-
-    if (A[i] > 0) {
-      bp = (double)B[i] / (double)A[i];
-      cp = (double)C[i] / (double)A[i];
-    }
-
-    rmsd += (bp - cp) * (bp - cp);
-  }
-
-  rmsd /= 4*4*4;
-
-  return(sqrt(rmsd));
-}
-
-
-
-
-
-int
-main(int argc, char **argv) {
-
-  showBias(5);
-
-  //for (uint32 i=0; i<23; i++)
-  //  fprintf(stdout, "rmsd "uint32FMTW(2)" %f\n", i, computeRMSD(i));
-}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/kmer-tools.git



More information about the debian-med-commit mailing list