about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--analyzer/pamfind.c91
-rw-r--r--buildtools/debian/README34
-rw-r--r--converter/other/pamtopng.c2
-rw-r--r--converter/other/pngx.c20
-rw-r--r--converter/other/pnmtopalm/palmtopnm.c28
-rw-r--r--converter/other/pnmtopalm/pnmtopalm.c279
-rw-r--r--converter/other/pstopnm.c55
-rw-r--r--converter/pbm/pbmtolps.c10
-rw-r--r--doc/HISTORY26
-rw-r--r--doc/TESTS35
-rw-r--r--doc/patent_summary9
-rw-r--r--editor/pnmcrop.c7
-rw-r--r--generator/pbmpage.c392
-rw-r--r--generator/pbmtext.c6
-rw-r--r--generator/ppmforge.c205
-rw-r--r--lib/pbm.h32
-rw-r--r--lib/pnm.h11
-rw-r--r--lib/util/runlength.c18
-rw-r--r--lib/util/shhopt.c2
-rw-r--r--lib/util/shhopt.h20
-rwxr-xr-xtest/Execute-Tests7
-rw-r--r--test/Test-Order8
-rwxr-xr-xtest/bmp-quant-roundtrip.test2
-rwxr-xr-xtest/g3-roundtrip.test2
-rw-r--r--test/pad-crop-roundtrip.ok2
-rwxr-xr-xtest/pad-crop-roundtrip.test15
-rw-r--r--test/pamditherbw.ok24
-rwxr-xr-xtest/pamditherbw.test52
-rw-r--r--test/pamfile.ok7
-rwxr-xr-xtest/pamfile.test16
-rw-r--r--test/pamfind.ok178
-rwxr-xr-xtest/pamfind.test11
-rw-r--r--test/pamgauss.ok10
-rwxr-xr-xtest/pamgauss.test21
-rw-r--r--test/pamhue-roundtrip.ok10
-rwxr-xr-xtest/pamhue-roundtrip.test19
-rw-r--r--test/pamhue.ok25
-rwxr-xr-xtest/pamhue.test10
-rw-r--r--test/pamscale-filters3.ok1
-rwxr-xr-xtest/pamscale-filters3.test3
-rw-r--r--test/pamseq.ok6
-rwxr-xr-xtest/pamseq.test19
-rw-r--r--test/pamsumm.ok7
-rwxr-xr-xtest/pamsumm.test16
-rwxr-xr-xtest/pamtable.test2
-rwxr-xr-xtest/pbm-misc-converters.test2
-rw-r--r--test/pbmclean.ok13
-rwxr-xr-xtest/pbmclean.test25
-rw-r--r--test/pbmmake.ok21
-rwxr-xr-xtest/pbmmake.test23
-rw-r--r--test/pbmpage.ok6
-rwxr-xr-xtest/pbmpage.test19
-rw-r--r--test/pbmupc.ok11
-rwxr-xr-xtest/pbmupc.test18
-rwxr-xr-xtest/pdb-roundtrip.test2
-rw-r--r--test/pgmhist.ok22
-rwxr-xr-xtest/pgmhist.test25
-rw-r--r--test/pgmmake.ok10
-rwxr-xr-xtest/pgmmake.test19
-rw-r--r--test/pgmramp.ok9
-rwxr-xr-xtest/pgmramp.test19
-rw-r--r--test/pnmcrop-blank.ok130
-rwxr-xr-xtest/pnmcrop-blank.test55
-rw-r--r--test/pnmcrop1.ok103
-rwxr-xr-xtest/pnmcrop1.test75
-rw-r--r--test/pnmcrop2.ok29
-rwxr-xr-xtest/pnmcrop2.test55
-rw-r--r--test/pnmcrop3.ok90
-rwxr-xr-xtest/pnmcrop3.test71
-rw-r--r--test/pnmpsnr.ok7
-rwxr-xr-xtest/pnmpsnr.test21
-rwxr-xr-xtest/pnmquantall.test2
-rw-r--r--test/ppmforge-parameters.ok10
-rwxr-xr-xtest/ppmforge-parameters.test29
-rw-r--r--test/ppmhist.ok6
-rwxr-xr-xtest/ppmhist.test18
-rw-r--r--test/ppmmake.ok13
-rwxr-xr-xtest/ppmmake.test20
-rw-r--r--test/ppmpat.ok33
-rwxr-xr-xtest/ppmpat.test55
-rwxr-xr-xtest/sgi-roundtrip.test2
-rw-r--r--version.mk4
82 files changed, 2281 insertions, 546 deletions
diff --git a/analyzer/pamfind.c b/analyzer/pamfind.c
index 860c01ff..acfb5ded 100644
--- a/analyzer/pamfind.c
+++ b/analyzer/pamfind.c
@@ -1,4 +1,6 @@
+#include <assert.h>
 #include <nstring.h>
+
 #include <pam.h>
 
 #include "pm_c_util.h"
@@ -9,11 +11,13 @@
 typedef struct {
     unsigned int * target;
     unsigned int   targetDepth;
+    unsigned int   machine;
     const char *   color;  /* NULL means not specified */
     const char *   inputFileName;
 } CmdLineInfo;
 
 
+
 static CmdLineInfo
 parsedCommandLine(int                 argc,
                   const char ** const argv) {
@@ -33,9 +37,10 @@ parsedCommandLine(int                 argc,
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0,   "target",  OPT_STRINGLIST, &target,         &targetSpec, 0);
-    OPTENT3(0,   "color",   OPT_STRING,     &cmdLine.color,  &colorSpec,  0);
-    OPTENT3(0,  0,          OPT_END,        NULL,            NULL,        0);
+    OPTENT3(0,   "target",  OPT_STRINGLIST, &target,          &targetSpec, 0);
+    OPTENT3(0,   "color",   OPT_STRING,     &cmdLine.color,   &colorSpec,  0);
+    OPTENT3(0,   "machine", OPT_FLAG,       NULL,       &cmdLine.machine,  0);
+    OPTENT3(0,  0,          OPT_END,        NULL,             NULL,        0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
@@ -43,35 +48,37 @@ parsedCommandLine(int                 argc,
 
     pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
 
-    if (targetSpec) {
-        if (colorSpec)
-            pm_error("You cannot specify both -target and -color");
-        else {
-            unsigned int i;
+    if (targetSpec + colorSpec > 1)
+        pm_error("You cannot specify both -target and -color");
 
-            cmdLine.color = NULL;
+    else if (targetSpec + colorSpec == 0)
+        pm_error("You must specify either -target or -color");
 
-            cmdLine.target = NULL;  /* initial value */
+    else if (targetSpec) {
+        unsigned int i;
 
-            for (i = 0, cmdLine.targetDepth = 0; target[i]; ++i) {
-                unsigned int sampleVal;
-                const char * error;
+        cmdLine.color = NULL;
 
-                pm_string_to_uint(target[i], &sampleVal, &error);
-                if (error) {
-                    pm_error("Invalid sample value in -target option: '%s'.  "
-                             "%s", target[i], error);
-                }
+        cmdLine.target = NULL;  /* initial value */
 
-                REALLOCARRAY(cmdLine.target, i+1);
+        for (i = 0, cmdLine.targetDepth = 0; target[i]; ++i) {
+            unsigned int sampleVal;
+            const char * error;
 
-                cmdLine.target[cmdLine.targetDepth++] = sampleVal;
+            pm_string_to_uint(target[i], &sampleVal, &error);
+            if (error) {
+                pm_error("Invalid sample value in -target option: '%s'.  "
+                         "%s", target[i], error);
             }
 
-            free(target);
+            REALLOCARRAY(cmdLine.target, i+1);
+
+            cmdLine.target[cmdLine.targetDepth++] = sampleVal;
         }
-    } else if (!colorSpec)
-        pm_error("You must specify either -target or -color");
+
+        free(target);
+    } else
+        assert (colorSpec == 1);
 
     if (argc-1 < 1)
         cmdLine.inputFileName = "-";
@@ -161,6 +168,29 @@ printHeader(FILE *       const ofP,
 
 
 
+static unsigned int
+decimalDigitCt(unsigned int const n) {
+/*----------------------------------------------------------------------------
+   Minimum number of digits needed to display 'n' in decimal.
+-----------------------------------------------------------------------------*/
+    unsigned int digitCt;
+
+    if (n == 0)
+        digitCt = 1;
+    else {
+        unsigned int x;
+
+        for (digitCt = 0, x = n; x > 0;) {
+            ++digitCt;
+            x /= 10;
+        }
+        assert(digitCt > 0);
+    }
+    return digitCt;
+}
+
+
+
 static void
 pamfind(FILE *       const ifP,
         struct pam * const inpamP,
@@ -174,8 +204,16 @@ pamfind(FILE *       const ifP,
         tuple   const target   = targetValue(cmdLine, inpamP);
 
         unsigned int row;
-
-        printHeader(ofP, inpamP, target);
+        const char * fmt;
+
+        if (cmdLine.machine) {
+            pm_asprintf(&fmt, "%%0%uu %%0%uu\n",
+                        decimalDigitCt(inpamP->height-1),
+                        decimalDigitCt(inpamP->width-1));
+        } else {
+            printHeader(ofP, inpamP, target);
+            fmt = pm_strdup("(%u, %u)\n");
+        }
 
         for (row = 0; row < inpamP->height; ++row) {
             unsigned int col;
@@ -185,10 +223,11 @@ pamfind(FILE *       const ifP,
             for (col = 0; col < inpamP->width; ++col) {
 
                 if (pnm_tupleequal(inpamP, target, inputRow[col])) {
-                    fprintf(ofP, "(%u, %u)\n", row, col);
+                    fprintf(ofP, fmt, row, col);
                 }
             }
         }
+        pm_strfree(fmt);
         pnm_freepamtuple(target);
         pnm_freepamrow(inputRow);
     }
diff --git a/buildtools/debian/README b/buildtools/debian/README
index 7cefb249..3f74f494 100644
--- a/buildtools/debian/README
+++ b/buildtools/debian/README
@@ -37,17 +37,23 @@ To install Netpbm as a Debian package:
 PREREQUSISITES
 --------------
 
-The following information was taken from the Jessie version (Version 8) of
-Debian, in March 2017.
-
-You don't actually need the current version of any of these.  For example,
-while we list package libjpeg62-dev, the package libjpeg8-dev works fine.
+The following information was taken from the Stretch version (Version 9) of
+Debian, in June 2019.
 
 
 Building
 --------
 
-You need the following Debian packages to build all of Netpbm.
+You need the following Debian packages to build all of Netpbm.  These
+are in addition to what is in the base system.
+
+Build tools:
+
+  gcc
+  make
+  flex
+
+Libraries to link with Netpbm:
 
 You could omit some of these and, in the Netpbm build configuration dialog,
 indicate you don't have them, and the build will simply omit some parts.
@@ -56,20 +62,14 @@ will not build the 'pamx' program.
 
   libjpeg-dev
   libpng-dev
-  libtiff5-dev
+  libtiff-dev
   libx11-dev
   libxml2-dev
   zlib1g-dev
 
+Example:
 
-In addition, you need the following build tools:
-
-  make
-  gcc
-  flex
-  perl
-  pkg-config
-
+  $ apt-get install gcc
 
 
 Running
@@ -95,6 +95,10 @@ be pretty obvious what the problem is when you need the prerequisite package
 and don't have it, so if you don't want to install a prerequisite, it would
 probably be fine to force install Netpbm, ignoring the prerequisites.
 
+There is one part you cannot build with current Debian: 'ppmsvgalib'.  That is
+because Debian does not include the required libsvga library (the last version
+that did was 7).
+
 
 CONFLICTS WITH DEBIAN'S NETPBM
 ------------------------------
diff --git a/converter/other/pamtopng.c b/converter/other/pamtopng.c
index a323844f..68d4055d 100644
--- a/converter/other/pamtopng.c
+++ b/converter/other/pamtopng.c
@@ -921,7 +921,7 @@ pamtopng(FILE *             const ifP,
 
     if (cmdline.interlace) {
         /* Libpng will expect us to provide pixels in interlaced sequence
-           if we write row-by-row, and that is much to difficult, so we
+           if we write row-by-row, and that is much too difficult, so we
            do whole-image-at-once and let Libpng do the work.
         */
         writeRasterWholeImg(&pam, pngxP, pnmBitDepth);
diff --git a/converter/other/pngx.c b/converter/other/pngx.c
index 4bb09421..8295b979 100644
--- a/converter/other/pngx.c
+++ b/converter/other/pngx.c
@@ -416,6 +416,26 @@ void
 pngx_setFilter(struct pngx * const pngxP,
                int           const filterSet) {
 
+    /* This sets the allowed filters in the compressor.  The filters, and thus
+       the interpretation of 'filterSet', is specific to a filter method (aka
+       filter type), which you set with pngx_setIhdr.  There is only one
+       filter method defined today, though (PNG_FILTER_TYPE_BASE).
+
+       For filter method Base, 'filterSet' is the OR of the following masks,
+       each one allowing the compressor to use one filter.  Not that  the
+       compressor decides on a row-by-row basis what filter to use.
+
+         PNG_FILTER_NONE
+         PNG_FILTER_SUB
+         PNG_FILTER_UP
+         PNG_FILTER_AVG
+         PNG_FILTER_PAETH
+
+       There are also
+
+         PNG_NO_FILTERS
+         PNG_ALL_FILTERS
+    */
     png_set_filter(pngxP->png_ptr, 0, filterSet);
 }
 
diff --git a/converter/other/pnmtopalm/palmtopnm.c b/converter/other/pnmtopalm/palmtopnm.c
index b3c0321a..445f7839 100644
--- a/converter/other/pnmtopalm/palmtopnm.c
+++ b/converter/other/pnmtopalm/palmtopnm.c
@@ -798,10 +798,12 @@ readRleRow(FILE *          const ifP,
         if (incount == 0)
             pm_error("Invalid (zero) count in RLE compression.");
         if (j + incount > bytesPerRow)
-            pm_error("Bytes in RLE compressed row exceed bytes per row.  "
-                     "Bytes per row is %u.  A run length of %u bytes "
-                     "pushes the bytes in this row up to %u bytes (and then "
-                     "we gave up).", bytesPerRow, incount, j + incount);
+            pm_error("Invalid Palm image input.  Header says %u bytes "
+                     "per row after uncompressing from RLE, "
+                     "but we encountered a row with a run length of %u bytes "
+                     "that pushes the bytes in the row up to %u bytes "
+                     "(and we didn't look at the rest of the row)",
+                     bytesPerRow, incount, j + incount);
         pm_readcharu(ifP, &inval);
         memset(palmrow + j, inval, incount);
         j += incount;
@@ -848,10 +850,11 @@ readPackBitsRow16(FILE *          const ifP,
             j += nonrunlength;
         }
         if (j > bytesPerRow)
-            pm_error("Bytes in PackBits compressed row exceed bytes per row.  "
-                     "Bytes per row is %u.  "
-                     "The bytes in this row were pushed up to %u bytes "
-                     "(and then we gave up).", bytesPerRow, j);
+            pm_error("Invalid Palm image input.  Header says %u bytes "
+                     "per row after uncompressing from 16-bit Packbits at, "
+                     "but we counted %u bytes in a row, "
+                     "before we stopped processing the row",
+                     bytesPerRow, j);
     }
 }
 
@@ -886,10 +889,11 @@ readPackBitsRow(FILE *          const ifP,
             j += nonrunlength;
         }
         if (j > bytesPerRow)
-            pm_error("Bytes in PackBits compressed row exceed bytes per row.  "
-                     "Bytes per row is %u.  "
-                     "The bytes in this row were pushed up to %u bytes "
-                     "(and then we gave up).", bytesPerRow, j);
+            pm_error("Invalid Palm image input.  Header says %u bytes "
+                     "per row after uncompressing from 8-bit Packbits, "
+                     "but we counted %u bytes in a row, "
+                     "before we stopped processing the row",
+                     bytesPerRow, j);
     }
 }
 
diff --git a/converter/other/pnmtopalm/pnmtopalm.c b/converter/other/pnmtopalm/pnmtopalm.c
index 25c8af2e..4f535d1a 100644
--- a/converter/other/pnmtopalm/pnmtopalm.c
+++ b/converter/other/pnmtopalm/pnmtopalm.c
@@ -74,27 +74,27 @@ parseCommandLine(int argc, const char ** argv, struct CmdlineInfo *cmdlineP) {
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENTRY */
-    OPTENT3(0, "transparent",      OPT_STRING, 
+    OPTENT3(0, "transparent",      OPT_STRING,
             &cmdlineP->transparent, &transSpec, 0);
-    OPTENT3(0, "depth",            OPT_UINT, 
+    OPTENT3(0, "depth",            OPT_UINT,
             &cmdlineP->depth,       &cmdlineP->depthSpec, 0);
-    OPTENT3(0, "maxdepth",         OPT_UINT, 
+    OPTENT3(0, "maxdepth",         OPT_UINT,
             &cmdlineP->maxdepth,    &cmdlineP->maxdepthSpec, 0);
-    OPTENT3(0, "scanline_compression", OPT_FLAG, 
+    OPTENT3(0, "scanline_compression", OPT_FLAG,
             NULL,                   &scanline_compression, 0);
-    OPTENT3(0, "rle_compression",  OPT_FLAG, 
+    OPTENT3(0, "rle_compression",  OPT_FLAG,
             NULL,                   &rle_compression, 0);
-    OPTENT3(0, "packbits_compression", OPT_FLAG, 
+    OPTENT3(0, "packbits_compression", OPT_FLAG,
             NULL,                   &packbits_compression, 0);
-    OPTENT3(0, "verbose",          OPT_FLAG, 
+    OPTENT3(0, "verbose",          OPT_FLAG,
             NULL,                   &cmdlineP->verbose, 0);
-    OPTENT3(0, "colormap",         OPT_FLAG, 
+    OPTENT3(0, "colormap",         OPT_FLAG,
             NULL,                   &cmdlineP->colormap, 0);
-    OPTENT3(0, "offset",           OPT_FLAG, 
+    OPTENT3(0, "offset",           OPT_FLAG,
             NULL,                   &cmdlineP->offset, 0);
-    OPTENT3(0, "density",          OPT_UINT, 
+    OPTENT3(0, "density",          OPT_UINT,
             &cmdlineP->density,     &densitySpec, 0);
-    OPTENT3(0, "withdummy",        OPT_FLAG, 
+    OPTENT3(0, "withdummy",        OPT_FLAG,
             NULL,                   &cmdlineP->withdummy, 0);
 
     opt.opt_table = option_def;
@@ -105,7 +105,7 @@ parseCommandLine(int argc, const char ** argv, struct CmdlineInfo *cmdlineP) {
         /* Uses and sets argc, argv, and some of *cmdline_p and others. */
 
     if (cmdlineP->depthSpec) {
-        if (cmdlineP->depth != 1 && cmdlineP->depth != 2 
+        if (cmdlineP->depth != 1 && cmdlineP->depth != 2
             && cmdlineP->depth != 4 && cmdlineP->depth != 8
             && cmdlineP->depth != 16)
             pm_error("invalid value for -depth: %u.  Valid values are "
@@ -113,14 +113,14 @@ parseCommandLine(int argc, const char ** argv, struct CmdlineInfo *cmdlineP) {
     }
 
     if (cmdlineP->maxdepthSpec) {
-        if (cmdlineP->maxdepth != 1 && cmdlineP->maxdepth != 2 
+        if (cmdlineP->maxdepth != 1 && cmdlineP->maxdepth != 2
             && cmdlineP->maxdepth != 4 && cmdlineP->maxdepth != 8
             && cmdlineP->maxdepth != 16)
             pm_error("invalid value for -maxdepth: %u.  Valid values are "
                      "1, 2, 4, 8, and 16", cmdlineP->maxdepth);
     }
 
-    if (cmdlineP->depthSpec && cmdlineP->maxdepthSpec && 
+    if (cmdlineP->depthSpec && cmdlineP->maxdepthSpec &&
         cmdlineP->depth > cmdlineP->maxdepth)
         pm_error("-depth value (%u) is greater than -maxdepth (%u) value.",
                  cmdlineP->depth, cmdlineP->maxdepth);
@@ -135,7 +135,7 @@ parseCommandLine(int argc, const char ** argv, struct CmdlineInfo *cmdlineP) {
             cmdlineP->density != PALM_DENSITY_TRIPLE &&
             cmdlineP->density != PALM_DENSITY_QUADRUPLE)
             pm_error("Invalid value for -density: %u.  Valid values are "
-                     "%u, %u, %u, %u and %u.", cmdlineP->density, 
+                     "%u, %u, %u, %u and %u.", cmdlineP->density,
                      PALM_DENSITY_LOW, PALM_DENSITY_ONEANDAHALF,
                      PALM_DENSITY_DOUBLE, PALM_DENSITY_TRIPLE,
                      PALM_DENSITY_QUADRUPLE);
@@ -163,11 +163,11 @@ parseCommandLine(int argc, const char ** argv, struct CmdlineInfo *cmdlineP) {
         else
             cmdlineP->compression = COMP_NONE;
     }
-        
+
     if (argc-1 > 1)
         pm_error("This program takes at most 1 argument: the file name.  "
                  "You specified %u", argc-1);
-    else if (argc-1 > 0) 
+    else if (argc-1 > 0)
         cmdlineP->inputFilespec = argv[1];
     else
         cmdlineP->inputFilespec = "-";
@@ -186,16 +186,16 @@ scaleSample(pixval const arg,
 
 
 static void
-determinePalmFormatPgm(xelval               const maxval, 
+determinePalmFormatPgm(xelval               const maxval,
                        bool                 const bppSpecified,
                        unsigned int         const bpp,
                        bool                 const maxBppSpecified,
-                       unsigned int         const maxBpp, 
+                       unsigned int         const maxBpp,
                        bool                 const wantCustomColormap,
                        enum CompressionType const compression,
                        bool                 const verbose,
                        unsigned int *       const bppP) {
-        
+
     /* We can usually handle this one, but may not have enough pixels.  So
        check.
     */
@@ -241,10 +241,10 @@ validateImageAgainstStandardColormap(const Colormap * const colormapP,
         unsigned int col;
 
         for (col = 0; col < cols; ++col) {
-            ColormapEntry const searchTarget = 
+            ColormapEntry const searchTarget =
                 palmcolor_mapEntryColorFmPixel(xels[row][col], maxval, 255);
 
-            ColormapEntry * const foundEntryP = 
+            ColormapEntry * const foundEntryP =
                 (bsearch(&searchTarget,
                          colormapP->color_entries, colormapP->ncolors,
                          sizeof(ColormapEntry), palmcolor_compare_colors));
@@ -261,21 +261,21 @@ validateImageAgainstStandardColormap(const Colormap * const colormapP,
 
 
 static void
-determinePalmFormatPpm(unsigned int         const cols, 
-                       unsigned int         const rows, 
-                       xelval               const maxval, 
+determinePalmFormatPpm(unsigned int         const cols,
+                       unsigned int         const rows,
+                       xelval               const maxval,
                        xel **               const xels,
                        bool                 const bppSpecified,
                        unsigned int         const bpp,
                        bool                 const maxBppSpecified,
-                       unsigned int         const maxBpp, 
+                       unsigned int         const maxBpp,
                        bool                 const wantCustomColormap,
                        enum CompressionType const compression,
                        bool                 const verbose,
-                       unsigned int *       const bppP, 
-                       bool *               const directColorP, 
+                       unsigned int *       const bppP,
+                       bool *               const directColorP,
                        Colormap **          const colormapPP) {
-            
+
     /* We don't attempt to identify PPM files that are actually
        monochrome.  So there are two options here: either 8-bit with a
        colormap, either the standard one or a custom one, or 16-bit direct
@@ -287,7 +287,7 @@ determinePalmFormatPpm(unsigned int         const cols,
        palmcolor8.map file that comes with Netpbm to avoid this).  We try
        for colormapped first, since it works on more PalmOS devices.
     */
-    if ((bppSpecified && bpp == 16) || 
+    if ((bppSpecified && bpp == 16) ||
         (!bppSpecified && maxBppSpecified && maxBpp == 16)) {
         /* we do the 16-bit direct color */
         *directColorP = TRUE;
@@ -296,7 +296,7 @@ determinePalmFormatPpm(unsigned int         const cols,
     } else if (!wantCustomColormap) {
         /* colormapped with the standard colormap */
         Colormap * colormapP;
-            
+
         if ((bppSpecified && bpp != 8) || (maxBppSpecified && maxBpp < 8))
             pm_error("Must use depth of 8 for color Palm Bitmap without "
                      "custom color table.");
@@ -311,7 +311,7 @@ determinePalmFormatPpm(unsigned int         const cols,
             pm_message("Output is color with default colormap at 8 bpp");
     } else {
         /* colormapped with a custom colormap */
-        *colormapPP = 
+        *colormapPP =
             palmcolor_build_custom_8bit_colormap(xels, rows, cols, maxval);
         for (*bppP = 1; (1 << *bppP) < (*colormapPP)->ncolors; *bppP *= 2);
         if (bppSpecified) {
@@ -337,7 +337,7 @@ determinePalmFormatPpm(unsigned int         const cols,
         *directColorP = FALSE;
         if (verbose)
             pm_message("Output is color with custom colormap "
-                       "with %u colors at %u bpp", 
+                       "with %u colors at %u bpp",
                        (*colormapPP)->ncolors, *bppP);
     }
 }
@@ -345,20 +345,20 @@ determinePalmFormatPpm(unsigned int         const cols,
 
 
 static void
-determinePalmFormat(unsigned int         const cols, 
-                    unsigned int         const rows, 
-                    xelval               const maxval, 
-                    int                  const format, 
+determinePalmFormat(unsigned int         const cols,
+                    unsigned int         const rows,
+                    xelval               const maxval,
+                    int                  const format,
                     xel **               const xels,
                     bool                 const bppSpecified,
                     unsigned int         const bpp,
                     bool                 const maxBppSpecified,
-                    unsigned int         const maxBpp, 
+                    unsigned int         const maxBpp,
                     bool                 const wantCustomColormap,
                     enum CompressionType const compression,
                     bool                 const verbose,
-                    unsigned int *       const bppP, 
-                    bool *               const directColorP, 
+                    unsigned int *       const bppP,
+                    bool *               const directColorP,
                     Colormap **          const colormapPP) {
 /*----------------------------------------------------------------------------
    Determine what kind of Palm output file to make.
@@ -414,9 +414,9 @@ determinePalmFormat(unsigned int         const cols,
 
 
 
-static const char * 
+static const char *
 formatName(int const format) {
-    
+
     const char * retval;
 
     switch(PNM_FORMAT_TYPE(format)) {
@@ -428,22 +428,22 @@ formatName(int const format) {
     return retval;
 }
 
-        
+
 
 static void
-findTransparentColor(const char *   const colorSpec, 
+findTransparentColor(const char *   const colorSpec,
                      pixval         const newMaxval,
-                     bool           const directColor, 
-                     pixval         const maxval, 
+                     bool           const directColor,
+                     pixval         const maxval,
                      Colormap *     const colormapP,
-                     xel *          const transcolorP, 
+                     xel *          const transcolorP,
                      unsigned int * const transindexP) {
 
     *transcolorP = ppm_parsecolor(colorSpec, maxval);
     if (!directColor) {
-        ColormapEntry const searchTarget = 
+        ColormapEntry const searchTarget =
             palmcolor_mapEntryColorFmPixel(*transcolorP, maxval, newMaxval);
-        ColormapEntry * const foundEntryP = 
+        ColormapEntry * const foundEntryP =
             (bsearch(&searchTarget,
                      colormapP->color_entries, colormapP->ncolors,
                      sizeof(ColormapEntry), palmcolor_compare_colors));
@@ -530,7 +530,7 @@ writeCommonHeader(unsigned int         const cols,
 
 
 
-static unsigned char 
+static unsigned char
 compressionFieldValue(enum CompressionType const compression) {
 
     unsigned char retval;
@@ -560,7 +560,7 @@ writeRemainingHeaderLow(unsigned int         const nextDepthOffset,
                         enum CompressionType const compression,
                         unsigned int         const bpp) {
 /*----------------------------------------------------------------------------
-   Write last 6 bytes of a low density Palm Bitmap header. 
+   Write last 6 bytes of a low density Palm Bitmap header.
 -----------------------------------------------------------------------------*/
     if (nextDepthOffset > USHRT_MAX)
         pm_error("Image too large for Palm Bitmap");
@@ -572,7 +572,7 @@ writeRemainingHeaderLow(unsigned int         const nextDepthOffset,
         fputc(transindex, stdout);    /* transparent index */
     } else
         fputc(0, stdout);    /* the DirectInfoType will hold this info */
-    
+
     fputc(compressionFieldValue(compression), stdout);
 
     pm_writebigshort(stdout, 0);  /* reserved by Palm */
@@ -590,7 +590,7 @@ writeRemainingHeaderHigh(unsigned int         const bpp,
                          unsigned int         const transindex,
                          unsigned int         const nextBitmapOffset) {
 /*----------------------------------------------------------------------------
-   Write last 16 bytes of a high density Palm Bitmap header. 
+   Write last 16 bytes of a high density Palm Bitmap header.
 -----------------------------------------------------------------------------*/
     if ((nextBitmapOffset >> 31) > 1)
         pm_error("Image too large for Palm Bitmap.  nextBitmapOffset "
@@ -648,7 +648,7 @@ writeDummy() {
     pm_writebiglong(stdout, 0x00);
     fputc(0xFF, stdout);               /* pixelSize */
     fputc(0x01, stdout);               /* version */
-    pm_writebigshort(stdout, 0x00); 
+    pm_writebigshort(stdout, 0x00);
     pm_writebiglong(stdout, 0x00);
 }
 
@@ -663,7 +663,7 @@ writeColormap(bool         const explicitColormap,
               xel          const transcolor,
               xelval       const maxval,
               unsigned int const version) {
-              
+
     /* if there's a colormap, write it out */
     if (explicitColormap) {
         unsigned int row;
@@ -681,11 +681,11 @@ writeColormap(bool         const explicitColormap,
         /* write the DirectInfoType (8 bytes) */
         if (bpp == 16) {
             fputc(5, stdout);   /* # of bits of red */
-            fputc(6, stdout);   /* # of bits of green */    
+            fputc(6, stdout);   /* # of bits of green */
             fputc(5, stdout);   /* # of bits of blue */
             fputc(0, stdout);   /* reserved by Palm */
         } else
-            pm_error("Don't know how to create %u bit DirectColor bitmaps.", 
+            pm_error("Don't know how to create %u bit DirectColor bitmaps.",
                      bpp);
         if (transparent) {
             fputc(0, stdout);
@@ -714,13 +714,13 @@ computeRawRowDirectColor(const xel *     const xelrow,
   'xelrow' is the image contents of row.  It is 'cols' columns wide and
   samples are based on maxval 'maxval'.
 
-  Put the output data at 'rowdata'. 
+  Put the output data at 'rowdata'.
 -----------------------------------------------------------------------------*/
     unsigned int col;
     unsigned char * outCursor;
-    
+
     for (col = 0, outCursor = &rowdata[0]; col < cols; ++col) {
-        unsigned int const color = 
+        unsigned int const color =
             (scaleSample(PPM_GETR(xelrow[col]), maxval, 31) << 11) |
             (scaleSample(PPM_GETG(xelrow[col]), maxval, 63) <<  5) |
             (scaleSample(PPM_GETB(xelrow[col]), maxval, 31) <<  0);
@@ -782,16 +782,16 @@ computeRawRowNonDirect(const xel *     const xelrow,
                 palmcolor_mapEntryColorFmPixel(xelrow[col], maxval, 255);
             ColormapEntry * const foundEntryP =
                 bsearch(&searchTarget,
-                        colormapP->color_entries, 
+                        colormapP->color_entries,
                         colormapP->ncolors,
-                        sizeof(ColormapEntry), 
+                        sizeof(ColormapEntry),
                         palmcolor_compare_colors);
             if (!foundEntryP) {
                 pm_error("INERNAL ERROR: "
                          "Color (%u,%u,%u) not found in colormap, "
                          "though it was supposedly there before",
-                         PPM_GETR(xelrow[col]), 
-                         PPM_GETG(xelrow[col]), 
+                         PPM_GETR(xelrow[col]),
+                         PPM_GETG(xelrow[col]),
                          PPM_GETB(xelrow[col]));
             }
             color = (*foundEntryP >> 24) & 0xFF;
@@ -816,27 +816,27 @@ computeRawRowNonDirect(const xel *     const xelrow,
 }
 
 
-struct seqBuffer {
+typedef struct {
 /*----------------------------------------------------------------------------
    A buffer to which one can write bytes sequentially.
 -----------------------------------------------------------------------------*/
     char * buffer;
     unsigned int allocatedSize;
     unsigned int occupiedSize;
-};
+} SeqBuffer;
 
 
 static void
-createBuffer(struct seqBuffer ** const bufferPP) {
+seqBuffer_create(SeqBuffer ** const bufferPP) {
 
-    struct seqBuffer * bufferP;
+    SeqBuffer * bufferP;
 
     MALLOCVAR_NOFAIL(bufferP);
 
     bufferP->allocatedSize = 4096;
     MALLOCARRAY(bufferP->buffer, bufferP->allocatedSize);
     if (bufferP == NULL)
-        pm_error("Unable to allocate %u bytes of buffer", 
+        pm_error("Unable to allocate %u bytes of buffer",
                  bufferP->allocatedSize);
     bufferP->occupiedSize = 0;
 
@@ -846,7 +846,7 @@ createBuffer(struct seqBuffer ** const bufferPP) {
 
 
 static void
-destroyBuffer(struct seqBuffer * const bufferP) {
+seqBuffer_destroy(SeqBuffer * const bufferP) {
 
     free(bufferP->buffer);
     free(bufferP);
@@ -855,8 +855,8 @@ destroyBuffer(struct seqBuffer * const bufferP) {
 
 
 static void
-addByteToBuffer(struct seqBuffer * const bufferP,
-                unsigned char      const newByte) {
+seqBuffer_addByte(SeqBuffer *   const bufferP,
+                  unsigned char const newByte) {
 /*-----------------------------------------------------------------------------
   Append one byte to buffer, expanding with realloc() whenever necessary.
 
@@ -866,7 +866,6 @@ addByteToBuffer(struct seqBuffer * const bufferP,
   compression can lead to an arithmetic overflow.
   Abort with error if an arithmetic overflow is detected during doubling.
 -----------------------------------------------------------------------------*/
-
     assert(bufferP->allocatedSize >= bufferP->occupiedSize);
 
     if (bufferP->allocatedSize == bufferP->occupiedSize) {
@@ -890,19 +889,19 @@ addByteToBuffer(struct seqBuffer * const bufferP,
 
 
 static unsigned int
-bufferLength(struct seqBuffer * const bufferP) {
+seqBuffer_length(SeqBuffer * const bufferP) {
     return bufferP->occupiedSize;
 }
 
 
 
 static void
-writeOutBuffer(struct seqBuffer * const bufferP,
-               FILE *             const fileP) {
+seqBuffer_writeOut(SeqBuffer * const bufferP,
+                   FILE *      const fileP) {
 
     size_t bytesWritten;
 
-    bytesWritten = fwrite(bufferP->buffer, sizeof(char), 
+    bytesWritten = fwrite(bufferP->buffer, sizeof(char),
                           bufferP->occupiedSize, fileP);
 
     if (bytesWritten != bufferP->occupiedSize)
@@ -914,19 +913,19 @@ writeOutBuffer(struct seqBuffer * const bufferP,
 static void
 copyRowToBuffer(const unsigned char * const rowdata,
                 unsigned int          const rowbytes,
-                struct seqBuffer *    const rasterBufferP) {
+                SeqBuffer *           const rasterBufferP) {
 
     unsigned int pos;
     for (pos = 0; pos < rowbytes; ++pos)
-        addByteToBuffer(rasterBufferP, rowdata[pos]);
-} 
+        seqBuffer_addByte(rasterBufferP, rowdata[pos]);
+}
 
 
 
 static void
 scanlineCompressAndBufferRow(const unsigned char * const rowdata,
                              unsigned int          const rowbytes,
-                             struct seqBuffer *    const rasterBufferP,
+                             SeqBuffer *           const rasterBufferP,
                              const unsigned char * const lastrow) {
 /*----------------------------------------------------------------------------
    Take the raw Palm Bitmap row 'rowdata', which is 'rowbytes'
@@ -945,27 +944,27 @@ scanlineCompressAndBufferRow(const unsigned char * const rowdata,
         unsigned char map;
             /* mask indicating which of the next 8 pixels are
                different from the previous row, and therefore present
-               in the file immediately following the map byte.  
+               in the file immediately following the map byte.
             */
         unsigned char differentPixels[8];
         unsigned char *outptr;
         unsigned char outbit;
-            
+
         for (outbit = 0, map = 0x00, outptr = differentPixels;
-             outbit < limit;  
+             outbit < limit;
              ++outbit) {
-            if (!lastrow 
+            if (!lastrow
                 || (lastrow[pos + outbit] != rowdata[pos + outbit])) {
                 map |= (1 << (7 - outbit));
                 *outptr++ = rowdata[pos + outbit];
             }
         }
 
-        addByteToBuffer(rasterBufferP, map);
+        seqBuffer_addByte(rasterBufferP, map);
         {
             unsigned int j;
             for (j = 0; j < (outptr - differentPixels); ++j)
-                addByteToBuffer(rasterBufferP, differentPixels[j]);
+                seqBuffer_addByte(rasterBufferP, differentPixels[j]);
         }
     }
 }
@@ -975,7 +974,7 @@ scanlineCompressAndBufferRow(const unsigned char * const rowdata,
 static void
 rleCompressAndBufferRow(const unsigned char * const rowdata,
                         unsigned int          const rowbytes,
-                        struct seqBuffer *    const rasterBufferP) {
+                        SeqBuffer *           const rasterBufferP) {
 /*----------------------------------------------------------------------------
    Take the raw Palm Bitmap row 'rowdata', which is 'rowbytes' bytes,
    and add the rle-compressed representation of it to the buffer with
@@ -984,19 +983,19 @@ rleCompressAndBufferRow(const unsigned char * const rowdata,
     unsigned int pos;
 
     /* we output a count of the number of bytes a value is
-       repeated, followed by that byte value 
+       repeated, followed by that byte value
     */
     pos = 0;
     while (pos < rowbytes) {
         unsigned int repeatcount;
-        for (repeatcount = 1;  
-             repeatcount < (rowbytes - pos) && repeatcount  < 255;  
-             ++repeatcount) 
+        for (repeatcount = 1;
+             repeatcount < (rowbytes - pos) && repeatcount  < 255;
+             ++repeatcount)
             if (rowdata[pos + repeatcount] != rowdata[pos])
                 break;
 
-        addByteToBuffer(rasterBufferP, repeatcount);
-        addByteToBuffer(rasterBufferP, rowdata[pos]);
+        seqBuffer_addByte(rasterBufferP, repeatcount);
+        seqBuffer_addByte(rasterBufferP, rowdata[pos]);
         pos += repeatcount;
     }
 }
@@ -1006,10 +1005,10 @@ rleCompressAndBufferRow(const unsigned char * const rowdata,
 static void
 packbitsCompressAndBufferRow(const unsigned char * const rowdata,
                              unsigned int          const rowbytes,
-                             struct seqBuffer *    const rasterBufferP) {
+                             SeqBuffer *           const rasterBufferP) {
 /*----------------------------------------------------------------------------
    Take the raw Palm Bitmap row 'rowdata', which is 'rowbytes' bytes, and
-   add the packbits-compressed representation of it to the buffer 
+   add the packbits-compressed representation of it to the buffer
    with handle 'rasterBufferP'.
 -----------------------------------------------------------------------------*/
     unsigned char * compressedData;
@@ -1021,7 +1020,7 @@ packbitsCompressAndBufferRow(const unsigned char * const rowdata,
                           rowbytes, &compressedDataCt);
 
     for (byteCt = 0; byteCt < compressedDataCt; ++byteCt)
-        addByteToBuffer(rasterBufferP, compressedData[byteCt]);
+        seqBuffer_addByte(rasterBufferP, compressedData[byteCt]);
 
     free(compressedData);
 }
@@ -1033,7 +1032,7 @@ bufferRowFromRawRowdata(const unsigned char *  const rowdata,
                         unsigned int           const rowbytes,
                         enum CompressionType   const compression,
                         const unsigned char *  const lastrow,
-                        struct seqBuffer *     const rasterBufferP) {
+                        SeqBuffer *            const rasterBufferP) {
 /*----------------------------------------------------------------------------
    Starting with a raw (uncompressed) Palm raster line, do the
    compression identified by 'compression' and add the compressed row
@@ -1049,7 +1048,7 @@ bufferRowFromRawRowdata(const unsigned char *  const rowdata,
         copyRowToBuffer(rowdata, rowbytes, rasterBufferP);
         break;
     case COMP_SCANLINE:
-        scanlineCompressAndBufferRow(rowdata, rowbytes, rasterBufferP, 
+        scanlineCompressAndBufferRow(rowdata, rowbytes, rasterBufferP,
                                      lastrow);
         break;
     case COMP_RLE:
@@ -1075,10 +1074,10 @@ bufferRow(const xel *          const xelrow,
           Colormap *           const colormapP,
           unsigned char *      const rowdata,
           unsigned char *      const lastrow,
-          struct seqBuffer *   const rasterBufferP) {
+          SeqBuffer *          const rasterBufferP) {
 /*----------------------------------------------------------------------------
    Add a row of the Palm Bitmap raster to buffer 'rasterBufferP'.
-   
+
    'xelrow' is the image contents of row.  It is 'cols' columns wide and
    samples are based on maxval 'maxval'.
 
@@ -1091,7 +1090,7 @@ bufferRow(const xel *          const xelrow,
 -----------------------------------------------------------------------------*/
     if (directColor)
         computeRawRowDirectColor(xelrow, cols, maxval, rowdata);
-    else 
+    else
         computeRawRowNonDirect(xelrow, cols, maxval, bpp, colormapP, newMaxval,
                                rowdata);
 
@@ -1101,7 +1100,7 @@ bufferRow(const xel *          const xelrow,
 
 
 
-static void 
+static void
 bufferRaster(xel **               const xels,
              unsigned int         const cols,
              unsigned int         const rows,
@@ -1112,14 +1111,14 @@ bufferRaster(xel **               const xels,
              enum CompressionType const compression,
              bool                 const directColor,
              Colormap *           const colormapP,
-             struct seqBuffer **  const rasterBufferPP) {
-    
+             SeqBuffer **         const rasterBufferPP) {
+
     unsigned char * rowdata;
     unsigned char * lastrow;
     unsigned int row;
 
-    createBuffer(rasterBufferPP);
-    
+    seqBuffer_create(rasterBufferPP);
+
     MALLOCARRAY_NOFAIL(rowdata, rowbytes);
     if (compression == COMP_SCANLINE)
         MALLOCARRAY_NOFAIL(lastrow, rowbytes);
@@ -1157,25 +1156,25 @@ computeOffsetStuff(bool                 const offsetWanted,
                    unsigned int *       const nextDepthOffsetP,
                    unsigned int *       const nextBitmapOffsetP,
                    unsigned int *       const padBytesRequiredP) {
-    
+
     if (offsetWanted) {
         /* Offset is measured in 4-byte words (double words in
            Intel/Microsoft terminology).  Account for header,
-           colormap, and raster size and round up 
+           colormap, and raster size and round up
         */
         unsigned int const headerSize = ((version < 3) ? 16 : 24);
         unsigned int const colormapSize =
             (colormapped ? (2 + colormapColorCount * 4) : 0);
         if (version < 3) {
-            unsigned int const directSize = 
-                (directColor && version < 3) ? 8 : 0; 
+            unsigned int const directSize =
+                (directColor && version < 3) ? 8 : 0;
             if (compression != COMP_NONE && sizePlusRasterSize > USHRT_MAX)
                 pm_error("Oversized compressed bitmap: %u bytes",
                          sizePlusRasterSize);
-            *padBytesRequiredP = 4 - (sizePlusRasterSize + headerSize + 
+            *padBytesRequiredP = 4 - (sizePlusRasterSize + headerSize +
                                       directSize + colormapSize) % 4;
-            *nextDepthOffsetP = 
-                (sizePlusRasterSize + headerSize + 
+            *nextDepthOffsetP =
+                (sizePlusRasterSize + headerSize +
                  directSize + colormapSize + *padBytesRequiredP) / 4;
         } else {
             if (compression != COMP_NONE && (sizePlusRasterSize >> 31) > 1)
@@ -1184,7 +1183,7 @@ computeOffsetStuff(bool                 const offsetWanted,
             /* Does version 3 need padding? Probably won't hurt */
             *padBytesRequiredP = 4 - (sizePlusRasterSize + headerSize +
                                       colormapSize) % 4;
-            *nextBitmapOffsetP = sizePlusRasterSize + headerSize + 
+            *nextBitmapOffsetP = sizePlusRasterSize + headerSize +
                 colormapSize + *padBytesRequiredP;
         }
     } else {
@@ -1204,7 +1203,7 @@ writeRasterSize(unsigned int const sizePlusRasterSize,
    Write to file 'fileP' a raster size field for a Palm Bitmap version
    'version' header, indicating 'sizePlusRasterSize' bytes.
 -----------------------------------------------------------------------------*/
-    if (version < 3) 
+    if (version < 3)
         pm_writebigshort(fileP, sizePlusRasterSize);
     else
         pm_writebiglong(fileP, sizePlusRasterSize);
@@ -1231,37 +1230,37 @@ writeBitmap(xel **               const xels,
             unsigned int         const version,
             unsigned int         const density,
             bool                 const withdummy) {
-    
+
     unsigned int sizePlusRasterSize;
     unsigned int nextDepthOffset;
     unsigned int nextBitmapOffset;
         /* Offset from the beginning of the image we write to the beginning
            of the next one, assuming user writes another one following this
            one.
-           nextDepthOffset is used in encodings 1, 2 and is in 4 byte words 
-           nextBitmapOffset is used in encoding 3, is in 4 bytes 
+           nextDepthOffset is used in encodings 1, 2 and is in 4 byte words
+           nextBitmapOffset is used in encoding 3, is in 4 bytes
         */
     unsigned int padBytesRequired;
         /* Number of bytes of padding we need to put after the image in
            order to align properly for User to add the next image to the
            stream.
         */
-    struct seqBuffer * rasterBufferP;
+    SeqBuffer * rasterBufferP;
 
-    writeCommonHeader(cols, rows, rowbytes, compression, colormapped, 
+    writeCommonHeader(cols, rows, rowbytes, compression, colormapped,
                       transparent, directColor, bpp, version);
-    
+
     bufferRaster(xels, cols, rows, maxval, rowbytes, bpp, newMaxval,
                  compression, directColor, colormapP, &rasterBufferP);
 
     /* rasterSize itself takes 2 or 4 bytes */
     if (version < 3)
-        sizePlusRasterSize = 2 + bufferLength(rasterBufferP);
+        sizePlusRasterSize = 2 + seqBuffer_length(rasterBufferP);
     else
-        sizePlusRasterSize = 4 + bufferLength(rasterBufferP);
-    
+        sizePlusRasterSize = 4 + seqBuffer_length(rasterBufferP);
+
     computeOffsetStuff(offsetWanted, version, directColor, compression,
-                       colormapped, colormapped ? colormapP->ncolors : 0, 
+                       colormapped, colormapped ? colormapP->ncolors : 0,
                        sizePlusRasterSize,
                        &nextDepthOffset, &nextBitmapOffset,
                        &padBytesRequired);
@@ -1273,15 +1272,15 @@ writeBitmap(xel **               const xels,
                                  maxval, transparent, transcolor,
                                  transindex, nextBitmapOffset);
 
-    writeColormap(colormapped, colormapP, directColor, bpp, 
+    writeColormap(colormapped, colormapP, directColor, bpp,
                   transparent, transcolor, maxval, version);
 
     if (compression != COMP_NONE)
         writeRasterSize(sizePlusRasterSize, version, stdout);
 
-    writeOutBuffer(rasterBufferP, stdout);
+    seqBuffer_writeOut(rasterBufferP, stdout);
 
-    destroyBuffer(rasterBufferP);
+    seqBuffer_destroy(rasterBufferP);
 
     {
         unsigned int i;
@@ -1291,11 +1290,11 @@ writeBitmap(xel **               const xels,
 
     if (withdummy)
         writeDummy();
-}        
+}
 
 
 
-int 
+int
 main( int argc, const char **argv ) {
     struct CmdlineInfo cmdline;
     unsigned int version;
@@ -1311,7 +1310,7 @@ main( int argc, const char **argv ) {
     bool directColor;
     unsigned int newMaxval;
     Colormap * colormapP;
-    
+
     pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
@@ -1322,9 +1321,9 @@ main( int argc, const char **argv ) {
     pm_close(ifP);
 
     if (cmdline.verbose)
-        pm_message("Input is %ux%u %s, maxval %u", 
+        pm_message("Input is %ux%u %s, maxval %u",
                    cols, rows, formatName(format), maxval);
-    
+
     determinePalmFormat(cols, rows, maxval, format, xels,
                         cmdline.depthSpec, cmdline.depth,
                         cmdline.maxdepthSpec, cmdline.maxdepth,
@@ -1333,23 +1332,23 @@ main( int argc, const char **argv ) {
 
     newMaxval = (1 << bpp) - 1;
 
-    if (cmdline.transparent) 
+    if (cmdline.transparent)
         findTransparentColor(cmdline.transparent, newMaxval, directColor,
                              maxval, colormapP, &transcolor, &transindex);
-    else 
+    else
         transindex = 0;
 
-    rowbytes = ((cols + (16 / bpp -1)) / (16 / bpp)) * 2;    
+    rowbytes = ((cols + (16 / bpp -1)) / (16 / bpp)) * 2;
         /* bytes per row - always a word boundary */
 
-    version = bitmapVersion(bpp, cmdline.colormap, !!cmdline.transparent, 
+    version = bitmapVersion(bpp, cmdline.colormap, !!cmdline.transparent,
                             cmdline.compression, cmdline.density);
 
     writeBitmap(xels, cols, rows, maxval,
                 rowbytes, bpp, newMaxval, cmdline.compression,
-                !!cmdline.transparent, directColor, cmdline.offset, 
+                !!cmdline.transparent, directColor, cmdline.offset,
                 cmdline.colormap, colormapP, transindex, transcolor,
                 version, cmdline.density, cmdline.withdummy);
-    
+
     return 0;
 }
diff --git a/converter/other/pstopnm.c b/converter/other/pstopnm.c
index f5342655..25f2c429 100644
--- a/converter/other/pstopnm.c
+++ b/converter/other/pstopnm.c
@@ -442,7 +442,7 @@ languageDeclaration(char const inputFileName[]) {
 /*----------------------------------------------------------------------------
   Return the Postscript language in which the file declares it is written.
   (Except that if the file is on Standard Input or doesn't validly declare
-  a languages, just say it is Common Postscript).
+  a language, just say it is Common Postscript).
 -----------------------------------------------------------------------------*/
     enum PostscriptLanguage language;
 
@@ -909,6 +909,27 @@ execGhostscript(int               const inputPipeFd,
 
 
 static void
+copyFileStream(FILE * const ifP,
+               FILE * const ofP) {
+
+    bool eof;
+
+    for (eof = false; !eof; ) {
+        char buffer[4096];
+        size_t readCt;
+
+        readCt = fread(buffer, 1, sizeof(buffer), ifP);
+
+        if (readCt == 0)
+            eof = true;
+        else
+            fwrite(buffer, 1, readCt, ofP);
+    }
+}
+
+
+
+static void
 feedPsToGhostScript(const char *            const inputFileName,
                     struct Box              const borderedBox,
                     struct Dimensions       const imageDim,
@@ -927,7 +948,6 @@ feedPsToGhostScript(const char *            const inputFileName,
 -----------------------------------------------------------------------------*/
     FILE * pipeToGsP;  /* Pipe to Ghostscript's standard input */
     FILE * ifP;
-    bool eof;  /* End of file on input */
 
     pipeToGsP = fdopen(pipeToGhostscriptFd, "w");
     if (pipeToGsP == NULL)
@@ -947,8 +967,14 @@ feedPsToGhostScript(const char *            const inputFileName,
       The example given is a much fancier solution than we need
       here, I think, so I boiled it down a bit.  JM
     */
-    if (language == ENCAPSULATED_POSTSCRIPT)
-        fprintf(pipeToGsP, "\n/b4_Inc_state save def /showpage { } def\n");
+    if (language == ENCAPSULATED_POSTSCRIPT) {
+        const char * const defShowpageCmd =
+            "/b4_Inc_state save def /showpage { } def";
+        if (verbose)
+            pm_message("Defining showpage with '%s'", defShowpageCmd);
+
+        fprintf(pipeToGsP, "\n%s\n", defShowpageCmd);
+    }
 
     writePstrans(borderedBox, imageDim, orientation, pipeToGsP);
 
@@ -958,22 +984,19 @@ feedPsToGhostScript(const char *            const inputFileName,
     */
     signal(SIGPIPE, SIG_IGN);
 
-    eof = FALSE;
-    while (!eof) {
-        char buffer[4096];
-        size_t readCt;
+    copyFileStream(ifP, pipeToGsP);
 
-        readCt = fread(buffer, 1, sizeof(buffer), ifP);
-        if (readCt == 0)
-            eof = TRUE;
-        else
-            fwrite(buffer, 1, readCt, pipeToGsP);
-    }
     pm_close(ifP);
 
-    if (language == ENCAPSULATED_POSTSCRIPT)
-        fprintf(pipeToGsP, "\nb4_Inc_state restore showpage\n");
+    if (language == ENCAPSULATED_POSTSCRIPT) {
+        const char * const restoreShowpageCmd =
+            "b4_Inc_state restore showpage";
+
+        if (verbose)
+            pm_message("Restoring showpage with '%s'", restoreShowpageCmd);
 
+        fprintf(pipeToGsP, "\n%s\n", restoreShowpageCmd);
+    }
     fclose(pipeToGsP);
 }
 
diff --git a/converter/pbm/pbmtolps.c b/converter/pbm/pbmtolps.c
index 5adef4c8..dd0342bc 100644
--- a/converter/pbm/pbmtolps.c
+++ b/converter/pbm/pbmtolps.c
@@ -35,7 +35,7 @@ static int pointcount = 2;
 static int run = 1;
 #endif
 
-static char 
+static char
 morepoints(char cmd, int howmany_pbmtolps) {
     pointcount += 2;
     if (pointcount > 1000) {
@@ -47,8 +47,8 @@ morepoints(char cmd, int howmany_pbmtolps) {
 
 
 
-static void 
-addstrip(int const white, 
+static void
+addstrip(int const white,
          int const black) {
 
     if (cmd) {
@@ -58,7 +58,7 @@ addstrip(int const white,
         else {
             if (run == 1)
 #endif
-                printf("%d %d %c ", 
+                printf("%d %d %c ",
                        prev_black, prev_white, morepoints(cmd, 2));
 #ifdef RUN
             else
@@ -78,7 +78,7 @@ addstrip(int const white,
 
 
 
-static void 
+static void
 nextline(void) {
     /* need to check run, should have an outcommand */
     if (cmd)
diff --git a/doc/HISTORY b/doc/HISTORY
index 308f903b..a2618cad 100644
--- a/doc/HISTORY
+++ b/doc/HISTORY
@@ -4,14 +4,14 @@ Netpbm.
 CHANGE HISTORY 
 --------------
 
-19.06.15 BJH  Release 10.86.04
+19.06.28 BJH  Release 10.87.00
 
-              pamtris: Fix bug: debug trace left in
-
-              pbmtozinc: Fix wrong output on big-endian machines.  Broken in
-              Netpbm 10.71 (June 2015).
+              pamfind: Add -machine .
 
-19.05.04 BJH  Release 10.86.03
+              Multiple: fix bug: when you specify the same option twice, you
+              can get a syntax error, with the message telling you you
+              specified some other option that conflicts with it.  Should just
+              take the last setting.
 
               pnmtopng: Fix bug: Defaults to no filters.  Should be all
               filters.  Effect is larger PNG output.  Broken after Netpbm
@@ -25,16 +25,18 @@ CHANGE HISTORY
               pnmcrop: Don't allow -borderfile with -reportXXX.  It doesn't
               work.
 
-19.04.10 BJH  Release 10.86.02
-
               pnmcrop: fix bug: -bgcolor doesn't work.  Always present
               (-bgcolor was introduced in Netpbm 10.86 (March 2019)).
 
-19.04.06 BJH  Release 10.86.01
+              pbmtext: fix bug: don't ignore -builtin when specified with
+              -font.  Fail with syntax error instead.
 
-              pnmcrop: fix bug: incorrect identification of background with
-              -bgcolor and PBM or PGM image.  Always present (-bgcolor was
-              introduced in Netpbm 10.86 (March 2019)).
+              pbmtozinc: fix wrong output on big-endian machines.  Broken in
+              Netpbm 10.71 (June 2015).
+
+              pbmpage: Fix error message for invalid syntax.
+
+              pamtris: Fix bug: debug trace left in
 
 19.03.30 BJH  Release 10.86.00
 
diff --git a/doc/TESTS b/doc/TESTS
index 9434f580..44f86758 100644
--- a/doc/TESTS
+++ b/doc/TESTS
@@ -1,5 +1,3 @@
-Please cut and paste from below:
----------------------------------------------------------------------------
 Contents
 ========
 
@@ -7,6 +5,8 @@ Contents
   1.1 Standard test procedure
   1.2 Summary report
   1.3 Prerequisites
+    1.3.1 Required programs
+    1.3.2 Required locales
   1.4 Repeatability
   1.5 Execution time
   1.6 Testing package in designated directory
@@ -69,6 +69,9 @@ appear at the end:
 1.3 Prerequisites
 =================
 
+1.3.1 Required programs
+-----------------------
+
 The tests require the Bash command shell.  The script Execute-Tests has
 some expressions unique to Bash.  Quite old versions work, at least back
 to Bash v. 2.05b.
@@ -81,28 +84,54 @@ The tests use the following utilities:
  - sh
  - awk
 
+ - basename
  - cat
  - cksum
  - cmp
+ - comm
  - cp
  - cut
  - date
  - dirname
  - egrep
  - fgrep
- - grep
  - file
+ - grep
+ - gs
  - head
  - iconv
  - mkdir
  - mktemp
+ - perl
  - rm
  - sed
  - seq
+ - sh
+ - sort
  - tee
  - tr
  - uniq
+ - wc
+
+
+1.3.2 Required locales
+----------------------
+
+For full covereage the following locales must be available:
+
+  en_US.iso88591, en_US.utf8
+
+To check whether they are available, execute the following and see if they
+are reported:
+
+  locale -a | grep en_US
+
+The output should contain these lines:
+
+  en_US.iso88591
+  en_US.utf8
 
+If these locales are absent some pbmtext tests will be skipped.
 
 
 1.4 Repeatability
diff --git a/doc/patent_summary b/doc/patent_summary
index b9623d09..5fe0923c 100644
--- a/doc/patent_summary
+++ b/doc/patent_summary
@@ -22,6 +22,13 @@ applied to things you implement in computer programs.  This is one of
 the Free Software Foundation's causes.  See 
 <http://www.gnu.org/philosophy.html#laws>.
 
+All the patents mentioned in this file have probably expired.  The maintainer
+is unaware of any recent patented inventions used in Netpbm.
+
+
+JBIG patents
+------------
+
 The Jbigtopnm and Pnmtojbig programs use arithmetic coding patents and
 other patents covering various aspects of the "front end."
 
@@ -37,7 +44,7 @@ Forgent owns a patent it believes covers JPEG compression.  This
 patent was virtually unknown before July 2002, when Forgent began to
 enforce it.  It has successfully enforced it against two companies
 (Sony and an unnamed Japanese digital camera maker), but without court
-ruling.  This patent, U.S. Patent No. 4,698,672, expires in 2006.
+ruling.  This patent, U.S. Patent No. 4,698,672, expired in 2006.
 
 Philips and Lucent Technologies also own patents they claim cover
 JPEG.
diff --git a/editor/pnmcrop.c b/editor/pnmcrop.c
index d6bae1d3..6ef1c280 100644
--- a/editor/pnmcrop.c
+++ b/editor/pnmcrop.c
@@ -454,7 +454,9 @@ backgroundColor(FILE *         const ifP,
    *ifP, which is described by 'cols', 'rows', 'maxval', and 'format'.
 
    'backgroundChoice' is the method we are to use in determining the
-   background color.
+   background color.  'colorName' is the color we are to assume is
+   background in the case that 'backgroundChoice' says to use a particular
+   color and meangingless otherwise.
 
    Expect the file to be positioned to the start of the raster, and leave
    it positioned arbitrarily.
@@ -484,9 +486,6 @@ backgroundColor(FILE *         const ifP,
         background =
             background1Corner(ifP, rows, cols, maxval, format, corner);
         break;
-
-    default:
-        pm_error("internal error");
     }
 
     return background;
diff --git a/generator/pbmpage.c b/generator/pbmpage.c
index a2f47bcc..96dca876 100644
--- a/generator/pbmpage.c
+++ b/generator/pbmpage.c
@@ -1,6 +1,6 @@
-/***************************************************************************
+/*=============================================================================
                                 pbmpage
-
+===============================================================================
   This program produces a printed page test pattern in PBM format.
 
   This was adapted from Tim Norman's 'pbmtpg' program, part of his
@@ -10,7 +10,7 @@
 
   For copyright and licensing information, see the pbmtoppa program,
   which was also derived from the same package.
-****************************************************************************/
+=============================================================================*/
 
 #include <stdlib.h>
 #include <string.h>
@@ -18,73 +18,139 @@
 #include <stdio.h>
 
 #include "pm_c_util.h"
+#include "mallocvar.h"
+#include "shhopt.h"
+#include "nstring.h"
 #include "pbm.h"
 
+enum Pattern {PAT_GRID, PAT_VERTICAL, PAT_DIAGONAL};
+
 /* US is 8.5 in by 11 in */
 
-#define USWIDTH  (5100)
-#define USHEIGHT (6600)
+static unsigned int const usWidth  = 5100;
+static unsigned int const usHeight = 6600;
 
 /* A4 is 210 mm by 297 mm == 8.27 in by 11.69 in */
 
-#define A4WIDTH  (4960)
-#define A4HEIGHT (7016)
+static unsigned int const a4Width  = 4960;
+static unsigned int const a4Height = 7016;
 
 
-struct bitmap {
-    unsigned int Width;      /* width and height in 600ths of an inch */
-    unsigned int Height;
-    bit ** bitmap;
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    enum Pattern pattern;
+    unsigned int a4;
 };
 
-static struct bitmap bitmap;
+
+
+static void
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;
+        /* Instructions to OptParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "a4",         OPT_FLAG, NULL, &cmdlineP->a4,       0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+    /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (argc-1 < 1)
+        cmdlineP->pattern = PAT_GRID;
+    else {
+        if (argc-1 > 1)
+            pm_error("Too many arguments (%u).  The only possible argument "
+                     "is the pattern number", argc-1);
+        if (streq(argv[1], "1"))
+            cmdlineP->pattern = PAT_GRID;
+        else if (streq(argv[1], "2"))
+            cmdlineP->pattern = PAT_VERTICAL;
+        else if (streq(argv[1], "3"))
+            cmdlineP->pattern = PAT_DIAGONAL;
+        else
+            pm_error("Invalid test pattern name '%s'.  "
+                     "We recognize only '1', '2', and '3'", argv[1]);
+    }
+    free(option_def);
+}
+
+
+
+struct Bitmap {
+    /* width and height in 600ths of an inch */
+    unsigned int width;
+    unsigned int height;
+
+    unsigned char ** bitmap;
+};
 
 
 
 static void
-setpixel(unsigned int const x,
-         unsigned int const y,
-         unsigned int const c) {
+setpixel(struct Bitmap * const bitmapP,
+         unsigned int    const x,
+         unsigned int    const y,
+         bit             const c) {
 
     char const bitmask = 128 >> (x % 8);
 
-    if (x < 0 || x >= bitmap.Width)
-        return;
-    if (y < 0 || y >= bitmap.Height)
-        return;
-
-    if (c)
-        bitmap.bitmap[y][x/8] |= bitmask;
-    else
-        bitmap.bitmap[y][x/8] &= ~bitmask;
+    if (x < 0 || x >= bitmapP->width) {
+        /* Off the edge of the canvas */
+    } else if (y < 0 || y >= bitmapP->height) {
+        /* Off the edge of the canvas */
+    } else {
+        if (c == PBM_BLACK)
+            bitmapP->bitmap[y][x/8] |= bitmask;
+        else
+            bitmapP->bitmap[y][x/8] &= ~bitmask;
+    }
 }
 
 
 
-static void 
-setplus(unsigned int const x,
-        unsigned int const y,
-        unsigned int const s) {
+static void
+setplus(struct Bitmap * const bitmapP,
+        unsigned int    const x,
+        unsigned int    const y,
+        unsigned int    const s) {
 /*----------------------------------------------------------------------------
-   Draw a black plus sign centered at (x,y) with arms 's' pixels long.  
+   Draw a black plus sign centered at (x,y) with arms 's' pixels long.
    Leave the exact center of the plus white.
 -----------------------------------------------------------------------------*/
     unsigned int i;
 
     for (i = 0; i < s; ++i) {
-        setpixel(x+i, y,   1);
-        setpixel(x-i, y,   1);
-        setpixel(x,   y+i, 1);
-        setpixel(x,   y-i, 1);
+        setpixel(bitmapP, x + i, y,     PBM_BLACK);
+        setpixel(bitmapP, x - i, y,     PBM_BLACK);
+        setpixel(bitmapP, x ,    y + i, PBM_BLACK);
+        setpixel(bitmapP, x ,    y - i, PBM_BLACK);
     }
 }
 
 
 
-static void 
-setblock(unsigned int const x,
-         unsigned int const y,
-         unsigned int const s) {
+static void
+setblock(struct Bitmap * const bitmapP,
+         unsigned int    const x,
+         unsigned int    const y,
+         unsigned int    const s) {
 
     unsigned int i;
 
@@ -92,16 +158,17 @@ setblock(unsigned int const x,
         unsigned int j;
 
         for (j = 0; j < s; ++j)
-            setpixel(x+i, y+j, 1);
+            setpixel(bitmapP, x + i, y + j, PBM_BLACK);
     }
 }
 
 
 
-static void 
-setchar(unsigned int const x,
-        unsigned int const y,
-        char         const c) {
+static void
+setchar(struct Bitmap * const bitmapP,
+        unsigned int    const x,
+        unsigned int    const y,
+        char            const c) {
 
     static char const charmap[10][5]= { { 0x3e, 0x41, 0x41, 0x41, 0x3e },
                                         { 0x00, 0x42, 0x7f, 0x40, 0x00 },
@@ -113,7 +180,7 @@ setchar(unsigned int const x,
                                         { 0x01, 0x01, 0x61, 0x19, 0x07 },
                                         { 0x36, 0x49, 0x49, 0x49, 0x36 },
                                         { 0x26, 0x49, 0x49, 0x49, 0x3e } };
-    
+
     if (c <= '9' && c >= '0') {
         unsigned int xo;
 
@@ -122,7 +189,7 @@ setchar(unsigned int const x,
 
             for (yo = 0; yo < 8; ++yo) {
                 if ((charmap[c-'0'][xo] >> yo) & 0x01)
-                    setblock(x + xo*3, y + yo*3, 3);
+                    setblock(bitmapP, x + xo*3, y + yo*3, 3);
             }
         }
     }
@@ -130,23 +197,25 @@ setchar(unsigned int const x,
 
 
 
-static void 
-setstring(unsigned int const x,
-          unsigned int const y,
-          const char * const s) {
+static void
+setstring(struct Bitmap * const bitmapP,
+          unsigned int    const x,
+          unsigned int    const y,
+          const char *    const s) {
 
     const char * p;
     unsigned int xo;
 
     for (xo = 0, p = s; *p; xo += 21, ++p)
-        setchar(x + xo, y, *p);
+        setchar(bitmapP, x + xo, y, *p);
 }
 
 
 
-static void 
-setCG(unsigned int const x,
-      unsigned int const y) {
+static void
+setCG(struct Bitmap * const bitmapP,
+      unsigned int    const x,
+      unsigned int    const y) {
 
     unsigned int xo;
 
@@ -155,16 +224,16 @@ setCG(unsigned int const x,
 
         unsigned int zo;
 
-        setpixel(x + xo, y + yo, 1);
-        setpixel(x+yo,   y + xo, 1);
-        setpixel(x-1-xo, y-1-yo, 1);
-        setpixel(x-1-yo, y-1-xo, 1);
-        setpixel(x+xo,   y-1-yo, 1);
-        setpixel(x-1-xo, y+yo,   1);
+        setpixel(bitmapP, x + xo    , y + yo    , PBM_BLACK);
+        setpixel(bitmapP, x + yo    , y + xo    , PBM_BLACK);
+        setpixel(bitmapP, x - 1 - xo, y - 1 - yo, PBM_BLACK);
+        setpixel(bitmapP, x - 1 - yo, y - 1 - xo, PBM_BLACK);
+        setpixel(bitmapP, x + xo    , y - 1 - yo, PBM_BLACK);
+        setpixel(bitmapP, x - 1 - xo, y + yo    , PBM_BLACK);
 
-        for(zo = 0; zo < yo; ++zo) {
-            setpixel(x + xo, y-1-zo, 1);
-            setpixel(x-1-xo, y+zo,   1);
+        for (zo = 0; zo < yo; ++zo) {
+            setpixel(bitmapP, x + xo    , y - 1 - zo, PBM_BLACK);
+            setpixel(bitmapP, x - 1 - xo, y + zo    , PBM_BLACK);
         }
     }
 }
@@ -173,129 +242,178 @@ setCG(unsigned int const x,
 
 static void
 outputPbm(FILE *        const ofP,
-          struct bitmap const bitmap) {
+          struct Bitmap const bitmap) {
 /*----------------------------------------------------------------------------
   Create a pbm file containing the image from the global variable bitmap[].
 -----------------------------------------------------------------------------*/
     int const forceplain = 0;
 
     unsigned int row;
-    
-    pbm_writepbminit(ofP, bitmap.Width, bitmap.Height, forceplain);
-    
-    for (row = 0; row < bitmap.Height; ++row) {
+
+    pbm_writepbminit(ofP, bitmap.width, bitmap.height, forceplain);
+
+    for (row = 0; row < bitmap.height; ++row) {
         pbm_writepbmrow_packed(ofP, bitmap.bitmap[row],
-                               bitmap.Width, forceplain); 
+                               bitmap.width, forceplain);
     }
 }
 
 
 
 static void
-framePerimeter(unsigned int const Width, 
-               unsigned int const Height) {
+framePerimeter(struct Bitmap * const bitmapP) {
 
     unsigned int x, y;
 
     /* Top edge */
-    for (x = 0; x < Width; ++x)
-        setpixel(x, 0, 1);
+    for (x = 0; x < bitmapP->width; ++x)
+        setpixel(bitmapP, x, 0, PBM_BLACK);
 
     /* Bottom edge */
-    for (x = 0; x < Width; ++x)
-        setpixel(x, Height-1, 1);
+    for (x = 0; x < bitmapP->width; ++x)
+        setpixel(bitmapP, x, bitmapP->height - 1, PBM_BLACK);
 
     /* Left edge */
-    for (y = 0; y < Height; ++y)
-        setpixel(0, y, 1);
+    for (y = 0; y < bitmapP->height; ++y)
+        setpixel(bitmapP, 0, y, PBM_BLACK);
 
     /* Right edge */
-    for (y = 0; y < Height; ++y)
-        setpixel(Width-1, y, 1);
+    for (y = 0; y < bitmapP->height; ++y)
+        setpixel(bitmapP, bitmapP->width - 1, y, PBM_BLACK);
 }
 
 
 
-int 
-main(int argc, const char** argv) {
+static void
+makeWhite(struct Bitmap * const bitmapP) {
 
-    int TP;
-    unsigned int x, y;
-    char buf[128];
-    /* width and height in 600ths of an inch */
-    unsigned int Width;
-    unsigned int Height;
+    unsigned int y;
 
-    pm_proginit(&argc, argv);
-
-    if (argc > 1 && strcmp(argv[1], "-a4") == 0) {
-        Width  = A4WIDTH;
-        Height = A4HEIGHT;
-        --argc;
-        ++argv;
-    } else {
-        Width  = USWIDTH;
-        Height = USHEIGHT;
+    for (y = 0; y < bitmapP->height; ++y) {
+        unsigned int x;
+        for (x = 0; x < pbm_packed_bytes(bitmapP->width); ++x)
+            bitmapP->bitmap[y][x] = 0x00;  /* 8 white pixels */
     }
+}
 
-    if (argc > 1)
-        TP = atoi(argv[1]);
-    else
-        TP = 1;
 
-    bitmap.Width  = Width;
-    bitmap.Height = Height;
-    bitmap.bitmap = pbm_allocarray_packed(Width, bitmap.Height);
 
-    for (y = 0; y < bitmap.Height; ++y) {
-        unsigned int x;
-        for (x = 0; x < pbm_packed_bytes(bitmap.Width); ++x) 
-            bitmap.bitmap[y][x] = 0x00; 
-    }
+static void
+drawGrid(struct Bitmap * const bitmapP) {
 
-    switch (TP) {
-    case 1:
-        framePerimeter(Width, Height);
-        for (x = 0; x < Width; x += 100) {
+    char buf[128];
+
+    framePerimeter(bitmapP);
+    {
+        unsigned int x;
+        for (x = 0; x < bitmapP->width; x += 100) {
             unsigned int y;
-            for(y = 0; y < Height; y += 100)
-                setplus(x, y, 4);
+            for (y = 0; y < bitmapP->height; y += 100)
+                setplus(bitmapP, x, y, 4);
         }
-        for(x = 0; x < Width; x += 100) {
-            sprintf(buf,"%d", x);
-            setstring(x + 3, (Height/200) * 100 + 3, buf);
+    }
+    {
+        unsigned int x;
+        for (x = 0; x < bitmapP->width; x += 100) {
+            sprintf(buf,"%u", x);
+            setstring(bitmapP, x + 3, (bitmapP->height/200) * 100 + 3, buf);
         }
-        for (y = 0; y < Height; y += 100) {
-            sprintf(buf, "%d", y);
-            setstring((Width/200) * 100 + 3, y + 3, buf);
+    }
+    {
+        unsigned int y;
+        for (y = 0; y < bitmapP->height; y += 100) {
+            sprintf(buf, "%u", y);
+            setstring(bitmapP, (bitmapP->width/200) * 100 + 3, y + 3, buf);
         }
-        for (x = 0; x < Width; x += 10)
-            for (y = 0; y < Height; y += 100)
-                setplus(x, y, ((x%100) == 50) ? 2 : 1);
-        for (x = 0; x < Width; x += 100) {
+    }
+    {
+        unsigned int x;
+        for (x = 0; x < bitmapP->width; x += 10) {
             unsigned int y;
-            for (y = 0; y < Height; y += 10)
-                setplus(x, y, ((y%100) == 50) ? 2 : 1);
+            for (y = 0; y < bitmapP->height; y += 100)
+                setplus(bitmapP, x, y, ((x%100) == 50) ? 2 : 1);
         }
-        setCG(Width/2, Height/2);
+    }
+    {
+        unsigned int x;
+        for (x = 0; x < bitmapP->width; x += 100) {
+            unsigned int y;
+            for (y = 0; y < bitmapP->height; y += 10)
+                setplus(bitmapP, x, y, ((y%100) == 50) ? 2 : 1);
+        }
+    }
+    setCG(bitmapP, bitmapP->width/2, bitmapP->height/2);
+}
+
+
+
+static void
+drawVertical(struct Bitmap * const bitmapP) {
+
+    unsigned int y;
+
+    for (y = 0; y < 300; ++y)
+        setpixel(bitmapP, bitmapP->width/2, bitmapP->height/2 - y, PBM_BLACK);
+}
+
+
+
+static void
+drawDiagonal(struct Bitmap * const bitmapP) {
+
+    unsigned int y;
+
+    for (y = 0; y < 300; ++y) {
+        setpixel(bitmapP, y, y, PBM_BLACK);
+        setpixel(bitmapP, bitmapP->width - 1 - y, bitmapP->height - 1 - y,
+                 PBM_BLACK);
+    }
+}
+
+
+
+int
+main(int argc, const char** argv) {
+
+    struct CmdlineInfo cmdline;
+    /* width and height in 600ths of an inch */
+    unsigned int width;
+    unsigned int height;
+    struct Bitmap bitmap;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    if (cmdline.a4) {
+        width  = a4Width;
+        height = a4Height;
+    } else {
+        width  = usWidth;
+        height = usHeight;
+    }
+
+    bitmap.width  = width;
+    bitmap.height = height;
+    bitmap.bitmap = pbm_allocarray_packed(width, height);
+
+    makeWhite(&bitmap);
+
+    switch (cmdline.pattern) {
+    case PAT_GRID:
+        drawGrid(&bitmap);
         break;
-    case 2:
-        for (y = 0; y < 300; ++y)
-            setpixel(Width/2, Height/2-y, 1);
+    case PAT_VERTICAL:
+        drawVertical(&bitmap);
         break;
-    case 3:
-        for (y = 0; y < 300; ++y) {
-            setpixel(y, y, 1);
-            setpixel(Width-1-y, Height-1-y, 1);
-        }
+    case PAT_DIAGONAL:
+        drawDiagonal(&bitmap);
         break;
-    default:
-        pm_error("unknown test pattern (%d)", TP);
     }
 
     outputPbm(stdout, bitmap);
 
-    pbm_freearray(bitmap.bitmap, Height);
+    pbm_freearray(bitmap.bitmap, height);
 
     pm_close(stdout);
 
diff --git a/generator/pbmtext.c b/generator/pbmtext.c
index e6f27865..a840d1df 100644
--- a/generator/pbmtext.c
+++ b/generator/pbmtext.c
@@ -153,6 +153,9 @@ parseCommandLine(int argc, const char ** argv,
     else if (cmdlineP->lspace < -pbm_maxfontheight())
         pm_error("negative -lspace value too large");
 
+    if (cmdlineP->font != NULL && cmdlineP->builtin != NULL)
+        pm_error("You cannot specify both -font and -builtin");
+
     if (cmdlineP->textdump) {
         if (cmdlineP->dryrun)
             pm_error("You cannot specify both -dry-run and -text-dump");
@@ -170,9 +173,8 @@ parseCommandLine(int argc, const char ** argv,
             pm_error("-wchar is not valid when text is from command line");
 
         cmdlineP->text = textFmCmdLine(argc, argv);
-
-
     }
+
     free(option_def);
 }
 
diff --git a/generator/ppmforge.c b/generator/ppmforge.c
index 390180e3..fe80f529 100644
--- a/generator/ppmforge.c
+++ b/generator/ppmforge.c
@@ -54,21 +54,14 @@ static double const hugeVal = 1e50;
 typedef struct {
     double x;
     double y;
-    double z; 
-} vector;
+    double z;
+} Vector;
 
 /* Definition for obtaining random numbers. */
 
 #define nrand 4               /* Gauss() sample count */
 #define Cast(low, high) ((low)+(((high)-(low)) * ((rand() & 0x7FFF) / arand)))
 
-/* prototypes */
-static void fourn ARGS((float data[], int nn[], int ndim, int isign));
-static void initgauss ARGS((unsigned int seed));
-static double gauss ARGS((void));
-static void spectralsynth ARGS((float **x, unsigned int n, double h));
-static void temprgb ARGS((double temp, double *r, double *g, double *b));
-static void etoile ARGS((pixel *pix));
 /*  Local variables  */
 
 static double arand, gaussadd, gaussfac; /* Gaussian random parameters */
@@ -111,11 +104,11 @@ static void
 parseCommandLine(int argc, const char **argv,
                  struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
-  Convert program invocation arguments (argc,argv) into a format the 
+  Convert program invocation arguments (argc,argv) into a format the
   program can use easily, struct cmdlineInfo.  Validate arguments along
   the way and exit program with message if invalid.
 
-  Note that some string information we return as *cmdlineP is in the storage 
+  Note that some string information we return as *cmdlineP is in the storage
   argv[] points to.
 -----------------------------------------------------------------------------*/
     optEntry * option_def;
@@ -243,9 +236,16 @@ parseCommandLine(int argc, const char **argv,
 }
 
 
-/*  FOURN  --  Multi-dimensional fast Fourier transform
 
-    Called with arguments:
+static void
+fourn(float *     const data,
+      const int * const nn,
+      int         const ndim,
+      int         const isign) {
+/*----------------------------------------------------------------------------
+    Multi-dimensional fast Fourier transform
+
+    Arguments:
 
        data       A  one-dimensional  array  of  floats  (NOTE!!!   NOT
               DOUBLES!!), indexed from one (NOTE!!!   NOT  ZERO!!),
@@ -265,13 +265,8 @@ parseCommandLine(int argc, const char **argv,
 
         This  function  is essentially as given in Press et al., "Numerical
         Recipes In C", Section 12.11, pp.  467-470.
-*/
-
-static void fourn(data, nn, ndim, isign)
-    float data[];
-    int nn[], ndim, isign;
-{
-    register int i1, i2, i3;
+-----------------------------------------------------------------------------*/
+    int i1, i2, i3;
     int i2rev, i3rev, ip1, ip2, ip3, ifp1, ifp2;
     int ibit, idim, k1, k2, n, nprev, nrem, ntot;
     float tempi, tempr;
@@ -339,12 +334,15 @@ static void fourn(data, nn, ndim, isign)
 }
 #undef SWAP
 
-/*  INITGAUSS  --  Initialize random number generators.  As given in
-           Peitgen & Saupe, page 77. */
 
-static void initgauss(seed)
-    unsigned int seed;
-{
+
+static void
+initgauss(unsigned int const seed) {
+/*----------------------------------------------------------------------------
+  Initialize random number generators.
+
+  As given in Peitgen & Saupe, page 77.
+-----------------------------------------------------------------------------*/
     /* Range of random generator */
     arand = pow(2.0, 15.0) - 1.0;
     gaussadd = sqrt(3.0 * nrand);
@@ -352,30 +350,36 @@ static void initgauss(seed)
     srand(seed);
 }
 
-/*  GAUSS  --  Return a Gaussian random number.  As given in Peitgen
-           & Saupe, page 77. */
 
-static double gauss()
-{
+
+static double
+gauss() {
+/*----------------------------------------------------------------------------
+  A Gaussian random number.
+
+  As given in Peitgen & Saupe, page 77.
+-----------------------------------------------------------------------------*/
     int i;
-    double sum = 0.0;
+    double sum;
 
-    for (i = 1; i <= nrand; i++) {
+    for (i = 1, sum = 0.0; i <= nrand; ++i) {
         sum += (rand() & 0x7FFF);
     }
     return gaussfac * sum - gaussadd;
 }
 
-/*  SPECTRALSYNTH  --  Spectrally  synthesized  fractal  motion in two
-               dimensions.  This algorithm is given under  the
-               name   SpectralSynthesisFM2D  on  page  108  of
-               Peitgen & Saupe. */
 
-static void spectralsynth(x, n, h)
-    float **x;
-    unsigned int n;
-    double h;
-{
+
+static void
+spectralsynth(float **     const x,
+              unsigned int const n,
+              double        const h) {
+/*----------------------------------------------------------------------------
+  Spectrally synthesized fractal motion in two dimensions.
+
+  This algorithm is given under the name SpectralSynthesisFM2D on page 108 of
+  Peitgen & Saupe.
+-----------------------------------------------------------------------------*/
     unsigned bl;
     int i, j, i0, j0, nsize[3];
     double rad, phase, rcos, rsin;
@@ -430,20 +434,20 @@ static void spectralsynth(x, n, h)
 
 
 
-/*  TEMPRGB  --  Calculate the relative R, G, and B components  for  a
-         black  body  emitting  light  at a given temperature.
-         The Planck radiation equation is solved directly  for
-         the R, G, and B wavelengths defined for the CIE  1931
-         Standard    Colorimetric    Observer.    The   color
-         temperature is specified in degrees Kelvin. */
-
-static void temprgb(temp, r, g, b)
-    double temp;
-    double *r, *g, *b;
-{
-    double c1 = 3.7403e10,
-        c2 = 14384.0,
-        er, eg, eb, es;
+static void
+temprgb(double   const temp,
+        double * const r,
+        double * const g,
+        double * const b) {
+/*----------------------------------------------------------------------------
+  Calculate the relative R, G, and B components for a black body emitting
+  light at a given temperature.  We solve the Planck radiation equation
+  directly for the R, G, and B wavelengths defined for the CIE 1931 Standard
+  Colorimetric Observer.  The color temperature is specified in kelvins.
+-----------------------------------------------------------------------------*/
+    double const c1 = 3.7403e10;
+    double const c2 = 14384.0;
+    double er, eg, eb, es;
 
 /* Lambda is the wavelength in microns: 5500 angstroms is 0.55 microns. */
 
@@ -462,11 +466,13 @@ static void temprgb(temp, r, g, b)
         *b = eb * es;
 }
 
-/*  ETOILE  --  Set a pixel in the starry sky.  */
 
-static void etoile(pix)
-    pixel *pix;
-{
+
+static void
+etoile(pixel * const pix) {
+/*----------------------------------------------------------------------------
+    Set a pixel in the starry sky.
+-----------------------------------------------------------------------------*/
     if ((rand() % 1000) < starfraction) {
 #define StarQuality 0.5       /* Brightness distribution exponent */
 #define StarIntensity   8         /* Brightness scale factor */
@@ -494,7 +500,7 @@ static void etoile(pix)
             temp = 5500 + starcolor *
                 pow(1 / (1 - Cast(0, 0.9999)), StarTintExp) *
                 ((rand() & 7) ? -1 : 1);
-            /* Constrain temperature to a reasonable value: >= 2600K 
+            /* Constrain temperature to a reasonable value: >= 2600K
                (S Cephei/R Andromedae), <= 28,000 (Spica). */
             temp = MAX(2600, MIN(28000, temp));
             temprgb(temp, &r, &g, &b);
@@ -567,7 +573,7 @@ createPlanetStuff(bool             const clouds,
                   unsigned int **  const bxfP,
                   unsigned int **  const bxcP,
                   unsigned char ** const cpP,
-                  vector *         const sunvecP,
+                  Vector *         const sunvecP,
                   unsigned int     const cols,
                   pixval           const maxval) {
 
@@ -614,23 +620,23 @@ createPlanetStuff(bool             const clouds,
        (N.b. the pictures would undoubtedly look better when generated
        with small grids if  a  more  well-behaved  interpolation  were
        used.)
-       
+
        Also compute the line-level interpolation parameters that
-       caller will need every time around his inner loop.  
+       caller will need every time around his inner loop.
     */
 
     MALLOCARRAY(u,   cols);
     MALLOCARRAY(u1,  cols);
     MALLOCARRAY(bxf, cols);
     MALLOCARRAY(bxc, cols);
-    
-    if (u == NULL || u1 == NULL || bxf == NULL || bxc == NULL) 
+
+    if (u == NULL || u1 == NULL || bxf == NULL || bxc == NULL)
         pm_error("Cannot allocate %d element interpolation tables.", cols);
     {
         unsigned int j;
         for (j = 0; j < cols; j++) {
             double const bx = (n - 1) * uprj(j, cols);
-            
+
             bxf[j] = floor(bx);
             bxc[j] = MIN(bxf[j] + 1, n - 1);
             u[j] = bx - bxf[j];
@@ -645,15 +651,15 @@ createPlanetStuff(bool             const clouds,
 
 
 static void
-generateStarrySkyRow(pixel *      const pixels, 
+generateStarrySkyRow(pixel *      const pixels,
                      unsigned int const cols) {
 /*----------------------------------------------------------------------------
   Generate a starry sky.  Note  that no FFT is performed;
   the output is  generated  directly  from  a  power  law
-  mapping  of  a  pseudorandom sequence into intensities. 
+  mapping  of  a  pseudorandom sequence into intensities.
 -----------------------------------------------------------------------------*/
     unsigned int j;
-    
+
     for (j = 0; j < cols; j++)
         etoile(pixels + j);
 }
@@ -681,7 +687,7 @@ generateCloudRow(pixel *         const pixels,
     for (col = 0; col < cols; ++col) {
         double r;
         pixval w;
-        
+
         r = 0.0;  /* initial value */
         /* Note that where t1 and t are zero, the cp[] element
            referenced below does not exist.
@@ -692,9 +698,9 @@ generateCloudRow(pixel *         const pixels,
         if (t > 0.0)
             r += t * u1[col] * cp[byc + bxf[col]] +
                 t * u[col]  * cp[byc + bxc[col]];
-        
+
         w = (r > 127.0) ? (maxval * ((r - 127.0) / 128.0)) : 0;
-        
+
         PPM_ASSIGN(pixels[col], w, w, maxval);
     }
 }
@@ -747,11 +753,11 @@ makeLand(int *  const irP,
     };
 
     unsigned int const ix = ((r - 128) * (ARRAY_SIZE(pgnd) - 1)) / 127;
-    
+
     *irP = pgnd[ix][0];
     *igP = pgnd[ix][1];
     *ibP = pgnd[ix][2];
-} 
+}
 
 
 
@@ -781,9 +787,9 @@ addIce(int *  const irP,
        pixval const maxval) {
 
     /* Generate polar ice caps. */
-    
+
     double const icet = pow(fabs(sin(azimuth)), 1.0 / icelevel) - 0.5;
-    double const ice = MAX(0.0, 
+    double const ice = MAX(0.0,
                            (icet + glaciers * MAX(-0.5, (r - 128) / 128.0)));
     if  (ice > 0.125) {
         *irP = maxval;
@@ -802,11 +808,11 @@ limbDarken(int *          const irP,
            unsigned int   const row,
            unsigned int   const cols,
            unsigned int   const rows,
-           vector         const sunvec,
+           Vector         const sunvec,
            pixval         const maxval) {
 
     /* With Gcc 2.95.3 compiler optimization level > 1, I have seen this
-       function confuse all the variables and ultimately generate a 
+       function confuse all the variables and ultimately generate a
        completely black image.  Adding an extra reference to 'rows' seems
        to put things back in order, and the assert() below does that.
        Take it out, and the problem comes back!  04.02.21.
@@ -828,9 +834,9 @@ limbDarken(int *          const irP,
     double const dxsq = dx * dx;
 
     double const ds = MIN(1.0, sqrt(dxsq + dysq));
-    
+
     /* Calculate atmospheric absorption based on the thickness of
-       atmosphere traversed by light on its way to the surface.  
+       atmosphere traversed by light on its way to the surface.
     */
     double const dsq = ds * ds;
     double const dsat = atSatFac * ((sqrt(atthick * atthick - dsq) -
@@ -848,7 +854,7 @@ limbDarken(int *          const irP,
         double const svx = sunvec.x;
         double const svy = sunvec.y * dy;
         double const svz = sunvec.z * sqomdysq;
-        double const di = 
+        double const di =
             MAX(0, MIN(1.0, svx * dx + svy + svz * sqrt(1.0 - dxsq)));
         double const inx = PlanetAmbient * 1.0 + (1.0 - PlanetAmbient) * di;
 
@@ -874,7 +880,7 @@ generatePlanetRow(pixel *         const pixelrow,
                   unsigned int *  const bxf,
                   int             const byc,
                   int             const byf,
-                  vector          const sunvec,
+                  Vector          const sunvec,
                   pixval          const maxval) {
 
     unsigned int const StarClose = 2;
@@ -892,9 +898,9 @@ generatePlanetRow(pixel *         const pixelrow,
         int ir, ig, ib;
 
         r = 0.0;   /* initial value */
-        
+
         /* Note that where t1 and t are zero, the cp[] element
-           referenced below does not exist.  
+           referenced below does not exist.
         */
         if (t1 > 0.0)
             r += t1 * u1[col] * cp[byf + bxf[col]] +
@@ -903,9 +909,9 @@ generatePlanetRow(pixel *         const pixelrow,
             r += t * u1[col] * cp[byc + bxf[col]] +
                 t * u[col]  * cp[byc + bxc[col]];
 
-        if (r >= 128) 
+        if (r >= 128)
             makeLand(&ir, &ig, &ib, r);
-        else 
+        else
             makeWater(&ir, &ig, &ib, r, maxval);
 
         addIce(&ir, &ig, &ib, r, azimuth, icelevel, glaciers, maxval);
@@ -928,10 +934,10 @@ generatePlanetRow(pixel *         const pixelrow,
 
 
 
-static void 
+static void
 genplanet(bool         const stars,
           bool         const clouds,
-          float *      const a, 
+          float *      const a,
           unsigned int const cols,
           unsigned int const rows,
           unsigned int const n,
@@ -950,21 +956,21 @@ genplanet(bool         const stars,
     pixel *pixelrow;
     unsigned int row;
 
-    vector sunvec;
+    Vector sunvec;
 
     ppm_writeppminit(stdout, cols, rows, maxval, FALSE);
 
     if (stars) {
         pm_message("night: -seed %d -stars %d -saturation %d.",
                    rseed, starfraction, starcolor);
-        cp = NULL; 
+        cp = NULL;
         u = NULL; u1 = NULL;
         bxf = NULL; bxc = NULL;
     } else {
         pm_message("%s: -seed %d -dimension %.2f -power %.2f -mesh %d",
                    clouds ? "clouds" : "planet",
                    rseed, fracdim, powscale, meshsize);
-        createPlanetStuff(clouds, a, n, &u, &u1, &bxf, &bxc, &cp, &sunvec, 
+        createPlanetStuff(clouds, a, n, &u, &u1, &bxf, &bxc, &cp, &sunvec,
                           cols, maxval);
     }
 
@@ -983,7 +989,7 @@ genplanet(bool         const stars,
                 generateCloudRow(pixelrow, cols,
                                  t, t1, u, u1, cp, bxc, bxf, byc, byf,
                                  maxval);
-            else 
+            else
                 generatePlanetRow(pixelrow, row, rows, cols,
                                   t, t1, u, u1, cp, bxc, bxf, byc, byf,
                                   sunvec,
@@ -1009,7 +1015,7 @@ applyPowerLawScaling(float * const a,
                      double  const powscale) {
 
     /* Apply power law scaling if non-unity scale is requested. */
-    
+
     if (powscale != 1.0) {
         unsigned int i;
         for (i = 0; i < meshsize; i++) {
@@ -1030,7 +1036,7 @@ computeExtremeReal(const float * const a,
                    int           const meshsize,
                    double *      const rminP,
                    double *      const rmaxP) {
-    
+
     /* Compute extrema for autoscaling. */
 
     double rmin, rmax;
@@ -1043,7 +1049,7 @@ computeExtremeReal(const float * const a,
         unsigned int j;
         for (j = 0; j < meshsize; j++) {
             double r = Real(a, i, j);
-            
+
             rmin = MIN(rmin, r);
             rmax = MAX(rmax, r);
         }
@@ -1094,7 +1100,7 @@ planet(unsigned int const cols,
     bool error;
 
     initgauss(rseed);
-    
+
     if (stars) {
         a = NULL;
         error = FALSE;
@@ -1104,7 +1110,7 @@ planet(unsigned int const cols,
             error = TRUE;
         } else {
             applyPowerLawScaling(a, meshsize, powscale);
-                
+
             replaceWithSpread(a, meshsize);
 
             error = FALSE;
@@ -1121,7 +1127,7 @@ planet(unsigned int const cols,
 
 
 
-int 
+int
 main(int argc, const char ** argv) {
 
     struct CmdlineInfo cmdline;
@@ -1147,7 +1153,7 @@ main(int argc, const char ** argv) {
 
     /* Force  screen to be at least  as wide as it is high.  Long,
        skinny screens  cause  crashes  because  picture  width  is
-       calculated based on height.  
+       calculated based on height.
     */
 
     cols = (MAX(cmdline.height, cmdline.width) + 1) & (~1);
@@ -1157,3 +1163,6 @@ main(int argc, const char ** argv) {
 
     exit(success ? 0 : 1);
 }
+
+
+
diff --git a/lib/pbm.h b/lib/pbm.h
index a29adb48..27fd1163 100644
--- a/lib/pbm.h
+++ b/lib/pbm.h
@@ -75,14 +75,14 @@ pbm_readpbmrow(FILE * const file,
                int    const format);
 
 void
-pbm_readpbmrow_packed(FILE *          const file, 
+pbm_readpbmrow_packed(FILE *          const file,
                       unsigned char * const packedBits,
-                      int             const cols, 
+                      int             const cols,
                       int             const format);
 
 void
 pbm_readpbmrow_bitoffset(FILE *          const fileP,
-                         unsigned char * const packedBits, 
+                         unsigned char * const packedBits,
                          int             const cols,
                          int             const format,
                          unsigned int    const offset);
@@ -92,28 +92,28 @@ pbm_cleanrowend_packed(unsigned char * const packedBits,
                        unsigned int    const cols);
 
 void
-pbm_writepbminit(FILE * const fileP, 
-                 int    const cols, 
-                 int    const rows, 
+pbm_writepbminit(FILE * const fileP,
+                 int    const cols,
+                 int    const rows,
                  int    const forceplain);
 
 void
-pbm_writepbm(FILE * const fileP, 
-             bit ** const bits, 
-             int    const cols, 
-             int    const rows, 
+pbm_writepbm(FILE * const fileP,
+             bit ** const bits,
+             int    const cols,
+             int    const rows,
              int    const forceplain);
 
 void
-pbm_writepbmrow(FILE *      const fileP, 
-                const bit * const bitrow, 
-                int         const cols, 
+pbm_writepbmrow(FILE *      const fileP,
+                const bit * const bitrow,
+                int         const cols,
                 int         const forceplain);
 
 void
-pbm_writepbmrow_packed(FILE *                const fileP, 
+pbm_writepbmrow_packed(FILE *                const fileP,
                        const unsigned char * const packed_bits,
-                       int                   const cols, 
+                       int                   const cols,
                        int                   const forceplain);
 
 void
@@ -124,7 +124,7 @@ pbm_writepbmrow_bitoffset(FILE *          const ifP,
                           unsigned int    const offset);
 
 void
-pbm_check(FILE * file, const enum pm_check_type check_type, 
+pbm_check(FILE * file, const enum pm_check_type check_type,
           const int format, const int cols, const int rows,
           enum pm_check_code * const retval_p);
 
diff --git a/lib/pnm.h b/lib/pnm.h
index 0625cb5c..a8aad161 100644
--- a/lib/pnm.h
+++ b/lib/pnm.h
@@ -18,7 +18,18 @@ extern "C" {
 
 
 typedef pixel xel;
+    /* Xels come in three types: PBM, PGM, and PPM; the user of an Xel has to
+       know which as a matter of context (and like a pixel, the user also has
+       to interpret an xel in the context of a certain maxval).  Though the
+       structure is identical to 'pixel', the values are the same only for PPM
+       xels.  For a PGM xel, the 'r' and 'g' components of the 'xel' structure
+       are zero and the 'b' component is the gray level.  For a PBM xel, the
+       'r' and 'g' components are zero and the 'b' component is 0 for black
+       or maxval for white.
+    */
+
 typedef pixval xelval;
+
 #define PNM_OVERALLMAXVAL PPM_OVERALLMAXVAL
 #define PNM_MAXMAXVAL PPM_MAXMAXVAL
 #define pnm_unnormalize ppm_unnormalize
diff --git a/lib/util/runlength.c b/lib/util/runlength.c
index 62e3bf0c..8f60759d 100644
--- a/lib/util/runlength.c
+++ b/lib/util/runlength.c
@@ -29,7 +29,7 @@
   A survey of netpbm source code in 2015 found Packbits encoding in the
   following Netpbm programs: pbmtoescp2, pbmtomacp, pnmtopalm, pnmtopclxl,
   pnmtops, ppmtoilbm and ppmtopjxl.
- 
+
   Packbits is an option in the TIFF standard; pamtotiff can generate TIFF
   images that use Packbits compression, but does so via code in the TIFF
   library (not part of Netpbm).
@@ -47,7 +47,7 @@
 
   Today, all Netpbm programs that do Packbits compression with the exception
   of pamtotiff, pbmtoppa, pbmtogo and pamtotga use the facilities in this
-  file for it.  
+  file for it.
 =============================================================================*/
 
 #include <string.h>
@@ -71,7 +71,7 @@ static const char * const errorUndefinedMode =
    strings follow a single index or "flag" byte N.  There are several
    variations, differing in the format of the flag byte, maximum string
    length and element size (byte or word).
-   
+
    In the most widely used version, Packbits, the meaning of the flag byte
    N is defined as follows:
 
@@ -110,7 +110,7 @@ pm_rlenc_compressbyte(const unsigned char * const inbuf,
 
     int packBase;
     int packSign;
- 
+
     switch (mode) {
     case PM_RLE_PACKBITS:
         packBase = 257 ; packSign = -1; break;
@@ -128,7 +128,7 @@ pm_rlenc_compressbyte(const unsigned char * const inbuf,
             for (count = 0;
                  inCurs < inSize &&
                      inbuf[inCurs] == inbuf[hold] &&
-                     count < maxRun; 
+                     count < maxRun;
                  ++inCurs, ++count)
                 ;
             outbuf[outCurs++] = (unsigned char) (packBase + packSign * count);
@@ -139,7 +139,7 @@ pm_rlenc_compressbyte(const unsigned char * const inbuf,
             size_t count;
             ++outCurs;
             count = 0;
-            while(((inCurs + 2 >= inSize) && (inCurs < inSize) ) || 
+            while(((inCurs + 2 >= inSize) && (inCurs < inSize) ) ||
                   ((inCurs + 2 <  inSize) &&
                    ((inbuf[inCurs] != inbuf[inCurs+1]  )
                     || (inbuf[inCurs] != inbuf[inCurs+2]  ) ) )    ) {
@@ -242,7 +242,7 @@ pm_rlenc_compressword(const uint16_t   * const inbuf,
             outCurs += count * 2;
         }
     }
-    
+
     if (mode == PM_RLE_SGI16) {
         * (uint16_t *) &outbuf[outCurs] = 0;     /* terminator */
         outCurs += 2;
@@ -336,7 +336,7 @@ pm_rlenc_maxbytes(size_t          const inSize,  /* number of elements */
     size_t itemSize;   /* Size of item, in bytes */
     size_t miscSize;   /* Size of other elements such as term code, in bytes */
     size_t overhead;   /* Worst-case overhead, in bytes */
-    /* return value:      Worst-case output size, in bytes */ 
+    /* return value:      Worst-case output size, in bytes */
 
     switch (mode) {
     case PM_RLE_PACKBITS:
@@ -359,7 +359,7 @@ pm_rlenc_maxbytes(size_t          const inSize,  /* number of elements */
     default:
         pm_error(errorUndefinedMode, mode);
     }
-    
+
     overhead = miscSize +
         (inSize / blockSize + (inSize % blockSize > 0 ? 1 : 0) ) * flagSize;
 
diff --git a/lib/util/shhopt.c b/lib/util/shhopt.c
index ab489fef..c0b4ba47 100644
--- a/lib/util/shhopt.c
+++ b/lib/util/shhopt.c
@@ -394,7 +394,7 @@ static void
 optExecute(optEntry  const opt, char *arg, int lng)
 {
     if (opt.specified)
-        (*(opt.specified))++;
+        *opt.specified = 1;
 
     switch (opt.type) {
     case OPT_FLAG:
diff --git a/lib/util/shhopt.h b/lib/util/shhopt.h
index d9304f9f..03f40cc5 100644
--- a/lib/util/shhopt.h
+++ b/lib/util/shhopt.h
@@ -144,8 +144,8 @@ typedef struct {
            the rightmost one affects this return value.
         */
     unsigned int *specified;
-        /* pointer to variable in which to return the number of times that
-           the option was specified.  If NULL, don't return anything.
+        /* pointer to variable in which to return 1 if the option was
+           specified and 0 if it was not.  If NULL, don't return anything.
         */
     int        flags;      /* modifier flags. */
 } optEntry;
@@ -213,15 +213,23 @@ typedef struct {
 /* OPTENT3 is the same as OPTENTRY except that it also sets the "specified"
    element of the table entry (so it assumes OPTION_DEF is a table of optEntry
    instead of optStruct).  This is a pointer to a variable that the parser
-   will set to the number of times that the option appears in the command
-   line.
+   will set to and indication of whether the option appears in the command
+   line.  1 for yes; 0 for no.
+
+   HISTORICAL NOTE: Until 2019, this was the number of times the option was
+   specified, but much Netpbm code assumed it was never more than 1, and no
+   Netpbm code has ever given semantics to specifying the same option class
+   multiple times.
 
    Here is an example:
 
        unsigned int option_def_index = 0;
+       unsigned int help_flag;
+       const char * alpha_filename
+       unsigned int alpha_spec;
        MALLOCARRAY_NOFAIL(option_def, 100);
-       OPTENT3('h', "help",     OPT_FLAG, &help_flag, 0);
-       OPTENT3(0,   "alphaout", OPT_STRING, &alpha_filename, 0);
+       OPTENT3('h', "help",     OPT_FLAG,   &help_flag,      NULL);
+       OPTENT3(0,   "alphaout", OPT_STRING, &alpha_filename, &alpha_spec);
 */
 
 #define OPTENT3(shortvalue,longvalue,typevalue,outputvalue,specifiedvalue, \
diff --git a/test/Execute-Tests b/test/Execute-Tests
index 7a65d51f..3530d978 100755
--- a/test/Execute-Tests
+++ b/test/Execute-Tests
@@ -179,9 +179,10 @@ elif [ $VALGRIND_TESTS = "on" ]
  
   vg_command_base="valgrind --trace-children=yes";
 
-  for i in awk cat cksum cmp cp cut date dirname egrep fgrep file grep gs \
-    head iconv mkdir mktemp perl rm sed seq sh tee testrandom tr uniq \
-    Available-Testprog
+  for i in awk basename cat cksum cmp comm cp cut date dirname \
+           egrep fgrep file grep gs head iconv mkdir mktemp perl rm \
+           sed seq sh sort tee tr uniq wc \
+           testrandom Available-Testprog
 
     # Tell valgrind not to probe execution of the above programs.
 
diff --git a/test/Test-Order b/test/Test-Order
index 49eaeff2..e9ea1b55 100644
--- a/test/Test-Order
+++ b/test/Test-Order
@@ -22,6 +22,7 @@ ppmcie.test
 ppmwheel.test
 pamcrater.test
 ppmpat.test
+ppmforge-parameters.test
 
 # Generators with random components
 
@@ -53,6 +54,7 @@ pnmtopnm-plain.test
 # Editor tests
 
 pamditherbw.test
+pamhue.test
 
 pbmclean.test
 pamcut.test
@@ -89,6 +91,11 @@ pamenlarge-pamscale-point.test
 
 pamstretch.test
 
+pnmcrop1.test
+pnmcrop2.test
+pnmcrop3.test
+pnmcrop-blank.test
+
 ppmmix.test
 pammixmulti-identity.test
 
@@ -125,6 +132,7 @@ pamslice-roundtrip.test
 lookup-roundtrip.test
 enlarge-reduce-roundtrip.test
 cut-cat-roundtrip.test
+pamhue-roundtrip.test
 
 # Round-trip tests : lossless converters
 
diff --git a/test/bmp-quant-roundtrip.test b/test/bmp-quant-roundtrip.test
index 2c223b7c..9f1036d0 100755
--- a/test/bmp-quant-roundtrip.test
+++ b/test/bmp-quant-roundtrip.test
@@ -1,6 +1,6 @@
 #! /bin/bash
 # This script tests: bmptopnm ppmtobmp pnmquant
-# Also requires: ppmhist
+# Also requires:
 
 tmpdir=${tmpdir:-/tmp}
 quant_ppm=${tmpdir}/quant.ppm
diff --git a/test/g3-roundtrip.test b/test/g3-roundtrip.test
index 6e31c587..d18e4466 100755
--- a/test/g3-roundtrip.test
+++ b/test/g3-roundtrip.test
@@ -1,6 +1,6 @@
 #! /bin/bash
 # This script tests: g3topbm pbmtog3
-# Also requires: pnmcrop
+# Also requires: pnmcrop pbmmake
 
 tmpdir=${tmpdir:-/tmp}
 complete256_pbm=${tmpdir}/complete256.pbm
diff --git a/test/pad-crop-roundtrip.ok b/test/pad-crop-roundtrip.ok
index 67f7a1fe..0e712ce7 100644
--- a/test/pad-crop-roundtrip.ok
+++ b/test/pad-crop-roundtrip.ok
@@ -1,2 +1,4 @@
 1926073387 101484
+1926073387 101484
+2425386270 41
 2425386270 41
diff --git a/test/pad-crop-roundtrip.test b/test/pad-crop-roundtrip.test
index c7780d68..75979901 100755
--- a/test/pad-crop-roundtrip.test
+++ b/test/pad-crop-roundtrip.test
@@ -1,9 +1,18 @@
 #! /bin/bash
-# This script tests: pnmcrop pnmmargin
-# Also requires: pnmpad
-
+# This script tests: pnmcrop pnmmargin pnmpad
+# Also requires:
 
 pnmmargin -white 10 testimg.ppm | \
   pnmcrop | cksum
+
+pnmpad -white -left 10 -top 10 testimg.ppm | \
+  pnmpad -white -right 10 -bottom 10 | \
+  pnmcrop -right -bottom | pnmcrop -left -top | cksum
+
 pnmmargin -white 10 testgrid.pbm | \
   pnmcrop | cksum
+
+pnmpad -white -left 10 -top 10 testgrid.pbm | \
+  pnmpad -white -right 10 -bottom 10 | \
+  pnmcrop -left -right | pnmcrop -top -bottom | cksum
+
diff --git a/test/pamditherbw.ok b/test/pamditherbw.ok
index e8186c24..eba3c44c 100644
--- a/test/pamditherbw.ok
+++ b/test/pamditherbw.ok
@@ -1,4 +1,28 @@
+Test: simple threshold
 1316122660 33894
+Test: Hilbert
 3342429190 33894
+2905156049 33894
+4294967295 0
+339841328 33894
+1633267750 33894
+Test: Dither-8
 3325147568 33894
+Test: Cluster-3
 4124728025 33894
+Test: Cluster-4
+4124728025 33894
+Test: Cluster-8
+3493215477 33894
+Test: Invalid
+Expected failure 1
+Expected failure 2
+Expected failure 3
+Expected failure 4
+Expected failure 5
+Expected failure 6
+Expected failure 7
+Expected failure 8
+Expected failure 9
+Expected failure 10
+Expected failure 11
diff --git a/test/pamditherbw.test b/test/pamditherbw.test
index 3f377f81..7b646a88 100755
--- a/test/pamditherbw.test
+++ b/test/pamditherbw.test
@@ -2,31 +2,59 @@
 # This script tests: pamditherbw
 # Also requires: pamchannel pamtopnm
 
-
 tmpdir=${tmpdir:-/tmp}
 test_red=${tmpdir}/testimg.red
 
 # Test 1.  Simple threshold
+echo "Test: simple threshold"
+
 pamchannel -infile=testimg.ppm -tupletype="GRAYSCALE" 0 | pamtopnm | \
   tee ${test_red} | \
   pamditherbw -threshold -val=0.5 | cksum
 
-# Test 2.  Floyd-Steinberg
-#pamditherbw -floyd -val=0.5 ${test_red} | cksum
-
-# Test 3. Atkinson
-#pamditherbw -atkinson -val=0.5 ${test_red} | cksum
 
-# Test 4. Hilbert
+# Test 2. Hilbert
+echo "Test: Hilbert"
 pamditherbw -hilbert ${test_red} | cksum
+pamditherbw -hilbert -clump=4   ${test_red} | cksum
+pamditherbw -hilbert -clump=4 -threshold -value=0.5  ${test_red} | cksum
+pamditherbw -hilbert -clump=16  ${test_red} | cksum
+pamditherbw -hilbert -clump=100 ${test_red} | cksum
 
-# Test 5. Dither-8
+# Test 3. Dither-8
+echo "Test: Dither-8"
 pamditherbw -dither8 ${test_red} | cksum
 
-# Test 6. Cluster4
+# Test 4. Cluster-3
+echo "Test: Cluster-3"
+pamditherbw -cluster4 ${test_red} | cksum
+
+# Test 5. Cluster-4
+echo "Test: Cluster-4"
 pamditherbw -cluster4 ${test_red} | cksum
 
-# Test 7. Atkinson
-#pamditherbw -atkinson -val=0.5 ${test_red} | cksum
+# Test 6. Cluster-8
+echo "Test: Cluster-8"
+pamditherbw -cluster8 ${test_red} | cksum
+
+
+echo "Test: Invalid"
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pamditherbw -fs -atkinson       ${test_red} || echo "Expected failure 1"
+pamditherbw -floyd -atkinson    ${test_red} || echo "Expected failure 2"
+pamditherbw -dither8  -cluster3 ${test_red} || echo "Expected failure 3"
+pamditherbw -cluster3 -cluster4 ${test_red} || echo "Expected failure 4"
+pamditherbw -cluster3 -cluster8 ${test_red} || echo "Expected failure 5"
+pamditherbw -cluster4 -cluster8 ${test_red} || echo "Expected failure 6"
+pamditherbw -clump=8            ${test_red} || echo "Expected failure 7"
+pamditherbw -fs -clump=8        ${test_red} || echo "Expected failure 8"
+pamditherbw -hilbert -clump=1   ${test_red} || echo "Expected failure 9"
+pamditherbw -th -value=-1       ${test_red} || echo "Expected failure 10"
+pamditherbw -th -value=1.1      ${test_red} || echo "Expected failure 11"
 
-rm ${test_red}
+rm ${test_red}
\ No newline at end of file
diff --git a/test/pamfile.ok b/test/pamfile.ok
index c0d80c28..b1d68ae1 100644
--- a/test/pamfile.ok
+++ b/test/pamfile.ok
@@ -1,12 +1,19 @@
+Test 1
 testimg.ppm:	PPM raw, 227 by 149  maxval 255
 testgrid.pbm:	PBM raw, 14 by 16
 stdin:	PGM raw, 227 by 149  maxval 255
 stdin:	PAM, 227 by 149 by 1 maxval 255
     Tuple type: GRAYSCALE
+Test 2
 stdin:	3 images
 stdin:	Image 0:	PBM raw, 14 by 16
 stdin:	Image 1:	PBM raw, 14 by 16
 stdin:	Image 2:	PBM raw, 14 by 16
+Test 3
 227 149
 testimg.ppm: PPM RAW 227 149 3 255 RGB
 stdin: PBM RAW 14 16 1 1 BLACKANDWHITE
+Test 4
+Expected failure 1
+Expected failure 2
+Expected failure 3
diff --git a/test/pamfile.test b/test/pamfile.test
index 545a2289..32771bfe 100755
--- a/test/pamfile.test
+++ b/test/pamfile.test
@@ -2,15 +2,31 @@
 # This script tests: pamfile
 # Also requires: pamchannel pamtopnm
 
+echo "Test 1"
 
 pamfile testimg.ppm
 pamfile testgrid.pbm
 pamchannel -infile=testimg.ppm -tupletype="GRAYSCALE" 0 | pamtopnm | pamfile
 pamchannel -tupletype="GRAYSCALE" -infile=testimg.ppm 0 | pamfile
 
+echo "Test 2"
+
 cat testgrid.pbm testgrid.pbm testgrid.pbm | pamfile -count
 cat testgrid.pbm testgrid.pbm testgrid.pbm | pamfile -allimages
 
+echo "Test 3"
+
 pamfile -size testimg.ppm
 pamfile -machine testimg.ppm
 cat testgrid.pbm testimg.ppm testgrid.pbm | pamfile -machine
+
+echo "Test 4"
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pamfile -size -machine  testimg.ppm || echo "Expected failure 1"
+pamfile -count -machine testimg.ppm || echo "Expected failure 2"
+head -n1 testimg.ppm | pamfile || echo "Expected failure 3"
\ No newline at end of file
diff --git a/test/pamfind.ok b/test/pamfind.ok
index dc0f95ed..9ddddced 100644
--- a/test/pamfind.ok
+++ b/test/pamfind.ok
@@ -20,6 +20,14 @@ Locations containing tuple (210/57/41)/255:
 (101, 77)
 (101, 78)
 (102, 72)
+118 195
+137 176
+137 177
+137 178
+138 183
+139 205
+140 188
+144 199
 Test 2
 Locations containing tuple (1)/1:
 (0, 1)
@@ -78,6 +86,176 @@ Locations containing tuple (1)/1:
 (14, 9)
 (14, 11)
 (14, 13)
+00 00
+00 02
+00 04
+00 06
+00 08
+00 10
+00 12
+01 00
+01 01
+01 02
+01 03
+01 04
+01 05
+01 06
+01 07
+01 08
+01 09
+01 10
+01 11
+01 12
+01 13
+02 00
+02 02
+02 04
+02 06
+02 08
+02 10
+02 12
+03 00
+03 01
+03 02
+03 03
+03 04
+03 05
+03 06
+03 07
+03 08
+03 09
+03 10
+03 11
+03 12
+03 13
+04 00
+04 02
+04 04
+04 06
+04 08
+04 10
+04 12
+05 00
+05 01
+05 02
+05 03
+05 04
+05 05
+05 06
+05 07
+05 08
+05 09
+05 10
+05 11
+05 12
+05 13
+06 00
+06 02
+06 04
+06 06
+06 08
+06 10
+06 12
+07 00
+07 01
+07 02
+07 03
+07 04
+07 05
+07 06
+07 07
+07 08
+07 09
+07 10
+07 11
+07 12
+07 13
+08 00
+08 02
+08 04
+08 06
+08 08
+08 10
+08 12
+09 00
+09 01
+09 02
+09 03
+09 04
+09 05
+09 06
+09 07
+09 08
+09 09
+09 10
+09 11
+09 12
+09 13
+10 00
+10 02
+10 04
+10 06
+10 08
+10 10
+10 12
+11 00
+11 01
+11 02
+11 03
+11 04
+11 05
+11 06
+11 07
+11 08
+11 09
+11 10
+11 11
+11 12
+11 13
+12 00
+12 02
+12 04
+12 06
+12 08
+12 10
+12 12
+13 00
+13 01
+13 02
+13 03
+13 04
+13 05
+13 06
+13 07
+13 08
+13 09
+13 10
+13 11
+13 12
+13 13
+14 00
+14 02
+14 04
+14 06
+14 08
+14 10
+14 12
+15 00
+15 01
+15 02
+15 03
+15 04
+15 05
+15 06
+15 07
+15 08
+15 09
+15 10
+15 11
+15 12
+15 13
 Test 3
 okay
 okay
+Test 4
+expected error
diff --git a/test/pamfind.test b/test/pamfind.test
index 39cb1437..e55f290c 100755
--- a/test/pamfind.test
+++ b/test/pamfind.test
@@ -10,10 +10,12 @@ sorted1_res=${tmpdir}/pamfind_sorted1.res
 echo Test 1
 pamfind -color=grey17     testimg.ppm 
 pamfind -target=210,57,41 testimg.ppm
+pamfind -target=50,55,49 -machine testimg.ppm
 
 # Test 2
 echo Test 2
 pamfind -target=1 testgrid.pbm
+pamfind -target=0 -machine testgrid.pbm
 
 # Test 3
 # The two outputs should be disjoint
@@ -29,4 +31,13 @@ comm -12 ${sorted0_res}  ${sorted1_res} |
 
 rm ${sorted0_res} ${sorted1_res}
 
+# Test 4
 
+echo 1>&2
+echo "Invalid command-line argument combination." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+echo Test 4
+pamfind -color=black -target=1 testimg.ppm || \
+  echo expected error
diff --git a/test/pamgauss.ok b/test/pamgauss.ok
index 153d4f6e..eaef2570 100644
--- a/test/pamgauss.ok
+++ b/test/pamgauss.ok
@@ -1,3 +1,4 @@
+Test 1
 3712518499 55
 3712518499 55
 1147844094 55
@@ -79,3 +80,12 @@
 4102007360 169
 3022719594 169
 1769176609 169
+Test 2
+stdin:	PAM, 3 by 3 by 1 maxval 255
+    Tuple type: GRAYSCALE
+Test 3.
+Expected error 1
+Expected error 2
+Expected error 3
+Expected error 4
+Expected error 5
diff --git a/test/pamgauss.test b/test/pamgauss.test
index b48517c4..392b5179 100755
--- a/test/pamgauss.test
+++ b/test/pamgauss.test
@@ -1,7 +1,8 @@
 #! /bin/bash
 # This script tests: pamgauss
-# Also requires:
+# Also requires: pamfile
 
+echo "Test 1"
 
 for i in `seq 3 11`
 do
@@ -10,3 +11,21 @@ do
 pamgauss $i $i -oversample=1 -sigma=.$s | cksum
 done
 done
+
+echo "Test 2"
+
+pamgauss 3 3 -sigma=0.5 -tupletype="GRAYSCALE" | pamfile
+
+
+echo "Test 3."
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pamgauss 3 3               | echo "Expected error 1"
+pamgauss 3 3   -sigma=0    | echo "Expected error 2"
+pamgauss 3 3   -sigma=-1.5 | echo "Expected error 3"
+pamgauss 3     -sigma=0.5  | echo "Expected error 4"
+pamgauss 3 3 3 -sigma=0.5  | echo "Expected error 5"
diff --git a/test/pamhue-roundtrip.ok b/test/pamhue-roundtrip.ok
new file mode 100644
index 00000000..b341398c
--- /dev/null
+++ b/test/pamhue-roundtrip.ok
@@ -0,0 +1,10 @@
+input image
+1926073387 101484
+360
+1926073387 101484
+180
+1926073387 101484
+120
+1926073387 101484
+60
+1926073387 101484
diff --git a/test/pamhue-roundtrip.test b/test/pamhue-roundtrip.test
new file mode 100755
index 00000000..643ac99a
--- /dev/null
+++ b/test/pamhue-roundtrip.test
@@ -0,0 +1,19 @@
+#! /bin/bash
+# This script tests: pamhue
+# Also requires:
+
+echo input image
+cat testimg.ppm | cksum
+
+echo 360
+pamhue -huechange=360 testimg.ppm | cksum
+echo 180
+pamhue -huechange=180 testimg.ppm | pamhue -huechange=180 | cksum
+echo 120
+pamhue -huechange=120 testimg.ppm | pamhue -huechange=120 | \
+  pamhue -huechange=120 | cksum
+echo 60
+pamhue -huechange=60 testimg.ppm | pamhue -huechange=60 | \
+  pamhue -huechange=60 | pamhue -huechange=60 | \
+  pamhue -huechange=60 | pamhue -huechange=60 | cksum
+
diff --git a/test/pamhue.ok b/test/pamhue.ok
new file mode 100644
index 00000000..447759ba
--- /dev/null
+++ b/test/pamhue.ok
@@ -0,0 +1,25 @@
+1213482165 83
+ Summary: 8 colors: 1 black, 1 white, 0 gray, 6 color
+
+   r     g     b   	 lum 	 count  
+ ----- ----- ----- 	-----	------- 
+     0     0     0	    0	      1 
+     0     0   255	   29	      1 
+   255   255     0	  226	      1 
+   255   255   255	  255	      1 
+     0   255     0	  150	      1 
+     0   255   255	  179	      1 
+   255     0     0	   76	      1 
+   255     0   255	  105	      1 
+ Summary: 8 colors: 1 black, 1 white, 0 gray, 6 color
+
+   r     g     b   	 lum 	 count  
+ ----- ----- ----- 	-----	------- 
+     0     0     0	    0	      1 
+     0     0   255	   29	      1 
+   255   255     0	  226	      1 
+   255   255   255	  255	      1 
+     0   255     0	  150	      1 
+     0   255   255	  179	      1 
+   255     0     0	   76	      1 
+   255     0   255	  105	      1 
diff --git a/test/pamhue.test b/test/pamhue.test
new file mode 100755
index 00000000..544b1d32
--- /dev/null
+++ b/test/pamhue.test
@@ -0,0 +1,10 @@
+#! /bin/bash
+# This script tests: pamhue
+# Also requires: pamseq ppmhist pamdepth
+
+pamseq -tupletype=RGB 3 1 | pamdepth 255 | pamhue -huechange=60 | cksum
+
+pamseq -tupletype=RGB 3 1 | pamdepth 255 | ppmhist
+pamseq -tupletype=RGB 3 1 | pamdepth 255 | pamhue -huechange=60 | ppmhist
+
+
diff --git a/test/pamscale-filters3.ok b/test/pamscale-filters3.ok
index 94d4ae96..182700cd 100644
--- a/test/pamscale-filters3.ok
+++ b/test/pamscale-filters3.ok
@@ -1,4 +1,3 @@
-failure : 0
 3.96 hermite:
 match
 match
diff --git a/test/pamscale-filters3.test b/test/pamscale-filters3.test
index 83198e2b..5a865508 100755
--- a/test/pamscale-filters3.test
+++ b/test/pamscale-filters3.test
@@ -1,7 +1,6 @@
 #! /bin/bash
 # This script tests: pamscale pamstretch pamstretch-gen 
- # Also requires: pamvalidate pnmpsnr || \
-  echo failure ${PIPESTATUS[@]} ":" $?
+# Also requires: pamvalidate pnmpsnr
 
 tmpdir=${tmpdir:-/tmp}
 stretch_ppm=${tmpdir}/stretch.ppm
diff --git a/test/pamseq.ok b/test/pamseq.ok
index 52bb3dd8..b0455449 100644
--- a/test/pamseq.ok
+++ b/test/pamseq.ok
@@ -1 +1,7 @@
+Test 1
 3929266994 304
+Test 2
+Expected error 1
+Expected error 2
+Expected error 3
+Expected error 4
diff --git a/test/pamseq.test b/test/pamseq.test
index e7b8060d..ea19013b 100755
--- a/test/pamseq.test
+++ b/test/pamseq.test
@@ -2,5 +2,24 @@
 # This script tests: pamseq
 # Also requires:
 
+echo "Test 1"
 
 pamseq 1 255 | cksum
+
+echo "Test 2"
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pamseq 1 || echo "Expected error 1"
+pamseq 0 255 || echo "Expected error 2"
+pamseq 3 0   || echo "Expected error 3"
+
+c64="0123456789012345678901234567890123456789012345678901234567890123"
+c256=${c64}${c64}${c64}${c64}
+
+# Tupletype string length=256
+
+pamseq -tupletype="${c256}" 3 15 || echo "Expected error 4"
diff --git a/test/pamsumm.ok b/test/pamsumm.ok
index 0643081b..24ae23d2 100644
--- a/test/pamsumm.ok
+++ b/test/pamsumm.ok
@@ -1,8 +1,15 @@
+Test 1
 56
 0
 1
 0.250000
+Test 2
 10772432
 15
 255
 106.164760
+Test 3
+Expected failure 1
+Expected failure 2
+the mean of all samples is 106.164760
+Expected failure 4
diff --git a/test/pamsumm.test b/test/pamsumm.test
index a99dea0e..882b1b14 100755
--- a/test/pamsumm.test
+++ b/test/pamsumm.test
@@ -2,13 +2,29 @@
 # This script tests: pamsumm
 # Also requires:
 
+echo "Test 1"
 
 for type in -sum -min -max -mean
   do
   pamsumm -brief $type testgrid.pbm
   done
 
+echo "Test 2"
+
 for type in -sum -min -max -mean
   do
   pamsumm -brief $type testimg.ppm
   done
+
+
+echo "Test 3"
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pamsumm -sum -min  testimg.ppm || echo "Expected failure 1"
+pamsumm -sum -max  testimg.ppm || echo "Expected failure 2"
+pamsumm -mean -max testimg.ppm || echo "Expected failure 3"
+pamsumm            testimg.ppm || echo "Expected failure 4"
diff --git a/test/pamtable.test b/test/pamtable.test
index 5c66b7ae..335d45c4 100755
--- a/test/pamtable.test
+++ b/test/pamtable.test
@@ -1,6 +1,6 @@
 #! /bin/bash
 # This script tests: pamtable
-# Also requires: pamgradient pamseq pamdepth
+# Also requires: pamseq pamdepth pbmmake ppmrainbow
 
 pamtable testgrid.pbm
 echo
diff --git a/test/pbm-misc-converters.test b/test/pbm-misc-converters.test
index aa71489b..ad96f13c 100755
--- a/test/pbm-misc-converters.test
+++ b/test/pbm-misc-converters.test
@@ -3,7 +3,7 @@
 # This script tests: pbmtodjvurle pbmtoepson pbmtogo pbmtoibm23xx
 # This script tests: pbmtolj pbmtoln03 pbmtomatrixorbital pbmtonokia
 # This script tests: pbmtoplot pbmtoptx pbmtozinc
-# Also requires: pbmpage
+# Also requires: pbmpage pbmtoppa
 
 # Note: one-way test.
 # These converters do not have counterparts that work in the opposite
diff --git a/test/pbmclean.ok b/test/pbmclean.ok
index 71b622d0..47d6c07d 100644
--- a/test/pbmclean.ok
+++ b/test/pbmclean.ok
@@ -1,3 +1,4 @@
+Test 1
 P1
 7 7
 1111111
@@ -70,4 +71,16 @@ P1
 0000000
 0000000
 0000000
+Test 2
 760076056 4210813
+Test 3
+2096087149 5051
+2096087149 5051
+3762787431 5051
+1966718 5051
+544084261 5051
+2970762900 5051
+2571756059 5051
+2571756059 5051
+436062787 5051
+4188415575 5051
diff --git a/test/pbmclean.test b/test/pbmclean.test
index a8e469b1..b9ea0937 100755
--- a/test/pbmclean.test
+++ b/test/pbmclean.test
@@ -1,19 +1,36 @@
 #! /bin/bash
 # This script tests: pbmclean
-# Also requires: pbmmake pbmpage pnmmargin pnmpad
+# Also requires: pbmmake pbmpage pbmtext pnmmargin pnmpad
 
 
 tmpdir=${tmpdir:-/tmp}
 test_pbm=${tmpdir}/test.pbm
+sheet_pbm=${tmpdir}/sheet.pbm
+
+echo "Test 1"
 
 pbmmake -g 3 3 | pnmmargin -black 2 > ${test_pbm}
 
 for n in 1 2 3 4 5 6 7 8
-do
-pbmclean -min=$n -black -plain ${test_pbm}
-done
+  do
+  pbmclean -min=${n} -black -plain ${test_pbm}
+  done
 
 rm ${test_pbm}
 
+
+echo "Test 2"
+
 # Should print 760076056 4210813
 pbmpage 1 | pbmclean -black | cksum
+
+
+echo "Test 3"
+
+pbmtext -dump-sheet > ${sheet_pbm}
+for n in 1 2 3 4 5 6 7 8 9 10
+  do
+  pbmclean -min=${n} -extended  ${sheet_pbm} | cksum
+  done
+
+rm ${sheet_pbm}
diff --git a/test/pbmmake.ok b/test/pbmmake.ok
index 754eefdf..354106f0 100644
--- a/test/pbmmake.ok
+++ b/test/pbmmake.ok
@@ -1,27 +1,36 @@
+Test 1.
 P11 10
 P11 11
 P11 10
+Test 2.
 P12 20000
 P12 21111
 P12 20110
+Test 2.
 P13 3000000000
 P13 3111111111
 P13 3010101010
+Test 2.
 P14 40000000000000000
 P14 41111111111111111
 P14 40101101001011010
+Test 2.
 P15 50000000000000000000000000
 P15 51111111111111111111111111
 P15 50101010101010101010101010
+Test 2.
 P16 6000000000000000000000000000000000000
 P16 6111111111111111111111111111111111111
 P16 6010101101010010101101010010101101010
+Test 2.
 P17 70000000000000000000000000000000000000000000000000
 P17 71111111111111111111111111111111111111111111111111
 P17 70101010101010101010101010101010101010101010101010
+Test 2.
 P18 80000000000000000000000000000000000000000000000000000000000000000
 P18 81111111111111111111111111111111111111111111111111111111111111111
 P18 80101010110101010010101011010101001010101101010100101010110101010
+Test 2.
 4058563256 45
 3969089344 105
 702117756 189
@@ -41,3 +50,15 @@ P18 80101010110101010010101011010101001010101101010100101010110101010
 1824232358 2931
 3651864954 3375
 3302595397 3849
+Test 3.
+Expected error 1
+Expected error 2
+Expected error 3
+Expected error 4
+Expected error 5
+Expected error 6
+Expected error 7
+Expected error 8
+P1
+1 1
+0
diff --git a/test/pbmmake.test b/test/pbmmake.test
index 4b18e3ea..eb4be6ea 100755
--- a/test/pbmmake.test
+++ b/test/pbmmake.test
@@ -2,13 +2,17 @@
 # This script tests: pbmmake
 # Also requires:
 
+echo "Test 1."
 
 for i in `seq 1 8`
 do
-for color in -w -b -g
+for color in -white -black -gray
 do
 pbmmake -plain $color $i $i | tr -d '\n'; echo
 done
+
+echo "Test 2."
+
 done
 for i in `seq 8 5 98`
 do
@@ -16,3 +20,20 @@ do
   pbmmake -b $i $i ;
   pbmmake  -g $i $i ) | cksum
 done
+
+echo "Test 3."
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pbmmake -b -w -plain 1 1 || echo "Expected error 1"
+pbmmake -b -g -plain 1 1 || echo "Expected error 2"
+pbmmake -white -gray -plain 1 1 || echo "Expected error 3"
+pbmmake -white -plain   || echo "Expected error 4"
+pbmmake -white -plain 1 || echo "Expected error 5"
+pbmmake -white -plain 1 0 || echo "Expected error 6"
+pbmmake -white -plain 0 1 || echo "Expected error 7"
+pbmmake -white -plain 1 1 1 || echo "Expected error 8"
+pbmmake -plain 1 1 ||  echo "Expected error 9"
diff --git a/test/pbmpage.ok b/test/pbmpage.ok
index 7f68da74..b41d7cf3 100644
--- a/test/pbmpage.ok
+++ b/test/pbmpage.ok
@@ -1,3 +1,9 @@
+Test 1
 550172004 4210813
 4142746975 4210813
 2347597649 4210813
+3453559794 4349933
+Test 2
+Expected error 1
+Expected error 2
+Expected error 3
diff --git a/test/pbmpage.test b/test/pbmpage.test
index e9bfe352..7cabcc7f 100755
--- a/test/pbmpage.test
+++ b/test/pbmpage.test
@@ -2,7 +2,20 @@
 # This script tests: pbmpage
 # Also requires:
 
+echo "Test 1"
 
-pbmpage 1 | cksum
-pbmpage 2 | cksum
-pbmpage 3 | cksum
+pbmpage 1     | cksum
+pbmpage 2     | cksum
+pbmpage 3     | cksum
+pbmpage -a4 2 | cksum
+
+echo "Test 2"
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pbmpage -a3 1 || echo "Expected error 1"
+pbmpage 0 || echo "Expected error 2"
+pbmpage 4 || echo "Expected error 3"
diff --git a/test/pbmupc.ok b/test/pbmupc.ok
index 3e58f409..c5753609 100644
--- a/test/pbmupc.ok
+++ b/test/pbmupc.ok
@@ -1 +1,12 @@
+Test 1
 2619309127 10172
+Test 2
+Exptected error 1
+Exptected error 2
+Exptected error 3
+Exptected error 4
+Exptected error 5
+Exptected error 6
+Exptected error 7
+Exptected error 8
+Exptected error 9
diff --git a/test/pbmupc.test b/test/pbmupc.test
index 275117d5..aee380b0 100755
--- a/test/pbmupc.test
+++ b/test/pbmupc.test
@@ -2,8 +2,26 @@
 # This script tests: pbmupc
 # Also requires:
 
+echo "Test 1"
 
 for type in -s1 -s2
 do
 pbmupc $type 0 72890 00011
 done | cksum
+
+echo "Test 2"
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pbmupc -s3 0 72890 00011     || echo "Exptected error 1"
+pbmupc -s1   72890 00011     || echo "Exptected error 2"
+pbmupc -s1 0 72890           || echo "Exptected error 3"
+pbmupc -s1 10 72890 00011    || echo "Exptected error 4"
+pbmupc -s1 0 172890 00011    || echo "Exptected error 5"
+pbmupc -s1 0   2890 00011    || echo "Exptected error 6"
+pbmupc -s1 0 72890 100011    || echo "Exptected error 7"
+pbmupc -s1 0 72890   0011    || echo "Exptected error 8"
+pbmupc -s1 0 72890 100011 1  || echo "Exptected error 9"
diff --git a/test/pdb-roundtrip.test b/test/pdb-roundtrip.test
index 6b4e152c..32d7aa87 100755
--- a/test/pdb-roundtrip.test
+++ b/test/pdb-roundtrip.test
@@ -1,6 +1,6 @@
 #! /bin/bash
 # This script tests: pamtopdbimg pdbimgtopam
-# Also requires: pnmtile pgmramp pamtopnm
+# Also requires: pnmtile pgmramp pamtopnm pamdepth
 
 tmpdir=${tmpdir:-/tmp}
 tiled_pbm=${tmpdir}/tiled.pbm
diff --git a/test/pgmhist.ok b/test/pgmhist.ok
index 7d89bb33..6d9dfbe5 100644
--- a/test/pgmhist.ok
+++ b/test/pgmhist.ok
@@ -1,3 +1,4 @@
+Test 1
 value count b% w%
 ----- ----- ------ ------
  0 2 12.5% 100%
@@ -12,3 +13,24 @@ value count b% w%
 ----- ----- ------ ------
  0 168 75% 100%
  255 56 100% 25%
+Test 2
+127
+63
+127
+191
+255
+25
+51
+76
+102
+127
+153
+179
+204
+230
+255
+Test 3
+Expected failure 1
+Expected failure 2
+Expected failure 3
+Expected failure 4
diff --git a/test/pgmhist.test b/test/pgmhist.test
index 42666fbf..c566c5cb 100755
--- a/test/pgmhist.test
+++ b/test/pgmhist.test
@@ -5,8 +5,33 @@
 
 # Ignore differences in spaces.
 
+echo "Test 1"
+
 pgmramp -maxval=8 -lr 8 2 | pgmhist | \
   sed -e 's/  */ /g' -e 's/ *$//'
 
 pgmhist testgrid.pbm | \
   sed -e 's/  */ /g' -e 's/ *$//'
+
+echo "Test 2"
+
+pgmramp -lr 256 1 | pgmhist -machine -median   | \
+  sed -e 's/  */ /g' -e 's/ *$//'
+
+pgmramp -lr 256 1 | pgmhist -machine -quartile | \
+  sed -e 's/  */ /g' -e 's/ *$//'
+
+pgmramp -lr 256 1 | pgmhist -machine -decile   | \
+  sed -e 's/  */ /g' -e 's/ *$//'
+
+echo "Test 3"
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pgmhist -median   -quartile testgrid.pbm || echo "Expected failure 1"
+pgmhist -median   -decile   testgrid.pbm || echo "Expected failure 2"
+pgmhist -quartile -decile   testgrid.pbm || echo "Expected failure 3"
+pgmhist testimg.ppm || echo "Expected failure 4"
diff --git a/test/pgmmake.ok b/test/pgmmake.ok
index b9a03af2..9a88b9a6 100644
--- a/test/pgmmake.ok
+++ b/test/pgmmake.ok
@@ -1,2 +1,12 @@
+Test 1.
 3662611538 2513
 3109612402 5012
+Test 2.
+Expected error 1
+Expected error 2
+Expected error 3
+Expected error 4
+Expected error 5
+Expected error 6
+Expected error 7
+Expected error 8
diff --git a/test/pgmmake.test b/test/pgmmake.test
index 4a3c4842..3823e36f 100755
--- a/test/pgmmake.test
+++ b/test/pgmmake.test
@@ -2,6 +2,25 @@
 # This script tests: pgmmake
 # Also requires:
 
+echo "Test 1."
 
 pgmmake 1 50 50 | cksum
 pgmmake .2 50 100 -maxval=5 | cksum
+
+
+echo "Test 2."
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pgmmake 100  5 5 || echo "Expected error 1"
+pgmmake 1.01 5 5 || echo "Expected error 2"
+pgmmake .5   5   || echo "Expected error 3"
+pgmmake .5       || echo "Expected error 4"
+pgmmake -maxval=5        5 5 || echo "Expected error 5"
+pgmmake -maxval=0     .5 5 5 || echo "Expected error 6"
+pgmmake -maxval=-1    .5 5 5 || echo "Expected error 7"
+pgmmake -maxval=65536 .5 5 5 || echo "Expected error 8"
+
diff --git a/test/pgmramp.ok b/test/pgmramp.ok
index 989ef7d4..309f5773 100644
--- a/test/pgmramp.ok
+++ b/test/pgmramp.ok
@@ -1,3 +1,4 @@
+Test 1
 P2
 4 4
 6
@@ -33,8 +34,16 @@ P2
 1 2 3 4
 2 3 4 5
 3 4 5 6
+Test 2
 1777787286 65551
 2046889993 65551
 1975520432 65551
 807973067 65551
+Test 3
 886972785 131087
+Test 4
+Expected error: -lr -tb
+Expected error: -lr -rectangle
+Expected error: -rectangle -ellipse
+Expected error: insufficient parameters
+Expected error: excessive parameters
diff --git a/test/pgmramp.test b/test/pgmramp.test
index f6f770fe..bd63e10d 100755
--- a/test/pgmramp.test
+++ b/test/pgmramp.test
@@ -2,14 +2,33 @@
 # This script tests: pgmramp
 # Also requires:
 
+echo "Test 1"
 
 for type in -lr -tb -rectangle -ellipse -diagonal
 do
 pgmramp -maxval=6 $type 4 4 -plain
 done
 
+echo "Test 2"
+
 for type in -lr -tb -rectangle -ellipse
 do pgmramp $type 256 256 | cksum
 done
 
+echo "Test 3"
+
 pgmramp -diagonal -maxval=510 256 256 | cksum
+
+echo "Test 4"
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+for combination in "-lr -tb" "-lr -rectangle" "-rectangle -ellipse"
+do pgmramp $combination 10 10 || echo "Expected error: $combination"
+done
+
+pgmramp -lr     1 || echo "Expected error: insufficient parameters"
+pgmramp -tb 1 1 1 || echo "Expected error: excessive parameters"
diff --git a/test/pnmcrop-blank.ok b/test/pnmcrop-blank.ok
new file mode 100644
index 00000000..55103acb
--- /dev/null
+++ b/test/pnmcrop-blank.ok
@@ -0,0 +1,130 @@
+Test 1
+-blank-image=pass
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+-blank-image=minimize
+-7 -7 -7 -6 1 1
+0 0 0 0 15 14
+-7 -7 -7 -6 1 1
+-7 -7 -7 -6 1 1
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+-7 -7 -7 -6 1 1
+-blank-image=minimize -top
+0 0 -13 0 15 1
+0 0 0 0 15 14
+0 0 -13 0 15 1
+0 0 -13 0 15 1
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 -13 0 15 1
+-blank-image=minimize -bottom
+0 0 0 -13 15 1
+0 0 0 0 15 14
+0 0 0 -13 15 1
+0 0 0 -13 15 1
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 -13 15 1
+-blank-image=minimize -left
+-14 0 0 0 1 14
+0 0 0 0 15 14
+-14 0 0 0 1 14
+-14 0 0 0 1 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+-14 0 0 0 1 14
+-blank-image=minimize -right
+0 -14 0 0 1 14
+0 0 0 0 15 14
+0 -14 0 0 1 14
+0 -14 0 0 1 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 -14 0 0 1 14
+-blank-image=minimize -left -right
+-7 -7 0 0 1 14
+0 0 0 0 15 14
+-7 -7 0 0 1 14
+-7 -7 0 0 1 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+-7 -7 0 0 1 14
+-blank-image=maxcrop
+-15 -15 -14 -14 15 14
+0 0 0 0 15 14
+-15 -15 -14 -14 15 14
+-15 -15 -14 -14 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+0 0 0 0 15 14
+-15 -15 -14 -14 15 14
+-blank-image=abort
+fail1
+fail2
+0 0 0 0 15 14
+0 0 0 0 15 14
+fail3
+
+fail1
+fail2
+0 0 0 0 15 14
+0 0 0 0 15 14
+fail3
+Test 2
+-blank-image=maxcrop -top
+0 0 -99 0 100 99
+0 0 -99 0 100 99
+0 0 0 0 100 99
+-blank-image=minimize
+-50 -49 -49 -49 1 1
+-50 -49 -49 -49 1 1
+0 0 0 0 100 99
+-blank-image=maxcrop
+-100 -100 -99 -99 100 99
+-100 -100 -99 -99 100 99
+0 0 0 0 100 99
+-blank-image=maxcrop -top
+0 0 -99 0 100 99
+0 0 -99 0 100 99
+0 0 0 0 100 99
+-blank-image=maxcrop -bottom
+0 0 0 -99 100 99
+0 0 0 -99 100 99
+0 0 0 0 100 99
+-blank-image=maxcrop -left
+-100 0 0 0 100 99
+-100 0 0 0 100 99
+0 0 0 0 100 99
+-blank-image=maxcrop -right
+0 -100 0 0 100 99
+0 -100 0 0 100 99
+0 0 0 0 100 99
+-blank-image=maxcrop -top -bottom -right
+0 -100 -99 -99 100 99
+0 -100 -99 -99 100 99
+0 0 0 0 100 99
+
+fail4
+fail5
+0 0 0 0 100 99
diff --git a/test/pnmcrop-blank.test b/test/pnmcrop-blank.test
new file mode 100755
index 00000000..087ad65e
--- /dev/null
+++ b/test/pnmcrop-blank.test
@@ -0,0 +1,55 @@
+#! /bin/bash
+# This script tests: pnmcrop
+# Also requires: pbmmake ppmmake
+
+tmpdir=${tmpdir:-/tmp}
+
+test_pbm=${tmpdir}/test.pbm
+test_ppm=${tmpdir}/test.ppm
+
+echo "Error messages should appear below the line." 1>&2
+echo "--------------------------------------------" 1>&2
+
+#Test 1
+echo Test 1
+
+( pbmmake -white 15 14; pbmmake -gray 15 14; pbmmake -black 15 14 ) > \
+  ${test_pbm}
+for type in    "-blank-image=pass" \
+               "-blank-image=minimize" \
+               "-blank-image=minimize -top" \
+               "-blank-image=minimize -bottom" \
+               "-blank-image=minimize -left" \
+               "-blank-image=minimize -right" \
+               "-blank-image=minimize -left -right" \
+               "-blank-image=maxcrop" \
+               "-blank-image=abort" ""
+  do
+  echo ${type}
+  pnmcrop -reportsize ${type} ${test_pbm} || echo "fail1"
+  pnmcrop -reportsize ${type} -white ${test_pbm} || echo "fail2"
+  pnmcrop -reportsize ${type} -black ${test_pbm} || echo "fail3"
+  done
+
+rm ${test_pbm}
+
+
+#Test 2
+
+ppmmake rgb:ff/ff/ff 100 99 > ${test_ppm}
+echo Test 2
+for type in    "-blank-image=maxcrop -top" \
+               "-blank-image=minimize" "-blank-image=maxcrop" \
+               "-blank-image=maxcrop -top" \
+               "-blank-image=maxcrop -bottom" \
+               "-blank-image=maxcrop -left" \
+               "-blank-image=maxcrop -right" \
+               "-blank-image=maxcrop -top -bottom -right" ""
+  do
+  echo ${type}
+  pnmcrop -reportsize ${type} ${test_ppm} || echo "fail4"
+  pnmcrop -reportsize ${type} -white ${test_ppm} || echo "fail5"
+  pnmcrop -reportsize ${type} -black ${test_ppm} || echo "fail6"
+  done
+
+rm ${test_ppm}
\ No newline at end of file
diff --git a/test/pnmcrop1.ok b/test/pnmcrop1.ok
new file mode 100644
index 00000000..25bc52ce
--- /dev/null
+++ b/test/pnmcrop1.ok
@@ -0,0 +1,103 @@
+Test 1
+test.pbm
+
+0 0 -7 0 28 25 rgb-1:1/1/1 0.000000
+-white
+0 0 -7 0 28 25 rgb-1:1/1/1 0.000000
+-black
+0 0 0 -2 28 30 rgb-1:0/0/0 0.000000
+-sides
+0 0 -7 0 28 25 rgb-1:1/1/1 0.000000
+-top
+0 0 -7 0 28 25 rgb-1:1/1/1 0.000000
+-bottom
+0 0 0 0 28 32 rgb-1:1/1/1 0.000000
+-left
+0 0 0 0 28 32 rgb-1:1/1/1 0.000000
+-right
+0 0 0 0 28 32 rgb-1:1/1/1 0.000000
+-top -bottom
+0 0 -7 0 28 25 rgb-1:1/1/1 0.000000
+-bottom -bg-corner=bottomright
+0 0 0 -2 28 30 rgb-1:0/0/0 0.000000
+-right -bg-corner=bottomright
+0 0 0 0 28 32 rgb-1:0/0/0 0.000000
+-bg-color=white
+0 0 0 0 28 32 rgb-1:1/1/1 0.000000
+-bg-color=black
+0 0 0 -2 28 30 rgb-1:0/0/0 0.000000
+-bg-color=red
+0 0 0 0 28 32 rgb-1:0/0/0 0.000000
+test.ppm
+
+0 0 0 0 250 161 rgb-255:127/127/127 0.000000
+-white
+-6 0 0 0 244 161 rgb-255:255/255/255 0.000000
+-black
+0 -11 0 0 239 161 rgb-255:0/0/0 0.000000
+-sides
+-6 0 0 0 244 161 rgb-255:255/255/255 0.000000
+-top
+0 0 0 0 250 161 rgb-255:127/127/127 0.000000
+-bottom
+0 0 0 0 250 161 rgb-255:127/127/127 0.000000
+-left
+0 0 0 0 250 161 rgb-255:127/127/127 0.000000
+-right
+0 0 0 0 250 161 rgb-255:127/127/127 0.000000
+-top -bottom
+0 0 0 0 250 161 rgb-255:127/127/127 0.000000
+-bottom -bg-corner=bottomright
+0 0 0 0 250 161 rgb-255:0/0/0 0.000000
+-right -bg-corner=bottomright
+0 -11 0 0 239 161 rgb-255:0/0/0 0.000000
+-bg-color=white
+-6 0 0 0 244 161 rgb-255:255/255/255 0.000000
+-bg-color=black
+0 -11 0 0 239 161 rgb-255:0/0/0 0.000000
+-bg-color=red
+0 0 0 0 250 161 rgb-255:255/0/0 0.000000
+Test 2
+test.pbm
+
+3130931737 109
+3130931737 109
+-white
+3130931737 109
+3130931737 109
+-top
+3130931737 109
+3130931737 109
+test.ppm
+
+1435955776 120765
+1435955776 120765
+-white
+638507845 117867
+638507845 117867
+-top
+1435955776 120765
+1435955776 120765
+Test 3
+-reportfull -reportsize
+expected failure
+-reportfull -borderfile=testgrid.pbm
+expected failure
+-reportsize -borderfile=testgrid.pbm
+expected failure
+-black -white
+expected failure
+-black -sides
+expected failure
+-white -bg-color=red
+expected failure
+-white -bg-corner=topleft
+expected failure
+-white -bg-corner=top
+expected failure
+-blank-image=pasturize
+expected failure
+-bg-color=black -closeness=-1
+expected failure
+-bg-color=black -closeness=101
+expected failure
diff --git a/test/pnmcrop1.test b/test/pnmcrop1.test
new file mode 100755
index 00000000..6b37da23
--- /dev/null
+++ b/test/pnmcrop1.test
@@ -0,0 +1,75 @@
+#! /bin/bash
+# This script tests: pnmcrop
+# Also requires: pnmpad pnmmargin pamcut
+
+tmpdir=${tmpdir:-/tmp}
+
+test_pbm=${tmpdir}/test.pbm
+test_ppm=${tmpdir}/test.ppm
+
+pnmmargin -white 7 testgrid.pbm | pnmpad -black -bottom=2  > ${test_pbm}
+pnmmargin -white 6 testimg.ppm  | pnmpad -black -right=11  > ${test_ppm}
+
+#Test 1
+echo Test 1
+
+for input_file in ${test_pbm} ${test_ppm}
+  do
+  echo `basename ${input_file}`
+  for option in "" "-white" "-black" "-sides" \
+              "-top" "-bottom" "-left" "-right" "-top -bottom" \
+              "-bottom -bg-corner=bottomright" \
+              "-right -bg-corner=bottomright" \
+              "-bg-color=white" "-bg-color=black" "-bg-color=red"
+    do
+    echo ${option}
+    pnmcrop -reportfull ${option} ${input_file} || echo fail
+    done
+  done
+
+#Test 2
+echo Test 2
+
+for input_file in ${test_pbm} ${test_ppm}
+  do
+  echo `basename ${input_file}`
+  for option in "" "-white" "-top"
+    do
+    echo ${option}
+    # Normal crop operation
+    pnmcrop ${option} ${input_file} | cksum
+
+    # Compute edge extents with pnmcrop; let pamcut do the actual cropping
+    pamcut ${input_file} `pnmcrop -reportsize ${option} ${input_file} | \
+        awk 'NF==6 && NR==1 && \
+             $1<=0 && $2<=0 && $3<=0 && $4<=0 && $5>=0 && $6>=0 \
+             { printf("-cropleft=%d -cropright=%d  ", -$1, -$2);
+               printf("-croptop=%d -cropbottom=%d", -$3, -$4) }' ` | cksum
+    done
+  done
+
+rm ${test_pbm} ${test_ppm}
+
+# Test 3
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+echo Test 3
+for option in "-reportfull -reportsize" \
+              "-reportfull -borderfile=testgrid.pbm" \
+              "-reportsize -borderfile=testgrid.pbm" \
+              "-black -white" \
+              "-black -sides" \
+              "-white -bg-color=red" \
+              "-white -bg-corner=topleft" \
+              "-white -bg-corner=top" \
+              "-blank-image=pasturize" \
+              "-bg-color=black -closeness=-1" \
+              "-bg-color=black -closeness=101"
+    do
+    echo ${option}
+    pnmcrop -reportfull ${option} testgrid.pbm || echo expected failure
+    done
diff --git a/test/pnmcrop2.ok b/test/pnmcrop2.ok
new file mode 100644
index 00000000..4eff830d
--- /dev/null
+++ b/test/pnmcrop2.ok
@@ -0,0 +1,29 @@
+Test 1
+
+0 0 0 0 5 5 rgb-200:2/2/2 0.000000
+-sides
+0 0 0 0 5 5 rgb-200:6/6/6 0.000000
+Test 2
+topleft
+0 0 0 0 5 5 rgb-200:0/0/0 0.000000
+topright
+0 0 0 0 5 5 rgb-200:4/4/4 0.000000
+bottomleft
+0 0 0 0 5 5 rgb-200:8/8/8 0.000000
+bottomright
+0 0 0 0 5 5 rgb-200:15/15/15 0.000000
+Test 3
+0
+0 0 0 0 5 5 rgb-200:0/0/0 0.000000
+1
+0 0 0 0 5 5 rgb-200:0/0/0 1.000000
+2
+0 0 -1 0 5 4 rgb-200:0/0/0 2.000000
+3
+-1 0 -1 0 4 4 rgb-200:0/0/0 3.000000
+4
+-1 0 -1 0 4 4 rgb-200:0/0/0 4.000000
+5
+-1 -1 -1 -1 3 3 rgb-200:0/0/0 5.000000
+6
+-1 -1 -1 -1 3 3 rgb-200:0/0/0 6.000000
diff --git a/test/pnmcrop2.test b/test/pnmcrop2.test
new file mode 100755
index 00000000..d6c83c73
--- /dev/null
+++ b/test/pnmcrop2.test
@@ -0,0 +1,55 @@
+#! /bin/bash
+# This script tests: pnmcrop
+# Also requires:
+
+tmpdir=${tmpdir:-/tmp}
+test_pgm=${tmpdir}/test.pgm
+
+cat > ${test_pgm} << EOF
+P2
+5 5
+200
+0 1 2 3 4
+5 199 199 199 9
+6 199 199 199 10
+7 199 199 199 11
+8 12 13 14 15
+EOF
+
+# Test 1
+# Test color detection; none of the sides are cropped
+
+echo Test 1
+
+for option in "" "-sides"
+  do
+  echo ${option}
+  pnmcrop -reportfull ${option} ${test_pgm} || echo fail1
+  done
+
+# Test 2
+# Test color detection; none of the sides are cropped
+echo Test 2
+
+for corner in topleft topright bottomleft bottomright
+  do
+  echo ${corner}
+  pnmcrop -reportfull -bg-corner=${corner} ${test_pgm} || echo fail2
+  done
+
+# Test 3
+# Left edge   is cropped at closeness 2% and above
+# Top  edge   is cropped at closeness 3% and above
+# All  edges are cropped at closeness 5% and above
+
+echo Test 3
+
+for closeness in `seq 0 6`
+  do
+  echo ${closeness}
+  pnmcrop -reportfull -bg-corner=topleft -closeness=${closeness} ${test_pgm} \
+    || echo fail3
+  done
+
+rm ${test_pgm}
+
diff --git a/test/pnmcrop3.ok b/test/pnmcrop3.ok
new file mode 100644
index 00000000..6824143a
--- /dev/null
+++ b/test/pnmcrop3.ok
@@ -0,0 +1,90 @@
+Test 1
+test.pbm
+-left
+-12 0 0 0 15 24
+-right
+0 -2 0 0 25 24
+-top
+0 0 -3 0 27 21
+-bottom
+0 0 0 -6 27 18
+-left -right
+-12 -2 0 0 13 24
+-left -bottom
+-12 0 0 -6 15 18
+-right -bottom
+0 -2 0 -6 25 18
+test.ppm
+-left
+-21 0 0 0 236 161
+-right
+0 -9 0 0 248 161
+-top
+0 0 -11 0 257 150
+-bottom
+0 0 0 -1 257 160
+-left -right
+-21 -9 0 0 227 161
+-left -bottom
+-21 0 0 -1 236 160
+-right -bottom
+0 -9 0 -1 248 160
+Test 2
+test.pbm
+-12 -2 -3 -6 13 15
+-11 -1 -2 -5 15 17
+-10 0 -1 -4 17 19
+-9 +1 0 -3 19 21
+-8 +2 +1 -2 21 23
+-7 +3 +2 -1 23 25
+test.ppm
+-21 -9 -11 -1 227 149
+-20 -8 -10 0 229 151
+-19 -7 -9 +1 231 153
+-18 -6 -8 +2 233 155
+-17 -5 -7 +3 235 157
+-16 -4 -6 +4 237 159
+Test 3
+13 15
+P2
+13 15
+255
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+128 128 128 128 128 128 128 128 128 128 128 128 128
+13 15
+0 0 0 0 13 15
+13 15
+P1
+13 15
+1111111111111
+1110101010101
+1111111111111
+1110101010101
+1111111111111
+1110101010101
+1111111111111
+1110101010101
+1111111111111
+1110101010101
+1111111111111
+1110101010101
+1111111111111
+1110101010101
+1111111111111
+-3 -1 -1 -1 9 13
+544280424 101484
+4294967295 0
+4294967295 0
diff --git a/test/pnmcrop3.test b/test/pnmcrop3.test
new file mode 100755
index 00000000..c46fd7ea
--- /dev/null
+++ b/test/pnmcrop3.test
@@ -0,0 +1,71 @@
+#! /bin/bash
+# This script tests: pnmcrop
+# Also requires: pnmpad pamfile pgmmake
+
+tmpdir=${tmpdir:-/tmp}
+
+test_pbm=${tmpdir}/test.pbm
+test_ppm=${tmpdir}/test.ppm
+border_pbm=${tmpdir}/border.pbm
+border_ppm=${tmpdir}/border.ppm
+gray_pgm=${tmpdir}/gray.pgm
+
+pnmpad -top=3 -bottom=5 -left=11 -right=2 testgrid.pbm > ${test_pbm}
+pnmpad -top=11 -bottom=1 -left=21 -right=9 testimg.ppm > ${test_ppm}
+
+pnmpad -top=4 -bottom=4 -left=8 -right=5 testgrid.pbm > ${border_pbm}
+pnmpad -top=7 -bottom=5 -left=30 -right=0 testimg.ppm > ${border_ppm}
+
+pgmmake 0.5 `pamfile -size ${test_pbm}` > ${gray_pgm}
+
+# Test 1
+echo Test 1
+
+for input_file in ${test_pbm} ${test_ppm}
+  do
+  echo `basename ${input_file}`
+  for option in "-left" "-right" "-top" "-bottom" \
+            "-left -right" "-left -bottom" "-right -bottom"
+    do
+    echo ${option}
+    pnmcrop -reportsize ${option} ${input_file} || echo fail1
+    done
+  done
+
+# Test 2
+echo Test 2
+
+for input_file in ${test_pbm} ${test_ppm}
+  do
+  echo `basename ${input_file}`
+  for margin in `seq 0 5`
+    do
+    pnmcrop -reportsize -margin=${margin} ${input_file} || echo fail2
+    done
+  done
+
+# Test 3
+echo Test 3
+
+pnmcrop -borderfile=${border_pbm} ${gray_pgm} | pamfile -size
+pnmcrop -borderfile=${border_pbm} ${gray_pgm} -plain 
+
+pnmcrop -borderfile=${test_pbm} ${test_pbm}   | pamfile -size
+pnmcrop -borderfile=${test_pbm} ${test_pbm}   | pnmcrop -black -reportsize
+
+pnmcrop -borderfile=${border_pbm} ${test_pbm} | pamfile -size
+pnmcrop -borderfile=${border_pbm} ${test_pbm} -plain
+pnmcrop -borderfile=${border_pbm} ${test_pbm} | pnmcrop -black -reportsize
+
+pnmcrop -borderfile=${border_ppm} ${test_ppm} | cksum 
+
+# The following two cases are expected to fai
+
+echo "Error messages should appear below the line." 1>&2
+echo "--------------------------------------------" 1>&2
+
+pnmcrop -borderfile=${border_ppm} ${test_pbm} | cksum 
+pnmcrop -borderfile=${border_pbm} ${test_ppm} | cksum 
+
+
+rm ${test_pbm} ${test_ppm} ${border_pbm} ${border_ppm} ${gray_pgm}
\ No newline at end of file
diff --git a/test/pnmpsnr.ok b/test/pnmpsnr.ok
index 3469f836..e8b5ebc2 100644
--- a/test/pnmpsnr.ok
+++ b/test/pnmpsnr.ok
@@ -1,7 +1,14 @@
+Test 1
 0.00
 inf
 1000.00
 match
+Test 2
 300.00 300.00 300.00
 match
 match
+Test 3
+Expected failure 1
+Expected failure 2
+Expected failure 3
+Expected failure 4
diff --git a/test/pnmpsnr.test b/test/pnmpsnr.test
index f24c08aa..c6520002 100755
--- a/test/pnmpsnr.test
+++ b/test/pnmpsnr.test
@@ -5,19 +5,36 @@
 
 tmpdir=${tmpdir:-/tmp}
 
-
 w_pbm=${tmpdir}/w.pbm
 b_pbm=${tmpdir}/b.pbm
 
 pbmmake -w 10 10 > ${w_pbm}
 pbmmake -b 10 10 > ${b_pbm}
 
+echo "Test 1"
+
 pnmpsnr  ${w_pbm}  ${b_pbm} -machine
 pnmpsnr  ${w_pbm}  ${w_pbm} -machine
 pnmpsnr  ${w_pbm}  ${w_pbm} -machine -max=1000
 pnmpsnr  ${w_pbm}  ${w_pbm} -target=1000
+
+echo "Test 2"
+
 pnmpsnr  testimg.ppm  testimg.ppm -machine -max=300
 pnmpsnr  testimg.ppm  testimg.ppm -target=1000
 pnmpsnr  testimg.ppm  testimg.ppm -target1=1000 -target2=1000 -target3=1000
 
-rm ${b_pbm} ${w_pbm}
+
+echo "Test 3"
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+pnmpsnr ${b_pbm} ${w_pbm} ${b_pbm}     || echo "Expected failure 1"
+pnmpsnr ${b_pbm}                       || echo "Expected failure 2"
+pnmpsnr ${b_pbm} ${w_pbm} -target1=100 || echo "Expected failure 3"
+pnmpsnr                   -machine     || echo "Expected failure 4"
+
+rm ${b_pbm} ${w_pbm}
\ No newline at end of file
diff --git a/test/pnmquantall.test b/test/pnmquantall.test
index cd01bb8d..b735b623 100755
--- a/test/pnmquantall.test
+++ b/test/pnmquantall.test
@@ -1,6 +1,6 @@
 #! /bin/bash
 # This script tests: pnmquantall
-# Also requires: ppmtorgb3 pgmhist
+# Also requires: ppmtorgb3 pgmhist pnmcat
 
 tmpdir=${tmpdir:-/tmp}
 test_ppm=${tmpdir}/testimg.ppm
diff --git a/test/ppmforge-parameters.ok b/test/ppmforge-parameters.ok
new file mode 100644
index 00000000..50e68390
--- /dev/null
+++ b/test/ppmforge-parameters.ok
@@ -0,0 +1,10 @@
+Test 1
+256 256
+100 90
+90 90
+Test 2
+Expected failure 1
+Expected failure 2
+Expected failure 3
+Expected failure 4
+Expected failure 5
diff --git a/test/ppmforge-parameters.test b/test/ppmforge-parameters.test
new file mode 100755
index 00000000..48c4ae4c
--- /dev/null
+++ b/test/ppmforge-parameters.test
@@ -0,0 +1,29 @@
+#! /bin/bash
+# This script tests: ppmforge
+# Also requires: pamfile
+
+echo "Test 1"
+
+# Should print 256 256
+ppmforge -night | pamfile -size
+
+# Width is adjusted if not even
+# becomes 100 in this case
+ppmforge -night -width=99 -height=90 | pamfile -size
+
+# Width is adjusted if smaller than height
+# brought up to 100 in this case
+ppmforge -night -width=80 -height=90 | pamfile -size
+
+echo "Test 2"
+
+echo 1>&2
+echo "Invalid command-line arguments." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+ppmforge -night  -dimension=0  || echo "Expected failure 1"
+ppmforge -clouds -mesh=1.99    || echo "Expected failure 2"
+ppmforge -clouds -power=0      || echo "Expected failure 3"
+ppmforge         -ice=0        || echo "Expected failure 4"
+ppmforge         -glaciers=0   || echo "Expected failure 5"
diff --git a/test/ppmhist.ok b/test/ppmhist.ok
index f2ba637b..38b7770f 100644
--- a/test/ppmhist.ok
+++ b/test/ppmhist.ok
@@ -1,3 +1,4 @@
+Test 1
      0     0     0	    0	      2 
      1     1     1	    1	      2 
      2     2     2	    2	      2 
@@ -7,6 +8,7 @@
      6     6     6	    6	      2 
      8     8     8	    8	      2 
 3081591280 60957
+Test 2
  Summary: 1 colors: 1 black, 0 white, 0 gray, 0 color
  Summary: 1 colors: 0 black, 1 white, 0 gray, 0 color
  Summary: 2 colors: 1 black, 1 white, 0 gray, 0 color
@@ -17,3 +19,7 @@
  Summary: 6 colors: 0 black, 0 white, 0 gray, 6 color
  Summary: 6 colors: 1 black, 0 white, 0 gray, 5 color
  Summary: 6 colors: 1 black, 1 white, 1 gray, 3 color
+Test 3
+Expected failure 1
+Expected failure 2
+Expected failure 3
diff --git a/test/ppmhist.test b/test/ppmhist.test
index 27d31562..c17bab5a 100755
--- a/test/ppmhist.test
+++ b/test/ppmhist.test
@@ -2,11 +2,15 @@
 # This script tests: ppmhist
 # Also requires: pgmramp pamtopnm pbmmake pamseq ppmpat
 
+echo "Test 1"
+
 pgmramp -maxval=8 -lr 8 2 | ppmhist -sort=rgb -noheader
 ppmhist -map -sort=rgb -noheader testimg.ppm | pamtopnm | cksum
 
 # Test summary header
 
+echo "Test 2"
+
 pbmmake -b 2 1 | ppmhist   | head -n1
 pbmmake -w 2 1 | ppmhist   | head -n1
 pbmmake -g 2 1 | ppmhist   | head -n1
@@ -19,4 +23,16 @@ ppmpat -madras --color=rgb:32/0d/b7,rgb:31/58/a3,rgb:e9/5e/d4 25 25 | \
 ppmpat -madras --color=rgb:00/00/00,rgb:31/58/a3,rgb:e9/5e/d4 25 25 | \
   ppmhist | head -n1
 ppmpat -madras --color=rgb:00/00/00,rgb:31/58/a3,rgb:ff/ff/ff 25 25 | \
-  ppmhist | head -n1
\ No newline at end of file
+  ppmhist | head -n1
+
+echo "Test 3"
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+ppmhist -hexcolor -float testimg.ppm || echo "Expected failure 1"
+ppmhist -hexcolor -map   testimg.ppm || echo "Expected failure 2"
+ppmhist -float    -map   testimg.ppm || echo "Expected failure 3"
+
diff --git a/test/ppmmake.ok b/test/ppmmake.ok
index 0e871732..8a2bedc7 100644
--- a/test/ppmmake.ok
+++ b/test/ppmmake.ok
@@ -1,2 +1,15 @@
+Test 1.
 2477651508 15012
+4294967295 0
 2378991101 7513
+Test 2.
+Expected error 1
+Expected error 2
+Expected error 3
+Expected error 4
+Expected error 5
+Expected error 6
+Expected error 7
+Expected error 8
+Expected error 9
+Expected error 10
diff --git a/test/ppmmake.test b/test/ppmmake.test
index 879a367e..edd6f251 100755
--- a/test/ppmmake.test
+++ b/test/ppmmake.test
@@ -2,6 +2,26 @@
 # This script tests: ppmmake
 # Also requires:
 
+echo "Test 1."
 
 ppmmake rgb:ff/80/80 50 100 -maxval=5 | cksum
+ppmmake rgbi:0.5/1.0/0 2   | cksum
 ppmmake red 50 50  | cksum
+
+echo "Test 2."
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+ppmmake rgb:gg/00/00  2 2  || echo "Expected error 1"
+ppmmake rgb:ff/ff/00  2    || echo "Expected error 2"
+ppmmake rgbi:1.1/0/0  2 2  || echo "Expected error 3"
+ppmmake rgbi:1.0/.5   2 2  || echo "Expected error 4"
+ppmmake rainbow       2 2  || echo "Expected error 5"
+ppmmake               2 2  || echo "Expected error 6"
+ppmmake blue -maxval=0 2 2  || echo "Expected error 7"
+ppmmake blue -maxval=-1 2 2  || echo "Expected error 8"
+ppmmake blue -maxval=65536 2 2  || echo "Expected error 9"
+RGBDEF=/dev/null ppmmake red 2 2 || echo "Expected error 10"
diff --git a/test/ppmpat.ok b/test/ppmpat.ok
index bb940aee..5493ba53 100644
--- a/test/ppmpat.ok
+++ b/test/ppmpat.ok
@@ -1,6 +1,39 @@
+Test 1
 4008533639 781
+Test 2
 3805937800 9613
+Test 3
 2698433077 1549
+Test 4
 3705929501 781
+Test 5
 3057513592 661
+Test 6
 1861389287 661
+Test 7
+Expected failure 1
+Expected failure 2
+Expected failure 3
+Expected failure 4
+Expected failure 5
+Expected failure 6
+Expected failure 7
+Expected failure 8
+Expected failure 9
+Expected failure 10
+Expected failure 11
+Expected failure 12
+Expected failure 13
+Expected failure 14
+Expected failure 15
+Expected failure 16
+Expected failure 17
+Expected failure 18
+Expected failure 19
+Expected failure 20
+Expected failure 21
+Expected failure 22
+Expected failure 23
+Expected failure 24
+Expected failure 25
+Expected failure 26
diff --git a/test/ppmpat.test b/test/ppmpat.test
index cd00c0f1..c6647328 100755
--- a/test/ppmpat.test
+++ b/test/ppmpat.test
@@ -3,19 +3,74 @@
 # Also requires:
 
 # Test 1. Should print: 4008533639 781
+echo "Test 1"
 ppmpat -g2 --color=rgb:32/0d/b7,rgb:31/58/a3 16 16 | cksum
 
 # Test 2. Should print: 3805937800 9613
+echo "Test 2"
 ppmpat -g3 --color=rgb:32/0d/b7,rgb:31/58/a3,rgb:e9/5e/d4 64 50 | cksum
 
 # Test 3. Should print: 2698433077 1549
+echo "Test 3"
 ppmpat -madras --color=rgb:32/0d/b7,rgb:31/58/a3,rgb:e9/5e/d4 32 16 | cksum
 
 # Test 4. Should print: 3705929501 781
+echo "Test 4"
 ppmpat -tartan --color=rgb:32/0d/b7,rgb:31/58/a3,rgb:e9/5e/d4 16 16 | cksum
 
 # Test 5. Should print: 3057513592 661
+echo "Test 5"
 ppmpat -argyle1 --color=rgb:ff/ff/ff,rgb:ff/0/0 12 18 | cksum
 
 # Test 6. Should print: 1861389287 661
+echo "Test 6"
 ppmpat -argyle2 --color=rgb:00/00/00,rgb:ff/80/80,rgb:e0/e0/e0 12 18 | cksum
+
+# Test 7.
+echo "Test 7"
+
+echo 1>&2
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+ppmpat -g2 -g3 10 10 || echo "Expected failure 1"
+ppmpat -madras -tartan 10 10 || echo "Expected failure 2"
+ppmpat -poles -squig 10 10 || echo "Expected failure 3"
+ppmpat -camo -anticamo 10 10 || echo "Expected failure 4"
+ppmpat -argyle1 -argyle2 10 10 || echo "Expected failure 5"
+
+ppmpat 10 10 || echo "Expected failure 6"
+ppmpat -g2 10 || echo "Expected failure 7"
+ppmpat -g2 10 10 10 || echo "Expected failure 8"
+ppmpat -g2 10 || echo "Expected failure 9"
+
+clist1="-color=rgb:00/00/00"
+clist2="-color=rgb:00/00/00,rgb:00/00/ff"
+clist3="-color=rgb:00/00/00,rgb:00/00/ff,rgb:00/ff/ff"
+clist4="-color=rgb:00/00/00,rgb:00/00/ff,rgb:00/ff/ff,rgb:ff/ff/ff"
+
+# These patterns require exactly 2 colors 
+ppmpat -gingham2 ${clist1} 10 10 || echo "Expected failure 10"
+ppmpat -argyle1  ${clist1} 10 10 || echo "Expected failure 11"
+ppmpat -gingham2 ${clist3} 10 10 || echo "Expected failure 12"
+ppmpat -argyle1  ${clist3} 10 10 || echo "Expected failure 13"
+
+# These require exactly 3 colors 
+ppmpat -gingham3 ${clist2} 10 10 || echo "Expected failure 14"
+ppmpat -argyle2  ${clist2} 10 10 || echo "Expected failure 15"
+ppmpat -madras   ${clist2} 10 10 || echo "Expected failure 16"
+ppmpat -tartan   ${clist2} 10 10 || echo "Expected failure 17"
+ppmpat -gingham3 ${clist4} 10 10 || echo "Expected failure 18"
+ppmpat -argyle2  ${clist4} 10 10 || echo "Expected failure 19"
+ppmpat -madras   ${clist4} 10 10 || echo "Expected failure 20"
+ppmpat -tartan   ${clist4} 10 10 || echo "Expected failure 21"
+
+# These require at least 3 colors 
+ppmpat -squig    ${clist2} 10 10 || echo "Expected failure 22"
+ppmpat -camo     ${clist2} 10 10 || echo "Expected failure 23"
+ppmpat -anticamo ${clist2} 10 10 || echo "Expected failure 24"
+
+# The squig pattern has an aspect ratio restriction 
+ppmpat -squig ${clist3} 10 250  || echo "Expected failure 25"
+ppmpat -squig ${clist3} 500 20  || echo "Expected failure 26"
diff --git a/test/sgi-roundtrip.test b/test/sgi-roundtrip.test
index 88efb75e..5052bb81 100755
--- a/test/sgi-roundtrip.test
+++ b/test/sgi-roundtrip.test
@@ -1,6 +1,6 @@
 #! /bin/bash
 # This script tests: pnmtosgi sgitopnm
-# Also requires: rgb3toppm
+# Also requires: rgb3toppm pamdepth pamtopnm
 
 
 a_sgi=${tmpdir}/a.sgi
diff --git a/version.mk b/version.mk
index f1ae314e..abe9fa9e 100644
--- a/version.mk
+++ b/version.mk
@@ -1,3 +1,3 @@
 NETPBM_MAJOR_RELEASE = 10
-NETPBM_MINOR_RELEASE = 86
-NETPBM_POINT_RELEASE = 4
+NETPBM_MINOR_RELEASE = 87
+NETPBM_POINT_RELEASE = 0