about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2013-06-29 19:19:47 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2013-06-29 19:19:47 +0000
commit380588e187c12000ac8082cb2a20a905d3c422a5 (patch)
tree296b1324b7a9360646a34ae836b8eb486b7feede
parentf8b633c2be1231a0c194214271caa456dc669ecb (diff)
downloadnetpbm-mirror-380588e187c12000ac8082cb2a20a905d3c422a5.tar.gz
netpbm-mirror-380588e187c12000ac8082cb2a20a905d3c422a5.tar.xz
netpbm-mirror-380588e187c12000ac8082cb2a20a905d3c422a5.zip
Release 10.63.00
git-svn-id: http://svn.code.sf.net/p/netpbm/code/advanced@1968 9d0c8265-081b-0410-96cb-a4ca84ce46f8
-rw-r--r--GNUmakefile10
-rw-r--r--analyzer/pamfile.c6
-rw-r--r--analyzer/pamtilt.c51
-rw-r--r--converter/other/Makefile5
-rw-r--r--converter/other/cameratopam/camera.c2
-rw-r--r--converter/other/cameratopam/cameratopam.c2
-rw-r--r--converter/other/cameratopam/foveon.c4
-rw-r--r--converter/other/cameratopam/foveon.h4
-rw-r--r--converter/other/ipdb.c1
-rw-r--r--converter/other/pamtogif.c4
-rw-r--r--converter/other/pamtooctaveimg.c4
-rw-r--r--converter/other/pamtopam.c2
-rw-r--r--converter/other/pamtopnm.c2
-rw-r--r--converter/other/pamtosrf.c4
-rw-r--r--converter/other/pamtosvg/pamtosvg.c2
-rw-r--r--converter/other/pamtotiff.c2
-rw-r--r--converter/other/pamtowinicon.c1177
-rw-r--r--converter/other/pamtoxvmini.c4
-rw-r--r--converter/other/pnmtopclxl.c2
-rw-r--r--converter/other/pnmtopng.c534
-rw-r--r--converter/other/pnmtops.c82
-rw-r--r--converter/other/pstopnm.c378
-rw-r--r--converter/other/winicon.h82
-rw-r--r--converter/other/winicontopam.c1282
-rw-r--r--converter/pbm/pbmtolj.c2
-rw-r--r--converter/pbm/pbmtopsg3.c2
-rw-r--r--converter/ppm/411toppm.c10
-rw-r--r--converter/ppm/ppmtompeg/bframe.c2
-rw-r--r--converter/ppm/ppmtompeg/frame.c2
-rw-r--r--converter/ppm/ppmtompeg/headers/frames.h1
-rw-r--r--converter/ppm/ppmtompeg/headers/param.h17
-rw-r--r--converter/ppm/ppmtompeg/parallel.c2
-rw-r--r--converter/ppm/ppmtompeg/param.c65
-rw-r--r--converter/ppm/ppmtompeg/ppmtompeg.c5
-rw-r--r--converter/ppm/ppmtompeg/readframe.c7
-rw-r--r--converter/ppm/ppmtompeg/specifics.c4
-rw-r--r--converter/ppm/ppmtopjxl.c229
-rw-r--r--converter/ppm/ppmtoyuv.c141
-rw-r--r--converter/ppm/sldtoppm.c137
-rw-r--r--converter/ppm/winicontoppm.c813
-rw-r--r--converter/ppm/yuvtoppm.c255
-rw-r--r--doc/HISTORY256
-rw-r--r--doc/INSTALL23
-rw-r--r--doc/TESTS302
-rw-r--r--doc/patent_summary15
-rw-r--r--editor/pamcut.c2
-rw-r--r--editor/pamscale.c4
-rw-r--r--editor/pamthreshold.c2
-rw-r--r--editor/pnmcrop.c4
-rwxr-xr-xeditor/pnmflip25
-rw-r--r--editor/pnmnlfilt.c2
-rwxr-xr-xeditor/pnmquant25
-rwxr-xr-xeditor/pnmquantall24
-rw-r--r--editor/pnmremap.c4
-rw-r--r--editor/ppmdraw.c10
-rwxr-xr-xeditor/ppmfade32
-rwxr-xr-xeditor/ppmquant26
-rwxr-xr-xeditor/ppmshadow35
-rw-r--r--editor/specialty/ppmntsc.c311
-rw-r--r--generator/pamgauss.c2
-rw-r--r--generator/pamgradient.c8
-rw-r--r--generator/pamseq.c2
-rw-r--r--generator/pgmnoise.c97
-rw-r--r--generator/ppmcie.c114
-rw-r--r--generator/ppmforge.c413
-rwxr-xr-xgenerator/ppmrainbow26
-rw-r--r--lib/libpam.c23
-rw-r--r--lib/libpammap.c2
-rw-r--r--lib/libpamn.c6
-rw-r--r--lib/libpamwrite.c14
-rw-r--r--lib/libpbm1.c27
-rw-r--r--lib/libpgm1.c20
-rw-r--r--lib/libppm1.c22
-rw-r--r--lib/libppmcolor.c108
-rw-r--r--lib/libsystem.c16
-rw-r--r--lib/pam.h13
-rw-r--r--lib/pmfileio.c4
-rw-r--r--lib/util/mallocvar.h2
-rw-r--r--lib/util/pm_c_util.h62
-rw-r--r--other/pamchannel.c10
-rw-r--r--other/pamdepth.c11
-rw-r--r--other/pamexec.c2
-rw-r--r--other/pampick.c10
-rw-r--r--other/pamsplit.c2
-rw-r--r--other/pamstack.c4
-rw-r--r--other/pnmcolormap.c4
-rwxr-xr-xtest/Execute-Tests39
-rw-r--r--test/Test-Order10
-rw-r--r--test/all-in-place.ok4
-rwxr-xr-xtest/all-in-place.test426
-rwxr-xr-xtest/g3-roundtrip.test8
-rwxr-xr-xtest/gem-roundtrip.test2
-rw-r--r--test/gif-quant-roundtrip.ok1
-rw-r--r--test/gif-quant-roundtrip.test15
-rw-r--r--test/gif-roundtrip.ok1
-rwxr-xr-xtest/gif-roundtrip.test11
-rwxr-xr-xtest/pad-crop-roundtrip.test2
-rw-r--r--test/pamchannel.ok3
-rw-r--r--test/pamchannel.test32
-rwxr-xr-xtest/pamslice-roundtrip.test2
-rwxr-xr-xtest/pbmclean.test2
-rwxr-xr-xtest/pbmminkowski.test2
-rw-r--r--test/pgmcrater.ok1
-rw-r--r--test/pgmcrater.test29
-rw-r--r--test/pgmnoise.ok1
-rw-r--r--test/pgmnoise.test22
-rwxr-xr-xtest/pnm-plain-roundtrip.test2
-rw-r--r--test/pnmremap1.ok2
-rwxr-xr-xtest/pnmtile.test3
-rwxr-xr-xtest/pnmtopnm-plain.test2
-rw-r--r--test/ppmcie.out-641
-rwxr-xr-xtest/ppmdfont.test10
-rwxr-xr-xtest/ppmdim.test2
-rw-r--r--test/ppmforge.ok1
-rw-r--r--test/ppmforge.test20
-rwxr-xr-xtest/ppmhist.test2
-rwxr-xr-xtest/ppmmake.test2
-rwxr-xr-xtest/ppmmix.test1
-rwxr-xr-xtest/ppmpat.test39
-rw-r--r--test/ppmrough.ok1
-rw-r--r--test/ppmrough.test18
-rw-r--r--test/ps-roundtrip.ok1
-rwxr-xr-xtest/ps-roundtrip.test33
-rw-r--r--test/rgb3-roundtrip.ok1
-rwxr-xr-xtest/rgb3-roundtrip.test9
-rw-r--r--test/winicon-roundtrip.ok2
-rw-r--r--test/winicon-roundtrip.test13
-rwxr-xr-xtest/yuv-roundtrip.test3
-rw-r--r--version.mk4
129 files changed, 6162 insertions, 2089 deletions
diff --git a/GNUmakefile b/GNUmakefile
index 489d6888..c6077285 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -72,6 +72,10 @@ NOMERGEBINARIES = netpbm
 
 OBJECTS = netpbm.o
 
+PBM_TESTPREFIX ?= $(PKGDIR)/bin
+PBM_LIBRARY_PATH ?= $(PKGDIR)/lib
+RGBDEF ?= $(SRCDIR)/lib/rgb.txt
+
 default: $(DEFAULT_TARGET)
 	echo "EXISTENCE OF THIS FILE MEANS NETPBM HAS BEEN BUILT." \
 	  >build_complete
@@ -412,9 +416,9 @@ check:
 # This works on typical Linux systems
 	if [ ! -d $(RESULTDIR) ]; then mkdir -pv $(RESULTDIR); fi
 	cd $(RESULTDIR); \
-	  PBM_TESTPREFIX=$(PKGDIR)/bin \
-	  LD_LIBRARY_PATH=$(PKGDIR)/lib \
-	  RGBDEF=$(SRCDIR)/lib/rgb.txt \
+	  PBM_TESTPREFIX=$(PBM_TESTPREFIX) \
+	  LD_LIBRARY_PATH=$(PBM_LIBRARY_PATH):${LD_LIBRARY_PATH} \
+	  RGBDEF=$(RGBDEF) \
 	  $(SRCDIR)/test/Execute-Tests 2>&1
 
 clean: localclean
diff --git a/analyzer/pamfile.c b/analyzer/pamfile.c
index c2507f66..9c5b2c33 100644
--- a/analyzer/pamfile.c
+++ b/analyzer/pamfile.c
@@ -171,7 +171,11 @@ doOneImage(const char * const name,
         
         pnm_freepamrow(tuplerow);
         
-        pnm_nextimage(fileP, eofP);
+        {
+            int eof;
+            pnm_nextimage(fileP, &eof);
+            *eofP = eof;
+        }
     }
 }
 
diff --git a/analyzer/pamtilt.c b/analyzer/pamtilt.c
index 5d1d1986..8fa34791 100644
--- a/analyzer/pamtilt.c
+++ b/analyzer/pamtilt.c
@@ -47,7 +47,7 @@ abandon(void) {
 
 
 static void
-parseCommandLine(int argc, char *argv[],
+parseCommandLine(int argc, const char ** const argv,
                  struct cmdlineInfo * const cmdlineP) {
 
     static optEntry option_def[50];
@@ -76,7 +76,7 @@ parseCommandLine(int argc, char *argv[],
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;          /* no short options used */
     opt.allowNegNum = FALSE;            /* don't allow negative values */
-    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
 
     if (cmdlineP->hstep < 1)
         pm_error("-hstep must be at least 1 column.");
@@ -143,9 +143,6 @@ load(const struct pam * const pamP,
     tuplerow = pnm_allocpamrow(pamP);
     
     MALLOCARRAY(pixels, pamP->height);
-    if (pixels == NULL)
-        pm_error("Unable to allocate array of %u pixel rows",
-                 pamP->height);
 
     if (pixels == NULL)
         pm_error("Unable to allocate array of %u rows", pamP->height);
@@ -214,9 +211,32 @@ replacePixelValuesWithScaledDiffs(
 
 
 
+static unsigned long
+totalBrightness(sample **    const pixelWindow,
+                unsigned int const hsampleCt,
+                float        const dy) {
+/*----------------------------------------------------------------------------
+   Total brightness of samples in the line that goes from the top left corner
+   of 'pixelWindow' down to the right at 'dy' rows per column.
+-----------------------------------------------------------------------------*/
+    unsigned long total;
+    unsigned int i;
+    float rowOffset;
+
+    for (i = 0, rowOffset = 0.5, total = 0;
+         i < hsampleCt;
+         ++i, rowOffset += dy) {
+
+        total += pixelWindow[(unsigned)rowOffset][i];
+    }
+    return total;
+}
+
+
+
 static void
 scoreAngleRegion(sample **    const pixels,
-                 unsigned int const hsamples,
+                 unsigned int const hsampleCt,
                  unsigned int const startRow,
                  unsigned int const endRow,
                  unsigned int const vstep,
@@ -234,7 +254,7 @@ scoreAngleRegion(sample **    const pixels,
    Instead of a tilt angle, we have 'dy', the slope (downward) of the lines
    in our assumed tilt.
 -----------------------------------------------------------------------------*/
-    double const tscale  = 1.0 / hsamples;
+    double const tscale  = 1.0 / hsampleCt;
 
     unsigned int row;
     double sum;
@@ -245,17 +265,10 @@ scoreAngleRegion(sample **    const pixels,
         /* Number of lines that went into 'total' */
 
     for (row = startRow, sum = 0.0, n = 0; row < endRow; row += vstep) {
-        float o;
-        long t;     /* total brightness of the samples in the line */
-        double dt;  /* mean brightness of the samples in the line */
+        double const dt =
+            tscale * totalBrightness(&pixels[row], hsampleCt, dy);
+            /* mean brightness of the samples in the line */
 
-        unsigned int i;
-
-        for (i = 0, t = 0, o = 0.5;
-             i < hsamples;
-             t += pixels[(int)(row + o)][i], ++i, o += dy) {
-        }
-        dt = tscale * t;
         sum += dt * dt;
         n += 1;
     }
@@ -478,7 +491,7 @@ getAngle(const struct pam * const pamP,
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char ** argv) {
 
     struct cmdlineInfo cmdline;
     struct pam pam;
@@ -488,7 +501,7 @@ main(int argc, char *argv[]) {
     unsigned int vstep;    /* vertical step size */
     float angle;
 
-    pgm_init(&argc, argv);              /* initialize netpbm system */
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
diff --git a/converter/other/Makefile b/converter/other/Makefile
index 746db87c..35f420f2 100644
--- a/converter/other/Makefile
+++ b/converter/other/Makefile
@@ -118,12 +118,13 @@ PORTBINARIES =  avstopam bmptopnm fitstopnm \
 		pamtoavs pamtodjvurle pamtofits pamtogif \
 		pamtohdiff pamtohtmltbl pamtompfont pamtooctaveimg \
 		pamtopam pamtopfm pamtopnm pamtouil \
-		pamtoxvmini \
+		pamtowinicon pamtoxvmini \
 		pbmtopgm pfmtopam \
 	        pgmtopbm pgmtoppm ppmtopgm pnmtoddif \
 		pnmtopclxl \
 		pnmtosgi pnmtosir pamtotga pnmtoxwd \
-		rlatopam sgitopnm sirtopnm sunicontopnm xwdtopnm zeisstopnm
+		rlatopam sgitopnm sirtopnm sunicontopnm \
+		winicontopam xwdtopnm zeisstopnm
 
 BINARIES = \
   $(PORTBINARIES) \
diff --git a/converter/other/cameratopam/camera.c b/converter/other/cameratopam/camera.c
index ea5eec39..254b6710 100644
--- a/converter/other/cameratopam/camera.c
+++ b/converter/other/cameratopam/camera.c
@@ -761,7 +761,7 @@ kodak_radc_load_raw()
 void kodak_jpeg_load_raw() {}
 #else
 
-static boolean
+static bool
 fill_input_buffer (j_decompress_ptr cinfo)
 {
   static char jpeg_buffer[4096];
diff --git a/converter/other/cameratopam/cameratopam.c b/converter/other/cameratopam/cameratopam.c
index 54b68a23..71c9c7af 100644
--- a/converter/other/cameratopam/cameratopam.c
+++ b/converter/other/cameratopam/cameratopam.c
@@ -69,7 +69,7 @@ int fuji_secondary;
 float cam_mul[4], pre_mul[4], coeff[3][4];
 int histogram[3][0x2000];
 jmp_buf failure;
-bool use_secondary;
+int use_secondary;
 bool verbose;
 
 #ifdef USE_LCMS
diff --git a/converter/other/cameratopam/foveon.c b/converter/other/cameratopam/foveon.c
index 0198940c..78e40baf 100644
--- a/converter/other/cameratopam/foveon.c
+++ b/converter/other/cameratopam/foveon.c
@@ -141,8 +141,8 @@ parse_foveon(FILE * const ifp) {
 
 
 void  
-foveon_coeff(bool * const useCoeffP,
-             float        coeff[3][4]) {
+foveon_coeff(int * const useCoeffP,
+             float       coeff[3][4]) {
 
     static const float foveon[3][3] =
     { {  1.4032, -0.2231, -0.1016 },
diff --git a/converter/other/cameratopam/foveon.h b/converter/other/cameratopam/foveon.h
index 57be2244..f3177e50 100644
--- a/converter/other/cameratopam/foveon.h
+++ b/converter/other/cameratopam/foveon.h
@@ -10,5 +10,5 @@ void
 foveon_load_raw(void);
 
 void  
-foveon_coeff(bool * const useCoeffP,
-             float        coeff[3][4]);
+foveon_coeff(int * const useCoeffP,
+             float       coeff[3][4]);
diff --git a/converter/other/ipdb.c b/converter/other/ipdb.c
index 5c1fc314..eec4495a 100644
--- a/converter/other/ipdb.c
+++ b/converter/other/ipdb.c
@@ -19,6 +19,7 @@
  *   Authors:  Eric A. Howe (mu@trends.net)
  *             Bryan Henderson, 2010
  */
+#define _BSD_SOURCE   /* Ensure strdup() is in <string.h> */
 #include <assert.h>
 #include <time.h>
 #include <string.h>
diff --git a/converter/other/pamtogif.c b/converter/other/pamtogif.c
index 4dac8923..5b9c219c 100644
--- a/converter/other/pamtogif.c
+++ b/converter/other/pamtogif.c
@@ -220,7 +220,7 @@ closestColor(tuple         const color,
     
     unsigned int i;
     unsigned int imin, dmin;
-    bool fits;
+    int fits;
 
     dmin = UINT_MAX;
     imin = 0;
@@ -1544,7 +1544,7 @@ computeTransparent(char          const colorarg[],
         const char * colorspec;
         bool exact;
         tuple transcolor;
-        bool found;
+        int found;
         int colorindex;
         
         if (colorarg[0] == '=') {
diff --git a/converter/other/pamtooctaveimg.c b/converter/other/pamtooctaveimg.c
index b090281d..28bc4cd4 100644
--- a/converter/other/pamtooctaveimg.c
+++ b/converter/other/pamtooctaveimg.c
@@ -75,13 +75,13 @@ findOrAddColor(tuple          const color,
   colormap *cmapP.  If the color isn't in the map, give it a new
   colormap index, put it in the colormap, and return that.
 -----------------------------------------------------------------------------*/
-    bool found;
+    int found;
     int colorIndex;
 
     pnm_lookuptuple(&cmapP->pam, cmapP->hash, color, &found, &colorIndex);
 
     if (!found) {
-        bool fits;
+        int fits;
         unsigned int plane;
 
         colorIndex = cmapP->nColors++;
diff --git a/converter/other/pamtopam.c b/converter/other/pamtopam.c
index cae54060..9cb82f7a 100644
--- a/converter/other/pamtopam.c
+++ b/converter/other/pamtopam.c
@@ -17,7 +17,7 @@
 int
 main(int argc, const char * argv[]) {
 
-    bool       eof;     /* no more images in input stream */
+    int        eof;     /* no more images in input stream */
     struct pam inpam;   /* Input PAM image */
     struct pam outpam;  /* Output PAM image */
 
diff --git a/converter/other/pamtopnm.c b/converter/other/pamtopnm.c
index ba655b1e..9bb662b7 100644
--- a/converter/other/pamtopnm.c
+++ b/converter/other/pamtopnm.c
@@ -109,7 +109,7 @@ main(int argc, char *argv[]) {
 
     struct cmdlineInfo cmdline;
     FILE* ifP;
-    bool eof;   /* no more images in input stream */
+    int eof;   /* no more images in input stream */
     struct pam inpam;   /* Input PAM image */
     struct pam outpam;  /* Output PNM image */
 
diff --git a/converter/other/pamtosrf.c b/converter/other/pamtosrf.c
index 19328073..3800d77c 100644
--- a/converter/other/pamtosrf.c
+++ b/converter/other/pamtosrf.c
@@ -112,7 +112,7 @@ srfAlphaFromTuple(tuple              const t,
                   const struct pam * const pamP) {
 
     uint8_t retval;
-    bool haveOpacity;
+    int haveOpacity;
     unsigned int opacityPlane;
 
     pnm_getopacity(pamP, &haveOpacity, &opacityPlane);
@@ -181,7 +181,7 @@ main(int argc, const char * argv[]) {
   struct cmdlineInfo cmdline;
   FILE *             ifP;
   struct srf         srf;
-  bool               eof;   /* No more images in input */
+  int                eof;   /* No more images in input */
   unsigned int       imageSeq;
       /* Sequence of current image in input file.  First = 0 */
 
diff --git a/converter/other/pamtosvg/pamtosvg.c b/converter/other/pamtosvg/pamtosvg.c
index 72aa4151..adf76801 100644
--- a/converter/other/pamtosvg/pamtosvg.c
+++ b/converter/other/pamtosvg/pamtosvg.c
@@ -134,7 +134,7 @@ parseCommandLine(int argc,
    Note that the strings we return are stored in the storage that
    was passed to us as the argv array.  We also trash *argv.
 --------------------------------------------------------------------------*/
-    optEntry *option_def;
+    optEntry * option_def;
     /* Instructions to pm_optParseOptions3 on how to parse our options. */
     optStruct3 opt;
 
diff --git a/converter/other/pamtotiff.c b/converter/other/pamtotiff.c
index 551909a0..0206678d 100644
--- a/converter/other/pamtotiff.c
+++ b/converter/other/pamtotiff.c
@@ -1055,7 +1055,7 @@ main(int argc, char *argv[]) {
     const char * inputFileDescription;
     FILE* ifP;
     TIFF* tifP;
-    bool eof;
+    int eof;
     unsigned int imageSeq;
 
     pnm_init(&argc, argv);
diff --git a/converter/other/pamtowinicon.c b/converter/other/pamtowinicon.c
new file mode 100644
index 00000000..c67267e4
--- /dev/null
+++ b/converter/other/pamtowinicon.c
@@ -0,0 +1,1177 @@
+#define _POSIX_SOURCE   /* Make sure fdopen() is in <stdio.h> */
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "netpbm/pm_config.h"
+#include "netpbm/pm_c_util.h"
+#include "netpbm/mallocvar.h"
+#include "netpbm/nstring.h"
+#include "netpbm/shhopt.h"
+#include "netpbm/pm_system.h"
+#include "netpbm/pam.h"
+#include "winicon.h"
+
+
+
+struct CmdlineInfo {
+    const char * inputFileName;
+    unsigned int verbose;
+    int          pngthreshold;
+    unsigned int truetransparent;
+};
+
+
+
+static void
+parseCommandLine(int argc, const char **argv,
+                 struct CmdlineInfo * const cmdlineP) {
+
+    optEntry *   option_def;
+    unsigned int option_def_index;
+    optStruct3   opt3;
+    unsigned int pngthresholdSpec;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;
+
+    OPTENT3 (0, "verbose",         OPT_FLAG, NULL,
+             &cmdlineP->verbose,         0);
+    OPTENT3 (0, "pngthreshold",    OPT_UINT, &cmdlineP->pngthreshold,
+             &pngthresholdSpec,          0);
+    OPTENT3 (0, "truetransparent", OPT_FLAG, NULL,
+             &cmdlineP->truetransparent, 0);
+
+    opt3.opt_table     = option_def;
+    opt3.short_allowed = false;
+    opt3.allowNegNum   = false;
+
+    pm_optParseOptions3(&argc, (char **)argv, opt3, sizeof(opt3), 0);
+
+    if (pngthresholdSpec) {
+        if (UINT_MAX / cmdlineP->pngthreshold < cmdlineP->pngthreshold)
+            pm_error("-pngthreshold is too large: %u", cmdlineP->pngthreshold);
+    } else
+        cmdlineP->pngthreshold = 128;
+
+    if (argc-1 > 0) {
+        cmdlineP->inputFileName = argv[1];
+
+        if (argc-1 > 1)
+            pm_error("Too many arguments: %u.  The only non-option "
+                     "argument is the optional input file name", argc-1);
+    } else
+        cmdlineP->inputFileName = "-";
+
+    free(option_def);
+}
+
+
+
+static bool verbose;
+
+static unsigned char const pngHeader[] = PNG_HEADER;
+
+
+
+struct Palette {
+    sample color[256][3];
+    unsigned int colorCt;
+        /* Number of colors in color[][] */
+    bool tooManyColors;
+        /* There are too many colors for a BMP palette (more than 256); only
+           the first 256 are in color[][]
+        */
+};
+
+
+
+static struct IconDir *
+newIconDir() {
+
+    struct IconDir * dirP;
+
+    MALLOCVAR_NOFAIL(dirP);
+
+    dirP->zero           = 0;
+    dirP->type           = ICONDIR_TYPE_ICO;
+    dirP->count          = 0;
+
+    dirP->entriesAllocCt = 0;
+    dirP->entries        = NULL;
+
+    return dirP;
+}
+
+
+
+static void
+freeIconDir(struct IconDir * const dirP) {
+    if (dirP->entries)
+        free(dirP->entries);
+
+    free(dirP);
+}
+
+
+
+static void
+addToDirectory(struct IconDirEntry * const dirEntryP,
+               struct IconDir *      const dirP) {
+/*----------------------------------------------------------------------------
+  Add an icon to the icon directory.
+-----------------------------------------------------------------------------*/
+    if (dirP->count + 1 > dirP->entriesAllocCt) {
+        /* Out of space in dirP->entries[].  Expand. */
+
+        dirP->entriesAllocCt += 8;
+
+        REALLOCARRAY(dirP->entries, dirP->entriesAllocCt);
+
+        if (!dirP->entries)
+            pm_error("Unable to get memory for %u entries "
+                     "in the Icon directory.", dirP->entriesAllocCt);
+    }
+
+    dirP->entries[dirP->count++] = *dirEntryP;
+}
+
+
+
+typedef void (GetPixelFn) (tuple **     const tuples,
+                           unsigned int const col,
+                           unsigned int const row,
+                           sample *     const pixel);
+
+
+
+static GetPixelFn get_grayscalePixel;
+
+static void
+get_grayscalePixel(tuple **     const tuples,
+                   unsigned int const col,
+                   unsigned int const row,
+                   sample *     const pixel) {
+/*----------------------------------------------------------------------------
+   Get a pixel from a grayscale PAM
+-----------------------------------------------------------------------------*/
+    pixel[0] = tuples[row][col][0];
+    pixel[1] = tuples[row][col][0];
+    pixel[2] = tuples[row][col][0];
+}
+
+
+
+static GetPixelFn get_rgbPixel;
+
+static void
+get_rgbPixel(tuple **     const tuples,
+             unsigned int const col,
+             unsigned int const row,
+             sample *     const pixel) {
+/*----------------------------------------------------------------------------
+   Get a pixel from an RGB PAM
+-----------------------------------------------------------------------------*/
+    pixel [0] = tuples [row][col][0];
+    pixel [1] = tuples [row][col][1];
+    pixel [2] = tuples [row][col][2];
+}
+
+
+static bool
+andMakesOpaque(const struct pam * const pamP,
+               tuple **           const tuples,
+               unsigned int       const row,
+               unsigned int       const col,
+               bool               const haveAlpha,
+               unsigned int       const alphaPlane,
+               bool               const haveAnd,
+               unsigned int       const andPlane) {
+/*----------------------------------------------------------------------------
+   The AND mask makes a pixel opaque
+-----------------------------------------------------------------------------*/
+    if (haveAnd)
+        return (pamP->maxval <= tuples[row][col][andPlane]);
+    else if (haveAlpha)
+        return (pamP->maxval <= tuples[row][col][alphaPlane]);
+    else
+        /* neither alpha channel nor AND mask: full opacity */
+        return true;
+}
+
+
+
+static void
+getPalette(struct pam *     const pamP,
+           tuple **         const tuples,
+           GetPixelFn *     const getPixel,
+           struct Palette * const paletteP) {
+/*----------------------------------------------------------------------------
+  Create the palette for all the colors in 'tuples'.
+-----------------------------------------------------------------------------*/
+    unsigned int row;
+
+    paletteP->colorCt = 0;  /* initial value */
+    paletteP->tooManyColors = false;  /* initial value */
+
+    for (row = 0; pamP->height > row && !paletteP->tooManyColors; ++row) {
+        unsigned int col;
+        for (col = 0; pamP->width > col && !paletteP->tooManyColors; ++col) {
+            sample pixel[3];
+            unsigned int i;
+
+            getPixel(tuples, col, row, pixel);
+
+            for (i = 0; i < paletteP->colorCt; ++i) {
+                if ((paletteP->color[i][0] == pixel[0])
+                    && (paletteP->color[i][1] == pixel[1])
+                    && (paletteP->color[i][2] == pixel[2]))
+                    break;
+            }
+            if (i == paletteP->colorCt) {
+                /* We didn't find the color. */
+                if (paletteP->colorCt >= 256) {
+                    /* Image exceeds the palette capacity */
+                    paletteP->tooManyColors = true;
+                } else {
+                    /* Add the color to the palette */
+                    paletteP->color[paletteP->colorCt][0] = pixel[0];
+                    paletteP->color[paletteP->colorCt][1] = pixel[1];
+                    paletteP->color[paletteP->colorCt][2] = pixel[2];
+
+                    ++paletteP->colorCt;
+                }
+            }
+        }
+    }
+}
+
+
+
+static bool
+realAlphaNeeded(const struct pam * const pamP,
+                tuple **           const tuples,
+                unsigned int       const alphaPlane) {
+/*----------------------------------------------------------------------------
+  A real alpha channel (in contrast to an AND mask) is needed to represent the
+  image in 'tuples', given that 'alphaPlane' is the alpha plane.
+
+  A real alpha channel is needed if any pixel is translucent (neither opaque
+  nor transparent).
+-----------------------------------------------------------------------------*/
+    unsigned int row;
+
+    for (row = 0; row < pamP->height; ++row) {
+        unsigned int col;
+        for (col = 0; col < pamP->width; ++col) {
+            sample const opacity = tuples[row][col][alphaPlane];
+
+            if (opacity != 0 && opacity != pamP->maxval)
+                return true;
+        }
+    }
+    return false;
+}
+
+
+
+static void
+writeBmpImageHeader(unsigned int const width,
+                    unsigned int const height,
+                    unsigned int const bpp,
+                    unsigned int const rasterSize,
+                    FILE *       const ofP) {
+/*----------------------------------------------------------------------------
+
+  Write BMP image header
+    
+  Note: bm_height is sum of rows in XOR mask and AND mask, while
+  image_size is the size of the AND mask only.
+    
+  image_size does not include the sizes of the (optional) palette
+  and the (mandatory) AND mask.
+-----------------------------------------------------------------------------*/
+    pm_writelittlelongu  (ofP, 40);              /* header_size          */
+    pm_writelittlelongu  (ofP, width);           /* bm_width             */
+    pm_writelittlelongu  (ofP, height *2);       /* bm_height            */
+    pm_writelittleshortu (ofP, 1);               /* color_planes         */
+    pm_writelittleshortu (ofP, bpp);             /* bits_per_pixel       */
+    pm_writelittlelongu  (ofP, BI_RGB);          /* compression_method   */
+    pm_writelittlelongu  (ofP, rasterSize);      /* image_size           */
+    pm_writelittlelongu  (ofP, 0);               /* horizontal_resolution*/
+    pm_writelittlelongu  (ofP, 0);               /* vertical_resolution  */
+    pm_writelittlelongu  (ofP, 0);               /* colors_in_palette    */
+    pm_writelittlelongu  (ofP, 0);               /* important_colors     */
+}
+
+
+
+static void
+write32BitBmp(const struct pam *   const pamP,
+              tuple     **         const tuples,
+              GetPixelFn *         const getPixel,
+              bool                 const haveAlpha,
+              unsigned int         const alphaPlane,
+              FILE *               const ofP,
+              uint32_t *           const sizeP) {
+/*----------------------------------------------------------------------------
+  Write a 32-bit BMP encoded image to file *ofP.
+-----------------------------------------------------------------------------*/
+    int row;
+    
+    writeBmpImageHeader(pamP->width, pamP->height, 32, 
+                        pamP->width * 4 * pamP->height, ofP);
+
+    /*  write "XOR mask" */
+    for (row = pamP->height - 1; row >= 0; --row) {
+        unsigned int col;
+        for (col = 0; col < pamP->width; ++col) {
+            sample   pixel[3];
+            uint32_t val;
+
+            getPixel(tuples, col, row, pixel);
+
+            val = ((uint32_t) pixel[PAM_RED_PLANE] << 16)
+                + ((uint32_t) pixel[PAM_GRN_PLANE] <<  8)
+                + ((uint32_t) pixel[PAM_BLU_PLANE] <<  0)
+                ;
+            
+            if (haveAlpha)
+                val += (uint32_t) tuples[row][col][alphaPlane] << 24;
+
+            pm_writelittlelongu(ofP, val);
+       }
+    }
+    *sizeP = 40 + pamP->height * pamP->width * 4;
+}
+
+
+
+static void
+writeBmpPalette(const struct Palette * const paletteP,
+                unsigned int           const maxColors,
+                FILE *                 const ofP) {
+/*----------------------------------------------------------------------------
+   Write the palette of a BMP image.
+-----------------------------------------------------------------------------*/
+    unsigned int i;
+
+    for (i = 0; i < paletteP->colorCt; ++i)
+        pm_writelittlelongu(ofP, 0
+                            +(paletteP->color[i][PAM_RED_PLANE] << 16)
+                            +(paletteP->color[i][PAM_GRN_PLANE] <<  8)
+                            +(paletteP->color[i][PAM_BLU_PLANE] <<  0));
+    
+    for (; i < maxColors; ++i)
+        pm_writelittlelongu(ofP, 0);
+}
+
+
+
+static void
+writeXorMask(const struct pam *     const pamP,
+             tuple **               const tuples,
+             GetPixelFn *           const getPixel,
+             const struct Palette * const paletteP,
+             unsigned int           const bpp,
+             FILE *                 const ofP) {
+/*----------------------------------------------------------------------------
+   Write the "XOR mask" part of a BMP image.
+
+   This is what one normally thinks of as the foreground image raster.
+-----------------------------------------------------------------------------*/
+    unsigned int const maxCol = ((pamP->width * bpp + 31) & ~31) / bpp;
+
+    int row;
+                 
+    for (row = pamP->height - 1; row >= 0; --row) {
+        uint8_t  val;
+        uint16_t mask;
+        unsigned int col;
+
+        mask = 0x1;
+        val  = 0x0;
+
+        for (col = 0; col < pamP->width; ++col) {
+            sample pixel[3];
+            unsigned int i;
+
+            mask <<= bpp;
+            val  <<= bpp;
+
+            getPixel(tuples, col, row, pixel);
+
+            for (i = 0; i < paletteP->colorCt; ++i)
+                if (true
+                    && (pixel[0] == paletteP->color[i][0])
+                    && (pixel[1] == paletteP->color[i][1])
+                    && (pixel[2] == paletteP->color[i][2]))
+                    break;
+
+            assert(i < paletteP->colorCt);
+
+            val |= i;
+
+            if (mask > 0xFF) {
+                pm_writecharu(ofP, val);
+                mask = 0x1;
+                val  = 0x0;
+            }
+        }
+        for (; col < maxCol; ++col) {
+            mask <<= bpp;
+            val  <<= bpp;
+
+            if (mask > 0xFF) {
+                pm_writecharu(ofP, val);
+                mask = 0x1;
+            }
+        }
+    }
+}
+
+
+
+static void
+writePaletteBmp(unsigned int           const bpp,
+                const struct pam   *   const pamP,
+                tuple **               const tuples,
+                GetPixelFn *           const getPixel,
+                const struct Palette * const paletteP,
+                FILE *                 const ofP,
+                uint32_t *             const sizeP) {
+/*----------------------------------------------------------------------------
+  Write a `BMP with palette' encoded image to file *ofP.
+
+  Unless it would be smaller as a 32-bit direct image, in which case
+  write that instead.
+-----------------------------------------------------------------------------*/
+    unsigned int const maxColors = 1 << bpp;
+
+    unsigned int const rasterSize =
+        pamP->height *((pamP->width * bpp + 31) & ~31) / 8;
+
+    if (pamP->height * pamP->width * 4 <= maxColors * 4 + rasterSize)
+        write32BitBmp(pamP, tuples, getPixel, false /*haveAlpha*/, 0,
+                      ofP, sizeP);
+    else {
+        unsigned int const headerSize = 40;
+        unsigned int const paletteSize = maxColors * 4;
+
+        writeBmpImageHeader(pamP->width, pamP->height, bpp, rasterSize, ofP);
+
+        writeBmpPalette(paletteP, maxColors, ofP);
+
+        writeXorMask(pamP, tuples, getPixel, paletteP, bpp, ofP);
+
+        *sizeP = headerSize + paletteSize + rasterSize;
+    }
+}
+
+
+
+static void
+writeAndMask(const struct pam * const pamP,
+             tuple     **       const tuples,
+             bool               const haveAlpha,
+             unsigned int       const alphaPlane,
+             bool               const haveAnd,
+             unsigned int       const andPlane,
+             FILE *             const ofP,
+             uint32_t *         const sizeP) {
+/*----------------------------------------------------------------------------
+  Write the AND mask to file *ofP.
+-----------------------------------------------------------------------------*/
+    unsigned int const maxCol =((pamP->width * 1 + 31) & ~31) / 1;
+
+    int row;
+    unsigned int sizeSoFar;
+
+    sizeSoFar = 0;
+
+    for (row = pamP->height - 1; row >= 0; --row) {
+        uint8_t  val;
+        uint16_t mask;
+        unsigned int col;
+
+        mask = 0x1;
+        val  = 0x0;
+
+        for (col = 0; col < pamP->width; ++col) {
+            mask <<= 1;
+            val  <<= 1;
+
+            if (!andMakesOpaque(pamP, tuples, row, col, 
+                                haveAlpha, alphaPlane, haveAnd, andPlane))
+                val |= 0x1;
+
+            if (mask > 0xFF) {
+                pm_writecharu(ofP, val);
+                sizeSoFar += 1;
+                mask = 0x1;
+                val  = 0x0;
+            }
+        }
+        for (; col < maxCol; ++col) {
+            mask <<= 1;
+            val  <<= 1;
+
+            if (mask > 0xFF){
+                pm_writecharu(ofP, val);
+                sizeSoFar += 1;
+                mask = 0x1;
+            }
+        }
+    }
+    *sizeP = sizeSoFar;
+}
+
+
+
+static void
+makeAlphaFile(const struct pam * const imagePamP,
+              tuple **           const imageTuples,
+              unsigned int       const alphaPlane,
+              const char **      const alphaFileNameP) {
+
+    FILE * alphaFileP;
+    struct pam alphaPam;
+    tuple ** alphaTuples;
+    unsigned int row;
+    
+    pm_make_tmpfile(&alphaFileP, alphaFileNameP);
+
+    alphaPam.size   = sizeof(alphaPam);
+    alphaPam.len    = PAM_STRUCT_SIZE(tuple_type);
+    alphaPam.file   = alphaFileP;
+    alphaPam.format = PAM_FORMAT;
+    alphaPam.width  = imagePamP->width;
+    alphaPam.height = imagePamP->height;
+    alphaPam.depth  = 1;
+    alphaPam.maxval = imagePamP->maxval;
+    strcpy(alphaPam.tuple_type, PAM_PGM_TUPLETYPE);
+
+    alphaTuples = pnm_allocpamarray(&alphaPam);
+
+    assert(alphaPlane < imagePamP->depth);
+
+    for (row = 0; row < alphaPam.height; ++row) {
+        unsigned int col;
+        for (col = 0; col < alphaPam.width; ++col)
+            alphaTuples[row][col][0] = imageTuples[row][col][alphaPlane];
+    }
+
+    pnm_writepam(&alphaPam, alphaTuples);
+
+    pnm_freepamarray(alphaTuples, &alphaPam);
+
+    pm_close(alphaFileP);
+}
+
+
+
+struct AcceptToFileParm {
+    FILE *   ofP;
+    size_t * writeCtP;
+};
+
+static void
+acceptToFile(int    const pipeToSuckFd,
+             void * const accepterParm) {
+
+    struct AcceptToFileParm * const parmP = accepterParm;
+
+    FILE * const inFileP = fdopen(pipeToSuckFd, "r");
+
+    bool eof;
+    size_t copyCt;
+
+    for (eof = false, copyCt = 0; !eof; ) {
+        size_t readCt;
+        unsigned char buffer[1024];
+
+        readCt = fread(buffer, 1, sizeof(buffer), inFileP);
+
+        if (readCt == 0)
+            eof = true;
+        else {
+            size_t writeCt;
+
+            writeCt = fwrite(buffer, 1, readCt, parmP->ofP);
+
+            if (writeCt != readCt)
+                pm_error("Write to images file failed.  errno=%d (%s)",
+                         errno, strerror(errno));
+
+            copyCt += writeCt;
+        }
+    }
+    *parmP->writeCtP = copyCt;
+}
+
+
+
+static void
+writePng(const struct pam * const pamP,
+         tuple **           const tuples,
+         bool               const haveAlpha,
+         unsigned int       const alphaPlane,
+         bool               const haveAnd,
+         unsigned int       const andPlane,
+         uint32_t *         const sizeP,
+         FILE *             const ofP) {
+
+    struct pamtuples pamTuples;
+    size_t pngSize;
+    struct AcceptToFileParm acceptParm;
+    struct pam pam;
+
+    pam = *pamP;
+    pam.depth = pamP->depth - (haveAlpha ? 1 : 0) - (haveAnd ? 1 : 0);
+
+    pamTuples.pamP    = &pam;
+    pamTuples.tuplesP = (tuple ***)&tuples;
+
+    /* We're going to fork a process to add stuff to *ofP, so we flush
+       out this process' previous writes to that file first:
+    */
+    fflush(ofP);
+
+    acceptParm.ofP = ofP;
+    acceptParm.writeCtP = &pngSize;
+    
+    if (haveAlpha || haveAnd) {
+        const char * alphaFileName;
+        const char * command;
+
+        if (haveAlpha)
+            makeAlphaFile(pamP, tuples, alphaPlane, &alphaFileName);
+        else
+            makeAlphaFile(pamP, tuples, andPlane, &alphaFileName);
+
+        strcpy (pam.tuple_type,
+                pam.depth == 3 ? PAM_PPM_TUPLETYPE: PAM_PGM_TUPLETYPE);
+        
+        pm_asprintf(&command, "pnmtopng -alpha=\"%s\"", alphaFileName);
+
+        pm_system(pm_feed_from_pamtuples, &pamTuples,
+                  acceptToFile, &acceptParm,
+                  command);
+    
+        pm_strfree(command);
+    
+        unlink(alphaFileName);
+    } else {
+        pm_system(pm_feed_from_pamtuples, &pamTuples,
+                  acceptToFile, &acceptParm,
+                  "pnmtopng");
+    }
+
+    *sizeP = pngSize;
+}
+
+
+
+static void
+blackenXor(const struct pam * const pamP,
+           tuple     **       const tuples,
+           bool               const haveAlpha,
+           unsigned int       const alphaPlane,
+           bool               const haveAnd,
+           unsigned int       const andPlane) {
+/*----------------------------------------------------------------------------
+  Set all pixels marked as transparent in AND mask to black.
+-----------------------------------------------------------------------------*/
+    unsigned int row;
+
+    for (row = 0; row < pamP->height; ++row) {
+        unsigned int col;
+        for (col = 0; col < pamP->width; ++col) {
+            if (!andMakesOpaque(pamP, tuples, row, col,
+                                haveAlpha, alphaPlane, haveAnd, andPlane)) {
+                tuples[row][col][0] = PAM_BLACK;
+
+                if (pamP->depth >= 3) {
+                    tuples[row][col][1] = PAM_BLACK;
+                    tuples[row][col][2] = PAM_BLACK;
+                }
+            }
+        }
+    }
+}
+
+
+
+
+static void
+readAndScalePam(struct pam * const pamP,
+                bool         const doingPng,
+                tuple **     const tuples) {
+
+    if (doingPng) {
+        /* Read the image with its native maxval */
+        unsigned int row;
+        for (row = 0; row < pamP->height; ++row)
+            pnm_readpamrow(pamP, tuples[row]);
+    } else {
+        /* Read the image and scale to maxval 255 */
+        tuple * tuplerow;
+        unsigned int row;
+        tuplerow = pnm_allocpamrow(pamP);
+
+        for (row = 0; row < pamP->height; ++row) {
+            pnm_readpamrow(pamP, tuplerow);
+            pnm_scaletuplerow(pamP, tuples[row], tuplerow, 255);
+        }
+        pnm_freepamrow(tuplerow);
+        pamP->maxval = 255;
+    }
+}
+
+
+
+static void
+determineImageType(const struct pam * const pamP,
+                   tuple **           const tuples,
+                   GetPixelFn **      const getPixelP,
+                   bool *             const haveAlphaP,
+                   unsigned int *     const alphaPlaneP,
+                   bool *             const haveAndP,
+                   unsigned int *     const andPlaneP) {
+
+    /*  PAM input channels:
+     *
+     *  1-channel PAM: Grayscale
+     *  2-channel PAM: Grayscale +Alpha
+     *  3-channel PAM: RGB
+     *  4-channel PAM: RGB +Alpha
+     *  5-channel PAM: RGB +Alpha +AND mask
+     */
+    switch (pamP->depth) {
+    case 1:
+        *getPixelP  = get_grayscalePixel;
+        *haveAlphaP = false;
+        *haveAndP   = false;
+        break;
+
+    case 2:
+        *getPixelP = get_grayscalePixel;
+        if (realAlphaNeeded(pamP, tuples, 1)) {
+            *haveAlphaP  = true;
+            *alphaPlaneP = 1;
+            *haveAndP    = false;
+        } else {
+            *haveAlphaP = false;
+            *haveAndP   = true;
+            *andPlaneP  = 1;
+        }
+        break;
+
+    case 3:
+        *getPixelP  = get_rgbPixel;
+        *haveAlphaP = false;
+        *haveAndP   = false;
+        break;
+
+    case 4:
+        *getPixelP = get_rgbPixel;
+        if (realAlphaNeeded(pamP, tuples, 3)) {
+            *haveAlphaP  = true;
+            *alphaPlaneP = 3;
+            *haveAndP    = false;
+        } else {
+            *haveAlphaP = false;
+            *haveAndP    = true;
+            *andPlaneP  = 3;
+        }
+        break;
+
+    case 5:
+        *getPixelP   = get_rgbPixel;
+        *haveAlphaP  = true;
+        *alphaPlaneP = 3;
+        *haveAndP    = true;
+        *andPlaneP   = 4;
+        break;
+
+    default:
+        pm_error("unexpected PAM depth %u.  "
+                 "We understand depths 1-5", pamP->depth);
+        break;
+    }
+}
+
+
+
+static void
+reportImageInfo(unsigned int           const imageNum,
+                const struct pam *     const pamP,
+                const struct Palette * const paletteP,
+                bool                   const haveAlpha,
+                bool                   const haveAnd) {
+
+    const char * colorCt;
+
+    if (paletteP->tooManyColors)
+        pm_asprintf(&colorCt, "> 256");
+    else
+        pm_asprintf(&colorCt, "%u", paletteP->colorCt);
+
+    pm_message("Image %2u:"
+               " %3u x %3u x %u, %s colors%s%s",
+               imageNum,
+               pamP->width, pamP->height, pamP->depth,
+               colorCt,
+               haveAlpha ? ", alpha channel": "",
+               haveAnd ? ", AND mask": "");
+
+    pm_strfree(colorCt);
+}
+
+
+
+static void
+writeIconAndCreateDirEntry(const struct pam *     const pamP,
+                           tuple **               const tuples,
+                           GetPixelFn *           const getPixel,
+                           bool                   const doingPng,
+                           bool                   const haveAlpha,
+                           unsigned int           const alphaPlane,
+                           bool                   const haveAnd,
+                           unsigned int           const andPlane,
+                           bool                   const mustBlackenXor,
+                           const struct Palette * const paletteP,
+                           FILE *                 const ofP,
+                           struct IconDirEntry *  const dirEntryP) {
+/*----------------------------------------------------------------------------
+   Write to *ofP the icon image for the image represented by *pamP and
+   'tuples'.
+
+   Generate the information for an icon directory entry for this image
+   and return it as *dirEntryP.  ==>BUT: the 'offset' member of this
+   structure will not be meaningful. <==
+
+   Make a PNG image if 'doingPng' is true; BMP otherwise.
+
+   'haveAlpha' means that there is an alpha plane in 'tuples' and it is
+   Plane 'alphaPlane'.
+
+   'haveAnd' means that there is an AND plane in 'tuples' and it is Plane
+   'andPlane'.
+
+   *paletteP is the color palette for the icon; it contains an entry for each
+   color in 'tuples'.  Except: it may simply indicate that there are too many
+   colors in 'tuples' to have a palette.
+
+   The 'bits_per_pixel' member of the directory entry is supposed to tell the
+   color resolution of the image so the user can decide which of many versions
+   of the icon in the file to use.  But we just call it 32 bits in every case
+   except paletted BMP, where it actually relates to how many colors are in
+   the image.
+-----------------------------------------------------------------------------*/
+    dirEntryP->width          = pamP->width;
+    dirEntryP->height         = pamP->height;
+    dirEntryP->color_planes   = 1;
+    dirEntryP->zero           = 0;
+
+    if (doingPng) {
+        dirEntryP->color_count    = 0;
+        dirEntryP->bits_per_pixel = 32;
+
+        writePng(pamP, tuples, haveAlpha, alphaPlane, haveAnd, andPlane,
+                 &dirEntryP->size, ofP);
+    } else {
+        uint32_t bmpSize;
+        uint32_t andMaskSize;
+
+        if (mustBlackenXor)
+            blackenXor(pamP, tuples,
+                       haveAlpha, alphaPlane, haveAnd, andPlane);
+
+        if (haveAlpha) {
+            dirEntryP->color_count    = 0;
+            dirEntryP->bits_per_pixel = 32;
+
+            write32BitBmp(pamP, tuples, getPixel, haveAlpha, alphaPlane,
+                          ofP, &bmpSize);
+        } else if (paletteP->tooManyColors) {
+            /* Do a truecolor image */
+            dirEntryP->color_count    = 0;
+            dirEntryP->bits_per_pixel = 32;
+
+            write32BitBmp(pamP, tuples, getPixel, false /*haveAlpha*/, 0,
+                          ofP, &bmpSize);
+        } else {
+            /* Do a paletted image */
+
+            if (paletteP->colorCt <= 2) {
+                dirEntryP->color_count    = paletteP->colorCt;
+                dirEntryP->bits_per_pixel = 1;
+                    
+                writePaletteBmp(1, pamP, tuples, getPixel, paletteP,
+                                ofP, &bmpSize);
+            } else if (paletteP->colorCt <= 16) {
+                dirEntryP->color_count    = paletteP->colorCt;
+                dirEntryP->bits_per_pixel = 4;
+                    
+                writePaletteBmp(4, pamP, tuples, getPixel,paletteP,
+                                ofP, &bmpSize);
+            } else {
+                dirEntryP->color_count    = 0;
+                dirEntryP->bits_per_pixel = 8;
+                    
+                writePaletteBmp(8, pamP, tuples, getPixel, paletteP,
+                                ofP, &bmpSize);
+            }
+        }
+        writeAndMask(pamP, tuples, haveAlpha, alphaPlane, haveAnd, andPlane,
+                     ofP, &andMaskSize);
+
+        dirEntryP->size = bmpSize + andMaskSize;
+    }
+}
+
+
+
+static void
+convertOneImage(unsigned int     const imageNum,
+                FILE *           const ifP,
+                unsigned int     const pngThreshold,
+                bool             const mustBlackenXor,
+                FILE *           const ofP,
+                struct IconDir * const dirP) {
+
+    struct IconDirEntry dirEntry;
+    struct pam          pam;
+    tuple **            tuples;
+    bool                haveAlpha;
+    unsigned int        alphaPlane;
+    bool                haveAnd;
+    unsigned int        andPlane;
+    GetPixelFn *        getPixel;
+    struct Palette      palette;
+    bool                doingPng;
+        
+    /*  Output:
+     *
+     *  threshold^2 pixels or more:
+     *      no alpha channel:        PNG (RGB)
+     *      alpha channel:           PNG (RGBA)
+     *      alpha channel +AND mask: PNG (RGBA), AND mask dropped
+     *  alpha values other than 0 and maxval: 32bit +alpha BMP
+     *  no more than   2 colors:  1bit or 32bit BMP
+     *  no more than  16 colors:  4bit or 32bit BMP
+     *  no more than 256 colors:  8bit or 32bit BMP
+     *  more than    256 colors: 32bit BMP
+     */
+    pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
+
+    if (pam.width > 256 || pam.height > 256)
+        pm_error("Image %u: too large as a windows icon (%u x %u).  "
+                 "Maximum allowed dimension is 256",
+                 imageNum, pam.width, pam.height);
+
+    tuples = pnm_allocpamarray(&pam);
+
+    doingPng = pam.width * pam.height >= pngThreshold;
+
+    readAndScalePam(&pam, doingPng, tuples);
+
+    determineImageType(&pam, tuples, &getPixel,
+                       &haveAlpha, &alphaPlane, &haveAnd, &andPlane);
+
+    getPalette(&pam, tuples, getPixel, &palette);
+
+    if (verbose)
+        reportImageInfo(imageNum, &pam, &palette, haveAlpha, haveAnd);
+
+    writeIconAndCreateDirEntry(&pam, tuples, getPixel, doingPng,
+                               haveAlpha, alphaPlane,
+                               haveAnd, andPlane,
+                               mustBlackenXor,
+                               &palette,
+                               ofP, &dirEntry);
+
+    if (verbose)
+        pm_message("Image %2u: %u bytes", imageNum, dirEntry.size);
+
+    pnm_freepamarray(tuples, &pam);
+
+    addToDirectory(&dirEntry, dirP);
+}
+
+
+
+static void
+convert(FILE *           const ifP,
+        unsigned int     const pngThreshold,
+        bool             const mustBlackenXor,
+        struct IconDir * const dirP,
+        FILE *           const ofP) {
+/*----------------------------------------------------------------------------
+  Read a (multi-image) PAM file from *ifP and convert the individual images
+  to the proper format for a Windows icon file and write those to *ofP.
+
+  Where the number of pixels in an image is at least 'pngThreshold', use
+  a PNG image.  Otherwise, use a BMP.
+-----------------------------------------------------------------------------*/
+    unsigned int imageNum;
+    int eof;
+    
+    for (imageNum = 0, eof = false; !eof; ++imageNum) {
+        convertOneImage(imageNum, ifP, pngThreshold, mustBlackenXor,
+                        ofP, dirP);
+
+        pnm_nextimage(ifP, &eof);
+    }
+}
+
+
+
+static void
+writeIconDirEntry(const struct IconDirEntry * const dirEntryP,
+                  FILE *                      const ofP) {
+        
+    pm_writecharu        (ofP, dirEntryP->width);
+    pm_writecharu        (ofP, dirEntryP->height);
+    pm_writecharu        (ofP, dirEntryP->color_count);
+    pm_writecharu        (ofP, dirEntryP->zero);
+    pm_writelittleshortu (ofP, dirEntryP->color_planes);
+    pm_writelittleshortu (ofP, dirEntryP->bits_per_pixel);
+    pm_writelittlelongu  (ofP, dirEntryP->size); 
+    pm_writelittlelongu  (ofP, dirEntryP->offset);
+}
+
+
+
+static void
+writeIconDirectory(const struct IconDir * const dirP,
+                   FILE *                 const ofP) {
+/*----------------------------------------------------------------------------
+  Write to file *ofP the icon directory described by *dirP.
+
+  *dirP's image offset members are meaningless as input.  We fill them in.
+-----------------------------------------------------------------------------*/
+    uint32_t const hsize = 6 + dirP->count * 16;
+
+    unsigned int imageNum;
+    unsigned int imageOffset;
+
+    pm_writelittleshortu(ofP, dirP->zero);
+    pm_writelittleshortu(ofP, dirP->type);
+    pm_writelittleshortu(ofP, dirP->count);
+
+    for (imageNum = 0, imageOffset = hsize;
+         imageNum < dirP->count;
+         ++imageNum) {
+
+        struct IconDirEntry * const dirEntryP = &dirP->entries[imageNum];
+        
+        pm_message("image %2u: %3u x %3u x %2u",
+                   imageNum,
+                   dirEntryP->width,
+                   dirEntryP->height,
+                   dirEntryP->bits_per_pixel);
+
+        dirEntryP->offset = imageOffset;
+
+        writeIconDirEntry(dirEntryP, ofP);
+
+        imageOffset += dirEntryP->size;
+    }
+}
+
+
+
+static void
+copyFile(FILE * const ifP,
+         FILE * const ofP) {
+
+    bool eof;
+    
+    for (eof = false; !eof; ) {
+        unsigned char buffer[1024];
+        size_t bytesRead;
+
+        bytesRead = fread(buffer, 1, sizeof(buffer), ifP);
+
+        if (bytesRead == 0)
+            eof = true;
+        else {
+            size_t bytesWritten;
+
+            bytesWritten = fwrite(buffer, 1, bytesRead, ofP);
+
+            if (bytesWritten < bytesRead)
+                pm_error("Error writing to output file.");
+        }
+    }
+}
+
+
+
+static void
+writeIconFile(const struct IconDir * const dirP,
+              FILE *                 const imagesFileP,
+              FILE *                 const ofP) {
+/*----------------------------------------------------------------------------
+  Write a windows icon file.
+
+  *dirP is the icon directory to put in it.
+
+  *imagesFileP contains all the text of the icon images.  The contents of
+  this file go verbatim into the output.
+-----------------------------------------------------------------------------*/
+    writeIconDirectory(dirP, ofP);
+
+    copyFile(imagesFileP, ofP);
+}
+
+
+
+int
+main(int argc, const char *argv []) {
+
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
+    FILE * imagesFileP;
+        /* This is the file in which we collect the individual icon
+           images to be copied later to the output.
+        */
+    struct IconDir * dirP;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    verbose = cmdline.verbose;
+
+    /* The output icon file has directory information at the top that we
+       can't know until we have looked at the input images.  So as we pass
+       through the input, we collect the directory information and generate
+       the individual icon images and store them in *imageFileP.  When we've
+       been through all of the input, we write out the directory and then
+       copy the images from *imageFileP to the output.
+    */
+
+    dirP = newIconDir();
+
+    imagesFileP = pm_tmpfile();
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    convert(ifP, SQR(cmdline.pngthreshold), cmdline.truetransparent,
+            dirP, imagesFileP);
+
+    rewind(imagesFileP);
+
+    writeIconFile(dirP, imagesFileP, stdout);
+
+    freeIconDir(dirP);
+
+    return 0;
+}
+
+
+
diff --git a/converter/other/pamtoxvmini.c b/converter/other/pamtoxvmini.c
index e1aa9b52..b57bcc74 100644
--- a/converter/other/pamtoxvmini.c
+++ b/converter/other/pamtoxvmini.c
@@ -152,14 +152,14 @@ getPaletteIndexThroughCache(struct pam *      const pamP,
    If the tuple-index association is in *paletteIndexP, use it.  If not,
    find it the hard way and add it to *palettedIndexP for the next guy.
 -----------------------------------------------------------------------------*/
-    bool found;
+    int found;
     int paletteIndex;
 
     pnm_lookuptuple(pamP, paletteHash, tuple, &found, &paletteIndex);
     if (found)
         *paletteIndexP = paletteIndex;
     else {
-        bool fits;
+        int fits;
         findClosestColor(pamP, tuple, xvPaletteP, paletteIndexP);
         
         pnm_addtotuplehash(pamP, paletteHash, tuple, *paletteIndexP, &fits);
diff --git a/converter/other/pnmtopclxl.c b/converter/other/pnmtopclxl.c
index 83fdf7bf..4cd7c4d0 100644
--- a/converter/other/pnmtopclxl.c
+++ b/converter/other/pnmtopclxl.c
@@ -1177,7 +1177,7 @@ printPages(int                 const outFd,
     while (sourceP) {
         FILE * ifP;
         struct pam pam;
-        bool eof;
+        int eof;
         unsigned int pageNum;
 
         ifP = pm_openr(sourceP->name);
diff --git a/converter/other/pnmtopng.c b/converter/other/pnmtopng.c
index edbe57f5..bcb94612 100644
--- a/converter/other/pnmtopng.c
+++ b/converter/other/pnmtopng.c
@@ -128,7 +128,6 @@ struct cmdlineInfo {
     int           filterSet;
     unsigned int  force;
     unsigned int  libversion;
-    unsigned int  compressionSpec;
     struct zlibCompression zlibCompression;
 };
 
@@ -480,6 +479,27 @@ parseCommandLine(int argc, const char ** argv,
 
 
 
+static void
+reportInputType(int    const format,
+                xelval const maxval) {
+
+    switch (PNM_FORMAT_TYPE(format)) {
+    case PBM_TYPE:
+        pm_message ("reading a PBM file");
+        break;
+    case PGM_TYPE:
+        pm_message ("reading a PGM file (maxval=%d)", maxval);
+        break;
+    case PPM_TYPE:
+        pm_message ("reading a PPM file (maxval=%d)", maxval);
+        break;
+    default:
+        assert(false);
+    }
+}
+
+
+
 static png_color_16
 xelToPngColor_16(xel    const input, 
                  xelval const maxval, 
@@ -857,7 +877,7 @@ tryTransparentColor(FILE *     const ifp,
                     pixel      const transcolor,
                     bool *     const singleColorIsTransP) {
 
-    int const pnm_type = PNM_FORMAT_TYPE(format);
+    int const pnmType = PNM_FORMAT_TYPE(format);
 
     xel * xelrow;
     bool singleColorIsTrans;
@@ -878,7 +898,7 @@ tryTransparentColor(FILE *     const ifp,
                 /* If we have a second transparent color, we're
                    disqualified
                 */
-                if (pnm_type == PPM_TYPE) {
+                if (pnmType == PPM_TYPE) {
                     if (!PPM_EQUAL(xelrow[col], transcolor))
                         singleColorIsTrans = FALSE;
                 } else {
@@ -895,7 +915,7 @@ tryTransparentColor(FILE *     const ifp,
                    the same color as our candidate transparent color,
                    that disqualifies us.
                 */
-                if (pnm_type == PPM_TYPE) {
+                if (pnmType == PPM_TYPE) {
                     if (PPM_EQUAL(xelrow[col], transcolor))
                         singleColorIsTrans = FALSE;
                 } else {
@@ -1118,6 +1138,51 @@ determineBackground(struct cmdlineInfo const cmdline,
 
 
 
+static bool
+hasColor(FILE *       const ifP,
+         unsigned int const cols,
+         unsigned int const rows,
+         xelval       const maxval,
+         int          const format,
+         pm_filepos   const rasterPos) {
+/*----------------------------------------------------------------------------
+   The image contains colors other than black, white, and gray.
+-----------------------------------------------------------------------------*/
+    bool retval;
+
+    if (PNM_FORMAT_TYPE(format) == PPM_TYPE) {
+        unsigned int row;
+        xel * xelrow;    /* malloc'ed */
+            /* The row of the input image currently being analyzed */
+        bool isGray;
+
+        xelrow = pnm_allocrow(cols);
+
+        pm_seek2(ifP, &rasterPos, sizeof(rasterPos));
+
+        for (row = 0, isGray = true; row < rows && isGray; ++row) {
+            unsigned int col;
+
+            pnm_readpnmrow(ifP, xelrow, cols, maxval, format);
+
+            for (col = 0; col < cols && isGray; ++col) {
+                    xel const p = xelrow[col];
+                if (PPM_GETR(p) != PPM_GETG(p) || PPM_GETG(p) != PPM_GETB(p))
+                    isGray = FALSE;
+            }
+        }
+
+        pnm_freerow(xelrow);
+
+        retval = !isGray;
+    } else
+        retval = false;
+
+    return retval;
+}
+
+
+
 static void
 findRedundantBits(FILE *         const ifp, 
                   int            const rasterPos, 
@@ -1819,19 +1884,19 @@ tryAlphaPalette(FILE *         const ifP,
 
 
 static void
-computePixelWidth(int            const pnm_type,
-                  unsigned int   const pnm_meaningful_bits,
+computePixelWidth(bool           const colorPng,
+                  unsigned int   const pnmMeaningfulBitCt,
                   bool           const alpha,
                   unsigned int * const bitsPerSampleP,
                   unsigned int * const bitsPerPixelP) {
 
     unsigned int bitsPerSample, bitsPerPixel;
 
-    if (pnm_type == PPM_TYPE || alpha) {
+    if (colorPng || alpha) {
         /* PNG allows only depths of 8 and 16 for a truecolor image 
            and for a grayscale image with an alpha channel.
           */
-        if (pnm_meaningful_bits > 8)
+        if (pnmMeaningfulBitCt > 8)
             bitsPerSample = 16;
         else 
             bitsPerSample = 8;
@@ -1839,24 +1904,24 @@ computePixelWidth(int            const pnm_type,
         /* A grayscale, non-colormapped, no-alpha PNG may have any 
              bit depth from 1 to 16
           */
-        if (pnm_meaningful_bits > 8)
+        if (pnmMeaningfulBitCt > 8)
             bitsPerSample = 16;
-        else if (pnm_meaningful_bits > 4)
+        else if (pnmMeaningfulBitCt > 4)
             bitsPerSample = 8;
-        else if (pnm_meaningful_bits > 2)
+        else if (pnmMeaningfulBitCt > 2)
             bitsPerSample = 4;
-        else if (pnm_meaningful_bits > 1)
+        else if (pnmMeaningfulBitCt > 1)
             bitsPerSample = 2;
         else
             bitsPerSample = 1;
     }
     if (alpha) {
-        if (pnm_type == PPM_TYPE)
+        if (colorPng)
             bitsPerPixel = 4 * bitsPerSample;
         else
             bitsPerPixel = 2 * bitsPerSample;
     } else {
-        if (pnm_type == PPM_TYPE)
+        if (colorPng)
             bitsPerPixel = 3 * bitsPerSample;
         else
             bitsPerPixel = bitsPerSample;
@@ -1904,7 +1969,7 @@ computeColorMap(FILE *         const ifP,
                 int            const cols,
                 int            const rows,
                 xelval         const maxval,
-                int            const pnmType,
+                bool           const colorPng,
                 int            const format,
                 bool           const force,
                 FILE *         const pfP,
@@ -1947,6 +2012,8 @@ computeColorMap(FILE *         const ifP,
 
   If the image is to have a background color, we return the palette index
   of that color as *backgroundIndexP.
+
+  'colorPng' means the PNG will be of the RGB variety.
 -------------------------------------------------------------------------- */
     if (force)
         pm_asprintf(noColormapReasonP, "You requested no color map");
@@ -1956,7 +2023,7 @@ computeColorMap(FILE *         const ifP,
                     maxval, PALETTEMAXVAL);
     else {
         unsigned int bitsPerPixel;
-        computePixelWidth(pnmType, pnm_meaningful_bits, alpha,
+        computePixelWidth(colorPng, pnm_meaningful_bits, alpha,
                           NULL, &bitsPerPixel);
 
         if (!pfP && bitsPerPixel == 1)
@@ -2069,9 +2136,9 @@ static void computeColorMapLookupTable(
 
 static void
 computeRasterWidth(bool           const colorMapped,
-                   unsigned int   const palette_size,
-                   int            const pnm_type,
-                   unsigned int   const pnm_meaningful_bits,
+                   unsigned int   const paletteSize,
+                   bool           const colorPng,
+                   unsigned int   const pnmMeaningfulBitCt,
                    bool           const alpha,
                    unsigned int * const bitsPerSampleP,
                    unsigned int * const bitsPerPixelP) {
@@ -2082,24 +2149,24 @@ computeRasterWidth(bool           const colorMapped,
 -----------------------------------------------------------------------------*/
     if (colorMapped) {
         /* The raster element is a palette index */
-        if (palette_size <= 2)
+        if (paletteSize <= 2)
             *bitsPerSampleP = 1;
-        else if (palette_size <= 4)
+        else if (paletteSize <= 4)
             *bitsPerSampleP = 2;
-        else if (palette_size <= 16)
+        else if (paletteSize <= 16)
             *bitsPerSampleP = 4;
         else
             *bitsPerSampleP = 8;
         *bitsPerPixelP = *bitsPerSampleP;
         if (verbose)
-            pm_message("Writing %d-bit color indexes", *bitsPerSampleP);
+            pm_message("Writing %u-bit color indexes", *bitsPerSampleP);
     } else {
         /* The raster element is an explicit pixel -- color and transparency */
-        computePixelWidth(pnm_type, pnm_meaningful_bits, alpha,
+        computePixelWidth(colorPng, pnmMeaningfulBitCt, alpha,
                           bitsPerSampleP, bitsPerPixelP);
 
         if (verbose)
-            pm_message("Writing %d bits per component per pixel", 
+            pm_message("Writing %u bits per component per pixel", 
                        *bitsPerSampleP);
     }
 }
@@ -2339,14 +2406,14 @@ doIhdrChunk(struct pngx * const pngxP,
             unsigned int  const height,
             unsigned int  const depth,
             bool          const colorMapped,
-            int           const pnmType,
+            bool          const colorPng,
             bool          const alpha) {
 
     int colorType;
 
     if (colorMapped)
         colorType = PNG_COLOR_TYPE_PALETTE;
-    else if (pnmType == PPM_TYPE)
+    else if (colorPng)
         colorType = PNG_COLOR_TYPE_RGB;
     else
         colorType = PNG_COLOR_TYPE_GRAY;
@@ -2552,252 +2619,235 @@ convertpnm(struct cmdlineInfo const cmdline,
    lazy -- it takes a great deal of work to carry all that information as
    separate arguments -- and it's only a very small violation.
 -----------------------------------------------------------------------------*/
-  xel p;
-  int rows, cols, format;
-  xelval maxval;
-      /* The maxval of the input image */
-  xelval png_maxval;
-      /* The maxval of the samples in the PNG output 
-         (must be 1, 3, 7, 15, 255, or 65535)
-      */
-  pixel transcolor;
-      /* The color that is to be transparent, with maxval equal to that
-         of the input image.
-      */
-  int transexact;  
-      /* boolean: the user wants only the exact color he specified to be
-         transparent; not just something close to it.
-      */
-  int transparent;
-  bool alpha;
-      /* There will be an alpha mask */
-  unsigned int pnm_meaningful_bits;
-  pixel backcolor;
-      /* The background color, with maxval equal to that of the input
-         image.
-      */
-  jmp_buf jmpbuf;
-  struct pngx * pngxP;
-
-  bool colorMapped;
-  pixel palettePnm[MAXCOLORS];
-  png_color palette[MAXCOLORS];
-      /* The color part of the color/alpha palette passed to the PNG
-         compressor 
-      */
-  unsigned int paletteSize;
-
-  gray transPnm[MAXCOLORS];
-  png_byte  trans[MAXCOLORS];
-      /* The alpha part of the color/alpha palette passed to the PNG
-         compressor 
-      */
-  unsigned int transSize;
-
-  colorhash_table cht;
-  coloralphahash_table caht;
-
-  unsigned int background_index;
-      /* Index into palette[] of the background color. */
-
-  gray alphaMaxval;
-  const char * noColormapReason;
-      /* The reason that we shouldn't make a colormapped PNG, or NULL if
-         we should.  malloc'ed null-terminated string.
-      */
-  unsigned int depth;
-      /* The number of bits per sample in the (uncompressed) png 
-         raster -- if the raster contains palette indices, this is the
-         number of bits in the index.
-      */
-  unsigned int fulldepth;
-      /* The total number of bits per pixel in the (uncompressed) png
-         raster, including all channels.
-      */
-  pm_filepos rasterPos;  
-      /* file position in input image file of start of image (i.e. after
-         the header)
-      */
-  xel *xelrow;    /* malloc'ed */
-      /* The row of the input image currently being processed */
-
-  int pnmType;
-  gray ** alpha_mask;
-
-  /* We initialize these guys to quiet compiler warnings: */
-  depth = 0;
-
-  errorlevel = 0;
-
-  if (setjmp(jmpbuf))
-      pm_error ("setjmp returns error condition");
-
-  pngx_create(&pngxP, PNGX_WRITE, &jmpbuf);
-
-  pnm_readpnminit(ifP, &cols, &rows, &maxval, &format);
-  pm_tell2(ifP, &rasterPos, sizeof(rasterPos));
-  pnmType = PNM_FORMAT_TYPE(format);
-
-  xelrow = pnm_allocrow(cols);
-
-  if (verbose) {
-      if (pnmType == PBM_TYPE)    
-          pm_message ("reading a PBM file");
-      else if (pnmType == PGM_TYPE)    
-          pm_message ("reading a PGM file (maxval=%d)", maxval);
-      else if (pnmType == PPM_TYPE)    
-          pm_message ("reading a PPM file (maxval=%d)", maxval);
-  }
-
-  determineTransparency(cmdline, ifP, rasterPos, cols, rows, maxval, format,
-                        afP,
-                        &alpha, &transparent, &transcolor, &transexact,
-                        &alpha_mask, &alphaMaxval);
-
-  determineBackground(cmdline, maxval, &backcolor);
-
-  /* first of all, check if we have a grayscale image written as PPM */
-
-  if (pnmType == PPM_TYPE && !cmdline.force) {
-      unsigned int row;
-      bool isgray;
-
-      isgray = TRUE;  /* initial assumption */
-      pm_seek2(ifP, &rasterPos, sizeof(rasterPos));
-      for (row = 0; row < rows && isgray; ++row) {
-          unsigned int col;
-          pnm_readpnmrow(ifP, xelrow, cols, maxval, format);
-          for (col = 0; col < cols && isgray; ++col) {
-              p = xelrow[col];
-              if (PPM_GETR(p) != PPM_GETG(p) || PPM_GETG(p) != PPM_GETB(p))
-                  isgray = FALSE;
-          }
-      }
-      if (isgray)
-          pnmType = PGM_TYPE;
-  }
-
-  /* handle `odd' maxvalues */
-
-  if (maxval > 65535 && !cmdline.downscale) {
-      pm_error("can only handle files up to 16-bit "
-               "(use -downscale to override");
-  }
-
-  findRedundantBits(ifP, rasterPos, cols, rows, maxval, format, alpha,
-                    cmdline.force, &pnm_meaningful_bits);
+    int rows, cols, format;
+    xelval maxval;
+    /* The maxval of the input image */
+    xelval pngMaxval;
+        /* The maxval of the samples in the PNG output 
+           (must be 1, 3, 7, 15, 255, or 65535)
+        */
+    pixel transcolor;
+        /* The color that is to be transparent, with maxval equal to that
+           of the input image.
+        */
+    bool transExact;  
+        /* boolean: the user wants only the exact color he specified to be
+           transparent; not just something close to it.
+        */
+    int transparent;
+    bool alpha;
+        /* There will be an alpha mask */
+    unsigned int pnmMeaningfulBitCt;
+    pixel backColor;
+        /* The background color, with maxval equal to that of the input
+           image.
+        */
+    jmp_buf jmpbuf;
+    struct pngx * pngxP;
+
+    bool colorMapped;
+    pixel palettePnm[MAXCOLORS];
+    png_color palette[MAXCOLORS];
+        /* The color part of the color/alpha palette passed to the PNG
+           compressor 
+        */
+    unsigned int paletteSize;
+
+    gray transPnm[MAXCOLORS];
+    png_byte  trans[MAXCOLORS];
+        /* The alpha part of the color/alpha palette passed to the PNG
+           compressor 
+        */
+    unsigned int transSize;
+
+    colorhash_table cht;
+    coloralphahash_table caht;
+
+    unsigned int backgroundIndex;
+        /* Index into palette[] of the background color. */
+
+    gray alphaMaxval;
+    const char * noColormapReason;
+        /* The reason that we shouldn't make a colormapped PNG, or NULL if
+           we should.  malloc'ed null-terminated string.
+        */
+    unsigned int depth;
+        /* The number of bits per sample in the (uncompressed) png 
+           raster -- if the raster contains palette indices, this is the
+           number of bits in the index.
+        */
+    unsigned int fulldepth;
+        /* The total number of bits per pixel in the (uncompressed) png
+           raster, including all channels.
+        */
+    pm_filepos rasterPos;  
+        /* file position in input image file of start of image (i.e. after
+           the header)
+        */
+    xel * xelrow;    /* malloc'ed */
+        /* The row of the input image currently being processed */
+
+    gray ** alpha_mask;
+
+    bool colorPng;
+        /* The PNG shall be of the color (RGB) variety */
+
+    /* We initialize these guys to quiet compiler warnings: */
+    depth = 0;
+
+    errorlevel = 0;
+
+    if (setjmp(jmpbuf))
+        pm_error ("setjmp returns error condition");
+
+    pngx_create(&pngxP, PNGX_WRITE, &jmpbuf);
+
+    pnm_readpnminit(ifP, &cols, &rows, &maxval, &format);
+    pm_tell2(ifP, &rasterPos, sizeof(rasterPos));
+
+    xelrow = pnm_allocrow(cols);
+
+    if (verbose)
+        reportInputType(format, maxval);
+
+    determineTransparency(cmdline, ifP, rasterPos, cols, rows, maxval, format,
+                          afP,
+                          &alpha, &transparent, &transcolor, &transExact,
+                          &alpha_mask, &alphaMaxval);
+
+    determineBackground(cmdline, maxval, &backColor);
+
+    if (cmdline.force)
+        colorPng = (PNM_FORMAT_TYPE(format) == PPM_TYPE);
+    else {
+        if (PNM_FORMAT_TYPE(format) == PPM_TYPE) {
+            colorPng = hasColor(ifP, cols, rows, maxval, format, rasterPos); 
+        } else
+            colorPng = false;
+    }
+
+
+    /* handle `odd' maxvalues */
+
+    if (maxval > 65535 && !cmdline.downscale) {
+        pm_error("can only handle files up to 16-bit "
+                 "(use -downscale to override");
+    }
+
+    findRedundantBits(ifP, rasterPos, cols, rows, maxval, format, alpha,
+                      cmdline.force, &pnmMeaningfulBitCt);
   
-  computeColorMap(ifP, rasterPos, cols, rows, maxval, pnmType, format,
-                  cmdline.force, pfP,
-                  alpha, transparent >= 0, transcolor, transexact, 
-                  !!cmdline.background, backcolor,
-                  alpha_mask, alphaMaxval, pnm_meaningful_bits,
-                  palettePnm, &paletteSize, transPnm, &transSize,
-                  &background_index, &noColormapReason);
-
-  if (noColormapReason) {
-      if (pfP)
-          pm_error("You specified a particular palette, but this image "
-                   "cannot be represented by any palette.  %s",
-                   noColormapReason);
-      if (verbose)
-          pm_message("Not using color map.  %s", noColormapReason);
-      pm_strfree(noColormapReason);
-      colorMapped = FALSE;
-  } else
-      colorMapped = TRUE;
+    computeColorMap(ifP, rasterPos, cols, rows, maxval, colorPng, format,
+                    cmdline.force, pfP,
+                    alpha, transparent >= 0, transcolor, transExact, 
+                    !!cmdline.background, backColor,
+                    alpha_mask, alphaMaxval, pnmMeaningfulBitCt,
+                    palettePnm, &paletteSize, transPnm, &transSize,
+                    &backgroundIndex, &noColormapReason);
+
+    if (noColormapReason) {
+        if (pfP)
+            pm_error("You specified a particular palette, but this image "
+                     "cannot be represented by any palette.  %s",
+                     noColormapReason);
+        if (verbose)
+            pm_message("Not using color map.  %s", noColormapReason);
+        pm_strfree(noColormapReason);
+        colorMapped = FALSE;
+    } else
+        colorMapped = TRUE;
   
-  computeColorMapLookupTable(colorMapped, palettePnm, paletteSize,
-                             transPnm, transSize, alpha, alphaMaxval,
-                             &cht, &caht);
+    computeColorMapLookupTable(colorMapped, palettePnm, paletteSize,
+                               transPnm, transSize, alpha, alphaMaxval,
+                               &cht, &caht);
 
-  computeRasterWidth(colorMapped, paletteSize, pnmType, 
-                     pnm_meaningful_bits, alpha,
-                     &depth, &fulldepth);
-  if (verbose)
-    pm_message ("writing a%s %d-bit %s%s file%s",
-                fulldepth == 8 ? "n" : "", fulldepth,
-                colorMapped ? "palette": 
-                (pnmType == PPM_TYPE ? "RGB" : "gray"),
-                alpha ? (colorMapped ? "+transparency" : "+alpha") : "",
-                cmdline.interlace ? " (interlaced)" : "");
+    computeRasterWidth(colorMapped, paletteSize, colorPng,
+                       pnmMeaningfulBitCt, alpha,
+                       &depth, &fulldepth);
+    if (verbose)
+        pm_message ("writing a%s %d-bit %s%s file%s",
+                    fulldepth == 8 ? "n" : "", fulldepth,
+                    colorMapped ? "palette": 
+                    colorPng ? "RGB" : "gray",
+                    alpha ? (colorMapped ? "+transparency" : "+alpha") : "",
+                    cmdline.interlace ? " (interlaced)" : "");
 
-  /* now write the file */
+    /* now write the file */
 
-  png_maxval = pm_bitstomaxval(depth);
+    pngMaxval = pm_bitstomaxval(depth);
 
-  if (setjmp (pnmtopng_jmpbuf_struct.jmpbuf)) {
-    pm_error ("setjmp returns error condition (2)");
-  }
+    if (setjmp (pnmtopng_jmpbuf_struct.jmpbuf)) {
+        pm_error ("setjmp returns error condition (2)");
+    }
 
-  doIhdrChunk(pngxP, cols, rows, depth, colorMapped, pnmType, alpha);
+    doIhdrChunk(pngxP, cols, rows, depth, colorMapped, colorPng, alpha);
 
-  if (cmdline.interlace)
-      pngx_setInterlaceHandling(pngxP);
+    if (cmdline.interlace)
+        pngx_setInterlaceHandling(pngxP);
 
-  doGamaChunk(cmdline, pngxP);
+    doGamaChunk(cmdline, pngxP);
 
-  doChrmChunk(cmdline, pngxP);
+    doChrmChunk(cmdline, pngxP);
 
-  doPhysChunk(cmdline, pngxP);
+    doPhysChunk(cmdline, pngxP);
 
-  if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE) {
+    if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE) {
 
-      /* creating PNG palette (Not counting the transparency palette) */
+        /* creating PNG palette (Not counting the transparency palette) */
 
-      createPngPalette(palettePnm, paletteSize, maxval,
-                       transPnm, transSize, alphaMaxval, 
-                       palette, trans);
-      pngx_setPlte(pngxP, palette, paletteSize);
+        createPngPalette(palettePnm, paletteSize, maxval,
+                         transPnm, transSize, alphaMaxval, 
+                         palette, trans);
+        pngx_setPlte(pngxP, palette, paletteSize);
 
-      doHistChunk(pngxP, cmdline.hist, palettePnm, ifP, rasterPos,
-                  cols, rows, maxval, format, cmdline.verbose);
-  }
+        doHistChunk(pngxP, cmdline.hist, palettePnm, ifP, rasterPos,
+                    cols, rows, maxval, format, cmdline.verbose);
+    }
 
-  doTrnsChunk(pngxP, trans, transSize,
-              transparent, transcolor, maxval, png_maxval);
+    doTrnsChunk(pngxP, trans, transSize,
+                transparent, transcolor, maxval, pngMaxval);
 
-  doBkgdChunk(pngxP, !!cmdline.background,
-              background_index, backcolor,
-              maxval, png_maxval, cmdline.verbose);
+    doBkgdChunk(pngxP, !!cmdline.background,
+                backgroundIndex, backColor,
+                maxval, pngMaxval, cmdline.verbose);
 
-  doSbitChunk(pngxP, png_maxval, maxval, alpha, alphaMaxval);
+    doSbitChunk(pngxP, pngMaxval, maxval, alpha, alphaMaxval);
 
-  /* tEXT and zTXT chunks */
-  if (cmdline.text || cmdline.ztxt)
-      pngtxt_read(pngxP, tfP, !!cmdline.ztxt, cmdline.verbose);
+    /* tEXT and zTXT chunks */
+    if (cmdline.text || cmdline.ztxt)
+        pngtxt_read(pngxP, tfP, !!cmdline.ztxt, cmdline.verbose);
 
-  doTimeChunk(cmdline, pngxP);
+    doTimeChunk(cmdline, pngxP);
 
-  if (cmdline.filterSet != 0)
-      pngx_setFilter(pngxP, cmdline.filterSet);
+    if (cmdline.filterSet != 0)
+        pngx_setFilter(pngxP, cmdline.filterSet);
 
-  setZlibCompression(pngxP, cmdline.zlibCompression);
+    setZlibCompression(pngxP, cmdline.zlibCompression);
 
-  png_init_io(pngxP->png_ptr, ofP);
+    png_init_io(pngxP->png_ptr, ofP);
 
-  /* write the png-info struct */
-  pngx_writeInfo(pngxP);
+    /* write the png-info struct */
+    pngx_writeInfo(pngxP);
 
-  /* let libpng take care of, e.g., bit-depth conversions */
-  pngx_setPacking(pngxP);
+    /* let libpng take care of, e.g., bit-depth conversions */
+    pngx_setPacking(pngxP);
 
-  writeRaster(pngxP, ifP, rasterPos,
-              cols, rows, maxval, format,
-              png_maxval, depth, alpha, alpha_mask, cht, caht);
+    writeRaster(pngxP, ifP, rasterPos,
+                cols, rows, maxval, format,
+                pngMaxval, depth, alpha, alpha_mask, cht, caht);
 
-  pngx_writeEnd(pngxP);
+    pngx_writeEnd(pngxP);
 
-  pngx_destroy(pngxP);
+    pngx_destroy(pngxP);
 
-  pnm_freerow(xelrow);
+    pnm_freerow(xelrow);
 
-  if (cht)
-      ppm_freecolorhash(cht);
-  if (caht)
-      freecoloralphahash(caht);
+    if (cht)
+        ppm_freecolorhash(cht);
+    if (caht)
+        freecoloralphahash(caht);
 
-  *errorLevelP = errorlevel;
+    *errorLevelP = errorlevel;
 }
 
 
diff --git a/converter/other/pnmtops.c b/converter/other/pnmtops.c
index dc55a7e3..1cf23be7 100644
--- a/converter/other/pnmtops.c
+++ b/converter/other/pnmtops.c
@@ -335,6 +335,22 @@ basebasename(const char * const filespec) {
 
 
 
+static void
+writeFile(const unsigned char * const buffer,
+          size_t                const writeCt,
+          const char *          const name,
+          FILE *                const ofP) {
+
+    size_t writtenCt;
+
+    writtenCt = fwrite(buffer, 1, writeCt, ofP);
+
+    if (writtenCt != writeCt)
+        pm_error("Error writing to %s output file", name);
+}
+
+
+
 #define MAX_FILTER_CT 10
     /* The maximum number of filters this code is capable of applying */
 
@@ -494,18 +510,12 @@ flateFilter(FILE *          const ifP,
         */
         do {
             unsigned int have;
-            size_t bytesWritten;
 
             strm.avail_out = chunkSz;
             strm.next_out = out;
             deflate(&strm, flush);
             have = chunkSz - strm.avail_out;
-            bytesWritten = fwrite(out, 1, have, ofP);
-            if (ferror(ofP) || bytesWritten != have) {
-                deflateEnd(&strm);
-                pm_error("Error writing to internal pipe during "
-                         "flate compression.");
-            }
+            writeFile(out, have, "flate filter", ofP);
         } while (strm.avail_out == 0);
         assert(strm.avail_in == 0);     /* all input is used */
 
@@ -548,10 +558,8 @@ rlePutBuffer (unsigned int    const repeat,
     if (repeat) {
         fputc(257 - count,  fP);
         fputc(repeatitem, fP);
-    } else {
-        fputc(count - 1, fP);
-        fwrite(itembuf, 1, count, fP);
-    }
+    } else
+        writeFile(itembuf, count, "rlePutBuffer", fP);
 }
 
 
@@ -673,23 +681,24 @@ asciiHexFilter(FILE *          const ifP,
     unsigned char inbuff[40], outbuff[81];
 
     for (eof = false; !eof; ) {
-        size_t bytesRead;
+        size_t readCt;
 
-        bytesRead = fread(inbuff, 1, 40, ifP);
+        readCt = fread(inbuff, 1, 40, ifP);
 
-        if (bytesRead == 0)
+        if (readCt == 0)
             eof = true;
         else {
             unsigned int i;
 
-            for (i = 0; i < bytesRead; ++i) {
+            for (i = 0; i < readCt; ++i) {
                 int const item = inbuff[i]; 
                 outbuff[i*2]   = hexits[item >> 4];
                 outbuff[i*2+1] = hexits[item & 15];
             }
         }
-        outbuff[bytesRead * 2] = '\n';
-        fwrite(outbuff, 1, bytesRead*2 + 1, ofP);
+        outbuff[readCt * 2] = '\n';
+
+        writeFile(outbuff, readCt * 2 + 1, "asciiHex filter", ofP);
     }
 
     fclose(ifP);
@@ -737,7 +746,9 @@ ascii85Filter(FILE *          const ifP,
                 outbuff[1] = value % 85 + 33;
                 outbuff[0] = value / 85 + 33;
 
-                fwrite(outbuff, 1, count + 1, ofP);
+                writeFile((const unsigned char *)outbuff, count + 1,
+                          "ASCII 85 filter", ofP);
+
                 count = value = 0;
                 outcount += 5; 
             }
@@ -759,7 +770,8 @@ ascii85Filter(FILE *          const ifP,
         outbuff[0] = value / 85 + 33;
         outbuff[count + 1] = '\n';
 
-        fwrite(outbuff, 1, count + 2, ofP);
+        writeFile((const unsigned char *)outbuff, count + 2,
+                  "ASCII 85 filter", ofP);
     }
 
     fclose(ifP);
@@ -869,13 +881,22 @@ addFilter(const char *    const description,
           OutputEncoder * const oeP,
           FILE **         const feedFilePP,
           pid_t *         const pidList) {
+/*----------------------------------------------------------------------------
+   Add a filter to the front of the chain.
 
-    pid_t pid;
+   Spawn a process to do the filtering, by running function 'filter'.
 
+   *feedFilePP is the present head of the chain.  We make the new filter
+   process write its output to that and get its input from a new pipe.
+   We update *feedFilePP to the sending end of the new pipe.
+
+   Add to the list pidList[] the PID of the process we spawn.
+-----------------------------------------------------------------------------*/
     FILE * const oldFeedFileP = *feedFilePP;
 
     FILE * newFeedFileP;
-        
+    pid_t pid;
+
     spawnFilter(oldFeedFileP, filter, oeP, &newFeedFileP, &pid);
             
     if (verbose)
@@ -883,7 +904,7 @@ addFilter(const char *    const description,
                    description, (unsigned)pid);
     
     fclose(oldFeedFileP);  /* Child keeps this open now */
-    
+
     addToPidList(pidList, pid);
 
     *feedFilePP = newFeedFileP;
@@ -1720,7 +1741,7 @@ convertRowPbm(struct pam *     const pamP,
         bitrow[colChars-1] <<= padRight;  /* right edge */
     }
 
-    fwrite(bitrow, 1, colChars, fP); 
+    writeFile(bitrow, colChars, "PBM reader", fP);
 }
 
 
@@ -1863,6 +1884,21 @@ convertRaster(struct pam * const inpamP,
 
 
 
+/* FILE MANAGEMENT: File management is pretty hairy here.  A filter, which
+   runs in its own process, needs to be able to cause its output file to
+   close because it might be an internal pipe and the next stage needs to
+   know output is done.  So the forking process must close its copy of the
+   file descriptor.  BUT: if the output of the filter is not an internal
+   pipe but this program's output, then we don't want it closed when the
+   filter terminates because we'll need it to be open for the next image
+   the program converts (with a whole new chain of filters).
+   
+   To prevent the progam output file from getting closed, we pass a
+   duplicate of it to spawnFilters() and keep the original open.
+*/
+
+
+
 static void
 convertPage(FILE *       const ifP, 
             int          const turnflag, 
diff --git a/converter/other/pstopnm.c b/converter/other/pstopnm.c
index 1dd27140..3704841b 100644
--- a/converter/other/pstopnm.c
+++ b/converter/other/pstopnm.c
@@ -18,6 +18,7 @@
 #define _XOPEN_SOURCE 500  
     /* Make sure fdopen() is in stdio.h and strdup() is in string.h */
 
+#include <assert.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>
@@ -32,8 +33,8 @@
 #include "shhopt.h"
 #include "nstring.h"
 
-enum orientation {PORTRAIT, LANDSCAPE, UNSPECIFIED};
-struct box {
+enum Orientation {PORTRAIT, LANDSCAPE, UNSPECIFIED};
+struct Box {
     /* Description of a rectangle within an image; all coordinates 
        measured in points (1/72") with lower left corner of page being the 
        origin.
@@ -45,15 +46,15 @@ struct box {
     int ury;  /* upper right Y coord */
 };
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
     const char * inputFileName;  /* Names of input files */
     unsigned int forceplain;
-    struct box extract_box;
+    struct Box extractBox;
     unsigned int nocrop;
-    unsigned int format_type;
+    unsigned int formatType;
     unsigned int verbose;
     float xborder;
     unsigned int xmax;
@@ -62,15 +63,15 @@ struct cmdlineInfo {
     unsigned int ymax;
     unsigned int ysize;  /* zero means unspecified */
     unsigned int dpi;    /* zero means unspecified */
-    enum orientation orientation;
-    unsigned int goto_stdout;
+    enum Orientation orientation;
+    unsigned int stdout;
     unsigned int textalphabits;
 };
 
 
 static void
 parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+                 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.
@@ -82,8 +83,8 @@ parseCommandLine(int argc, char ** argv,
 
     unsigned int option_def_index;
 
-    unsigned int pbm_opt, pgm_opt, ppm_opt;
-    unsigned int portrait_opt, landscape_opt;
+    unsigned int pbmOpt, pgmOpt, ppmOpt;
+    unsigned int portraitOpt, landscapeOpt;
     float llx, lly, urx, ury;
     unsigned int llxSpec, llySpec, urxSpec, urySpec;
     unsigned int xmaxSpec, ymaxSpec, xsizeSpec, ysizeSpec, dpiSpec;
@@ -98,9 +99,9 @@ parseCommandLine(int argc, char ** argv,
     OPTENT3(0, "urx",        OPT_FLOAT, &urx, &urxSpec,                  0);
     OPTENT3(0, "ury",        OPT_FLOAT, &ury, &urySpec,                  0);
     OPTENT3(0, "nocrop",     OPT_FLAG,  NULL, &cmdlineP->nocrop,         0);
-    OPTENT3(0, "pbm",        OPT_FLAG,  NULL, &pbm_opt,                  0);
-    OPTENT3(0, "pgm",        OPT_FLAG,  NULL, &pgm_opt,                  0);
-    OPTENT3(0, "ppm",        OPT_FLAG,  NULL, &ppm_opt,                  0);
+    OPTENT3(0, "pbm",        OPT_FLAG,  NULL, &pbmOpt ,                  0);
+    OPTENT3(0, "pgm",        OPT_FLAG,  NULL, &pgmOpt,                   0);
+    OPTENT3(0, "ppm",        OPT_FLAG,  NULL, &ppmOpt,                  0);
     OPTENT3(0, "verbose",    OPT_FLAG,  NULL, &cmdlineP->verbose,        0);
     OPTENT3(0, "xborder",    OPT_FLOAT, &cmdlineP->xborder, NULL,        0);
     OPTENT3(0, "xmax",       OPT_UINT,  &cmdlineP->xmax, &xmaxSpec,      0);
@@ -109,9 +110,9 @@ parseCommandLine(int argc, char ** argv,
     OPTENT3(0, "ymax",       OPT_UINT,  &cmdlineP->ymax, &ymaxSpec,      0);
     OPTENT3(0, "ysize",      OPT_UINT,  &cmdlineP->ysize, &ysizeSpec,    0);
     OPTENT3(0, "dpi",        OPT_UINT,  &cmdlineP->dpi, &dpiSpec,        0);
-    OPTENT3(0, "portrait",   OPT_FLAG,  NULL, &portrait_opt,             0);
-    OPTENT3(0, "landscape",  OPT_FLAG,  NULL, &landscape_opt,            0);
-    OPTENT3(0, "stdout",     OPT_FLAG,  NULL, &cmdlineP->goto_stdout,    0);
+    OPTENT3(0, "portrait",   OPT_FLAG,  NULL, &portraitOpt,             0);
+    OPTENT3(0, "landscape",  OPT_FLAG,  NULL, &landscapeOpt,            0);
+    OPTENT3(0, "stdout",     OPT_FLAG,  NULL, &cmdlineP->stdout,         0);
     OPTENT3(0, "textalphabits", OPT_UINT,
             &cmdlineP->textalphabits,  &textalphabitsSpec, 0);
 
@@ -149,38 +150,38 @@ parseCommandLine(int argc, char ** argv,
     } else 
         cmdlineP->ysize = 0;
 
-    if (portrait_opt && !landscape_opt)
+    if (portraitOpt && !landscapeOpt)
         cmdlineP->orientation = PORTRAIT;
-    else if (!portrait_opt && landscape_opt)
+    else if (!portraitOpt && landscapeOpt)
         cmdlineP->orientation = LANDSCAPE;
-    else if (!portrait_opt && !landscape_opt)
+    else if (!portraitOpt && !landscapeOpt)
         cmdlineP->orientation = UNSPECIFIED;
     else
         pm_error("Cannot specify both -portrait and -landscape options");
 
-    if (pbm_opt)
-        cmdlineP->format_type = PBM_TYPE;
-    else if (pgm_opt)
-        cmdlineP->format_type = PGM_TYPE;
-    else if (ppm_opt)
-        cmdlineP->format_type = PPM_TYPE;
+    if (pbmOpt)
+        cmdlineP->formatType = PBM_TYPE;
+    else if (pgmOpt)
+        cmdlineP->formatType = PGM_TYPE;
+    else if (ppmOpt)
+        cmdlineP->formatType = PPM_TYPE;
     else
-        cmdlineP->format_type = PPM_TYPE;
+        cmdlineP->formatType = PPM_TYPE;
 
     /* If any one of the 4 bounding box coordinates is given on the
        command line, we default any of the 4 that aren't.  
     */
     if (llxSpec || llySpec || urxSpec || urySpec) {
-        if (!llxSpec) cmdlineP->extract_box.llx = 72;
-        else cmdlineP->extract_box.llx = llx * 72;
-        if (!llySpec) cmdlineP->extract_box.lly = 72;
-        else cmdlineP->extract_box.lly = lly * 72;
-        if (!urxSpec) cmdlineP->extract_box.urx = 540;
-        else cmdlineP->extract_box.urx = urx * 72;
-        if (!urySpec) cmdlineP->extract_box.ury = 720;
-        else cmdlineP->extract_box.ury = ury * 72;
+        if (!llxSpec) cmdlineP->extractBox.llx = 72;
+        else cmdlineP->extractBox.llx = llx * 72;
+        if (!llySpec) cmdlineP->extractBox.lly = 72;
+        else cmdlineP->extractBox.lly = lly * 72;
+        if (!urxSpec) cmdlineP->extractBox.urx = 540;
+        else cmdlineP->extractBox.urx = urx * 72;
+        if (!urySpec) cmdlineP->extractBox.ury = 720;
+        else cmdlineP->extractBox.ury = ury * 72;
     } else {
-        cmdlineP->extract_box.llx = -1;
+        cmdlineP->extractBox.llx = -1;
     }
 
     if (dpiSpec) {
@@ -230,19 +231,19 @@ addPsToFileName(char          const origFileName[],
    *newFileNameP.
 -----------------------------------------------------------------------------*/
     struct stat statbuf;
-    int stat_rc;
+    int statRc;
 
-    stat_rc = lstat(origFileName, &statbuf);
+    statRc = lstat(origFileName, &statbuf);
     
-    if (stat_rc == 0)
+    if (statRc == 0)
         *newFileNameP = strdup(origFileName);
     else {
         const char * fileNamePlusPs;
 
         pm_asprintf(&fileNamePlusPs, "%s.ps", origFileName);
 
-        stat_rc = lstat(fileNamePlusPs, &statbuf);
-        if (stat_rc == 0)
+        statRc = lstat(fileNamePlusPs, &statbuf);
+        if (statRc == 0)
             *newFileNameP = strdup(fileNamePlusPs);
         else
             *newFileNameP = strdup(origFileName);
@@ -311,9 +312,9 @@ computeSizeResBlind(unsigned int   const xmax,
 
 
 static void
-computeSizeRes(struct cmdlineInfo const cmdline, 
-               enum orientation   const orientation, 
-               struct box         const bordered_box,
+computeSizeRes(struct CmdlineInfo const cmdline, 
+               enum Orientation   const orientation, 
+               struct Box         const borderedBox,
                unsigned int *     const xsizeP, 
                unsigned int *     const ysizeP,
                unsigned int *     const xresP, 
@@ -344,11 +345,11 @@ computeSizeRes(struct cmdlineInfo const cmdline,
         */
 
     if (orientation == LANDSCAPE) {
-        sx = bordered_box.ury - bordered_box.lly;
-        sy = bordered_box.urx - bordered_box.llx;
+        sx = borderedBox.ury - borderedBox.lly;
+        sy = borderedBox.urx - borderedBox.llx;
     } else {
-        sx = bordered_box.urx - bordered_box.llx;
-        sy = bordered_box.ury - bordered_box.lly;
+        sx = borderedBox.urx - borderedBox.llx;
+        sy = borderedBox.ury - borderedBox.lly;
     }
 
     if (cmdline.dpi) {
@@ -373,9 +374,9 @@ computeSizeRes(struct cmdlineInfo const cmdline,
 
 
 
-enum postscript_language {COMMON_POSTSCRIPT, ENCAPSULATED_POSTSCRIPT};
+enum PostscriptLanguage {COMMON_POSTSCRIPT, ENCAPSULATED_POSTSCRIPT};
 
-static enum postscript_language
+static enum PostscriptLanguage
 languageDeclaration(char const inputFileName[],
                     bool const verbose) {
 /*----------------------------------------------------------------------------
@@ -383,7 +384,7 @@ languageDeclaration(char const inputFileName[],
   (Except that if the file is on Standard Input or doesn't validly declare
   a languages, just say it is Common Postscript).
 -----------------------------------------------------------------------------*/
-    enum postscript_language language;
+    enum PostscriptLanguage language;
 
     if (streq(inputFileName, "-"))
         /* Can't read stdin, because we need it to remain positioned for the 
@@ -399,9 +400,9 @@ languageDeclaration(char const inputFileName[],
         if (fgets(line, sizeof(line), infile) == NULL)
             language = COMMON_POSTSCRIPT;
         else {
-            const char eps_header[] = " EPSF-";
+            const char epsHeader[] = " EPSF-";
 
-            if (strstr(line, eps_header))
+            if (strstr(line, epsHeader))
                 language = ENCAPSULATED_POSTSCRIPT;
             else
                 language = COMMON_POSTSCRIPT;
@@ -418,61 +419,64 @@ languageDeclaration(char const inputFileName[],
 
 
 
-static struct box
-computeBoxToExtract(struct box const cmdline_extract_box,
+static struct Box
+computeBoxToExtract(struct Box const cmdlineExtractBox,
                     char       const inputFileName[],
                     bool       const verbose) {
 
-    struct box retval;
+    struct Box retval;
 
-    if (cmdline_extract_box.llx != -1)
+    if (cmdlineExtractBox.llx != -1)
         /* User told us what box to extract, so that's what we'll do */
-        retval = cmdline_extract_box;
+        retval = cmdlineExtractBox;
     else {
         /* Try to get the bounding box from the DSC %%BoundingBox
            statement (A Postscript comment) in the input.
         */
-        struct box ps_bb;  /* Box described by %%BoundingBox stmt in input */
+        struct Box psBb;  /* Box described by %%BoundingBox stmt in input */
 
         if (streq(inputFileName, "-"))
             /* Can't read stdin, because we need it to remain
                positioned for the Ghostscript interpreter to read it.  
             */
-            ps_bb.llx = -1;
+            psBb.llx = -1;
         else {
-            FILE *infile;
-            int found_BB, eof;  /* logical */
-            infile = pm_openr(inputFileName);
+            FILE * ifP;
+            bool foundBb;
+            bool eof;
+
+            ifP = pm_openr(inputFileName);
             
-            found_BB = FALSE;
-            eof = FALSE;
-            while (!eof && !found_BB) {
+            for (foundBb = FALSE, eof = FALSE; !foundBb && !eof; ) {
                 char line[200];
-                
-                if (fgets(line, sizeof(line), infile) == NULL)
+                char * fgetsRc;
+
+                fgetsRc = fgets(line, sizeof(line), ifP);
+
+                if (fgetsRc == NULL)
                     eof = TRUE;
                 else {
                     int rc;
                     rc = sscanf(line, "%%%%BoundingBox: %d %d %d %d",
-                                &ps_bb.llx, &ps_bb.lly, 
-                                &ps_bb.urx, &ps_bb.ury);
+                                &psBb.llx, &psBb.lly, 
+                                &psBb.urx, &psBb.ury);
                     if (rc == 4) 
-                        found_BB = TRUE;
+                        foundBb = TRUE;
                 }
             }
-            fclose(infile);
+            fclose(ifP);
 
-            if (!found_BB) {
-                ps_bb.llx = -1;
+            if (!foundBb) {
+                psBb.llx = -1;
                 pm_message("Warning: no %%%%BoundingBox statement "
-                           "in the input or command line.\n"
+                           "in the input or command line.  "
                            "Will use defaults");
             }
         }
-        if (ps_bb.llx != -1) {
+        if (psBb.llx != -1) {
             if (verbose)
                 pm_message("Using %%%%BoundingBox statement from input.");
-            retval = ps_bb;
+            retval = psBb;
         } else { 
             /* Use the center of an 8.5" x 11" page with 1" border all around*/
             retval.llx = 72;
@@ -489,13 +493,14 @@ computeBoxToExtract(struct box const cmdline_extract_box,
 
 
 
-static enum orientation
-computeOrientation(struct cmdlineInfo const cmdline, 
-                   struct box         const extract_box) {
+static enum Orientation
+computeOrientation(struct CmdlineInfo const cmdline, 
+                   struct Box         const extractBox) {
 
-    enum orientation retval;
-    unsigned int const input_width  = extract_box.urx - extract_box.llx;
-    unsigned int const input_height = extract_box.ury - extract_box.lly;
+    unsigned int const inputWidth  = extractBox.urx - extractBox.llx;
+    unsigned int const inputHeight = extractBox.ury - extractBox.lly;
+
+    enum Orientation retval;
 
     if (cmdline.orientation != UNSPECIFIED)
         retval = cmdline.orientation;
@@ -506,24 +511,24 @@ computeOrientation(struct cmdlineInfo const cmdline,
                so we can't use output dimensions to make the decision.  So
                just use the input dimensions.
             */
-            if (input_height > input_width) retval = PORTRAIT;
+            if (inputHeight > inputWidth) retval = PORTRAIT;
             else retval = LANDSCAPE;
         } else {
-            int output_width, output_height;
+            unsigned int outputWidth, outputHeight;
             if (cmdline.xsize) {
                 /* He gave xsize and ysize, so that's the output size */
-                output_width = cmdline.xsize;
-                output_height = cmdline.ysize;
+                outputWidth  = cmdline.xsize;
+                outputHeight = cmdline.ysize;
             } else {
                 /* Well then we'll just use his (or default) xmax, ymax */
-                output_width = cmdline.xmax;
-                output_height = cmdline.ymax;
+                outputWidth  = cmdline.xmax;
+                outputHeight = cmdline.ymax;
             }
 
-            if (input_height > input_width && output_height > output_width)
+            if (inputHeight > inputWidth && outputHeight > outputWidth)
                 retval = PORTRAIT;
-            else if (input_height < input_width && 
-                     output_height < output_width)
+            else if (inputHeight < inputWidth && 
+                     outputHeight < outputWidth)
                 retval = PORTRAIT;
             else 
                 retval = LANDSCAPE;
@@ -534,32 +539,39 @@ computeOrientation(struct cmdlineInfo const cmdline,
 
 
 
-static struct box
-addBorders(struct box const input_box, 
-           float      const xborder_scale,
-           float      const yborder_scale,
+static struct Box
+addBorders(struct Box const inputBox, 
+           float      const xborderScale,
+           float      const yborderScale,
            bool       const verbose) {
 /*----------------------------------------------------------------------------
-   Return a box which is 'input_box' plus some borders.
+   Return a box which is 'inputBox' plus some borders.
 
-   Add left and right borders that are the fraction 'xborder_scale' of the
+   Add left and right borders that are the fraction 'xborderScale' of the
    width of the input box; likewise for top and bottom borders with 
-   'yborder_scale'.
+   'yborderScale'.
 -----------------------------------------------------------------------------*/
-    struct box retval;
+    unsigned int const leftRightBorderSize = 
+        ROUNDU((inputBox.urx - inputBox.llx) * xborderScale);
+    unsigned int const topBottomBorderSize = 
+        ROUNDU((inputBox.ury - inputBox.lly) * yborderScale);
+
+    struct Box retval;
+
 
-    const int left_right_border_size = 
-        (int) ((input_box.urx - input_box.llx) * xborder_scale + 0.5);
-    const int top_bottom_border_size = 
-        (int) ((input_box.ury - input_box.lly) * yborder_scale + 0.5);
+    assert(inputBox.urx >= inputBox.llx);
+    assert(inputBox.ury >= inputBox.lly);
 
-    retval.llx = input_box.llx - left_right_border_size;
-    retval.lly = input_box.lly - top_bottom_border_size;
-    retval.urx = input_box.urx + left_right_border_size;
-    retval.ury = input_box.ury + top_bottom_border_size;
+    assert(inputBox.llx >= leftRightBorderSize);
+    assert(inputBox.lly >= topBottomBorderSize);
+
+    retval.llx = inputBox.llx - leftRightBorderSize;
+    retval.lly = inputBox.lly - topBottomBorderSize;
+    retval.urx = inputBox.urx + leftRightBorderSize;
+    retval.ury = inputBox.ury + topBottomBorderSize;
 
     if (verbose)
-        pm_message("With borders, extracted box is ((%d,%d),(%d,%d))",
+        pm_message("With borders, extracted box is ((%u,%u),(%u,%u))",
                    retval.llx, retval.lly, retval.urx, retval.ury);
 
     return retval;
@@ -568,8 +580,8 @@ addBorders(struct box const input_box,
 
 
 static const char *
-computePstrans(struct box       const box,
-               enum orientation const orientation,
+computePstrans(struct Box       const box,
+               enum Orientation const orientation,
                int              const xsize,
                int              const ysize, 
                int              const xres,
@@ -598,11 +610,20 @@ computePstrans(struct box       const box,
 
 
 static const char *
-computeOutfileArg(struct cmdlineInfo const cmdline) {
-
+computeOutfileArg(struct CmdlineInfo const cmdline) {
+/*----------------------------------------------------------------------------
+   Determine the value for the "OutputFile" variable to pass to Ghostscript,
+   which is what tells Ghostscript where to put its output.  This is either
+   a pattern such as "foo%03d.ppm" or "-" to indicate Standard Output.
+
+   We go with "-" if, according to 'cmdline', the user asked for
+   Standard Output or is giving his input on Standard Input.  Otherwise,
+   we go with the pattern, based on the name of the input file and output
+   format type the user requested.
+-----------------------------------------------------------------------------*/
     const char * retval;  /* malloc'ed */
 
-    if (cmdline.goto_stdout)
+    if (cmdline.stdout)
         retval = strdup("-");
     else if (streq(cmdline.inputFileName, "-"))
         retval = strdup("-");
@@ -616,12 +637,12 @@ computeOutfileArg(struct cmdlineInfo const cmdline) {
             /* The input file name ends in ".ps".  Chop it off. */
             basename[strlen(basename)-3] = '\0';
 
-        switch (cmdline.format_type) {
+        switch (cmdline.formatType) {
         case PBM_TYPE: suffix = "pbm"; break;
         case PGM_TYPE: suffix = "pgm"; break;
         case PPM_TYPE: suffix = "ppm"; break;
-        default: pm_error("Internal error: invalid value for format_type: %d",
-                          cmdline.format_type);
+        default: pm_error("Internal error: invalid value for formatType: %d",
+                          cmdline.formatType);
         }
         pm_asprintf(&retval, "%s%%03d.%s", basename, suffix);
 
@@ -633,17 +654,17 @@ computeOutfileArg(struct cmdlineInfo const cmdline) {
 
 
 static const char *
-computeGsDevice(int  const format_type,
+computeGsDevice(int  const formatType,
                 bool const forceplain) {
 
     const char * basetype;
     const char * retval;
 
-    switch (format_type) {
+    switch (formatType) {
     case PBM_TYPE: basetype = "pbm"; break;
     case PGM_TYPE: basetype = "pgm"; break;
     case PPM_TYPE: basetype = "ppm"; break;
-    default: pm_error("Internal error: invalid value format_type");
+    default: pm_error("Internal error: invalid value formatType");
     }
     if (forceplain)
         retval = strdup(basetype);
@@ -703,14 +724,13 @@ findGhostscriptProg(const char ** const retvalP) {
 
 static void
 execGhostscript(int          const inputPipeFd,
-                char         const ghostscript_device[],
-                char         const outfile_arg[], 
+                char         const ghostscriptDevice[],
+                char         const outfileArg[], 
                 int          const xsize,
                 int          const ysize, 
                 int          const xres,
                 int          const yres,
                 unsigned int const textalphabits,
-                char         const inputFileName[],
                 bool         const verbose) {
     
     const char * arg0;
@@ -729,8 +749,8 @@ execGhostscript(int          const inputPipeFd,
     close(inputPipeFd);
 
     pm_asprintf(&arg0, "gs");
-    pm_asprintf(&deviceopt, "-sDEVICE=%s", ghostscript_device);
-    pm_asprintf(&outfileopt, "-sOutputFile=%s", outfile_arg);
+    pm_asprintf(&deviceopt, "-sDEVICE=%s", ghostscriptDevice);
+    pm_asprintf(&outfileopt, "-sOutputFile=%s", outfileArg);
     pm_asprintf(&gopt, "-g%dx%d", xsize, ysize);
     pm_asprintf(&ropt, "-r%dx%d", xres, yres);
     pm_asprintf(&textalphabitsopt, "-dTextAlphaBits=%u", textalphabits);
@@ -760,26 +780,26 @@ execGhostscript(int          const inputPipeFd,
 
 
 static void
-executeGhostscript(char                     const pstrans[],
-                   char                     const ghostscript_device[],
-                   char                     const outfile_arg[], 
-                   int                      const xsize,
-                   int                      const ysize, 
-                   int                      const xres,
-                   int                      const yres,
-                   unsigned int             const textalphabits,
-                   char                     const inputFileName[], 
-                   enum postscript_language const language,
-                   bool                     const verbose) {
-
-    int gs_exit;  /* wait4 exit code from Ghostscript */
-    FILE *gs;  /* Pipe to Ghostscript's standard input */
-    FILE *infile;
+executeGhostscript(char                    const pstrans[],
+                   char                    const ghostscriptDevice[],
+                   char                    const outfileArg[], 
+                   int                     const xsize,
+                   int                     const ysize, 
+                   int                     const xres,
+                   int                     const yres,
+                   unsigned int            const textalphabits,
+                   char                    const inputFileName[], 
+                   enum PostscriptLanguage const language,
+                   bool                    const verbose) {
+
+    int gsTermStatus;  /* termination status of Ghostscript process */
+    FILE * pipeToGsP;  /* Pipe to Ghostscript's standard input */
+    FILE * ifP;
     int rc;
     int eof;  /* End of file on input */
     int pipefd[2];
 
-    if (strlen(outfile_arg) > 80)
+    if (strlen(outfileArg) > 80)
         pm_error("output file spec too long.");
     
     rc = pm_pipe(pipefd);
@@ -794,20 +814,20 @@ executeGhostscript(char                     const pstrans[],
     else if (rc == 0) {
         /* Child process */
         close(pipefd[1]);
-        execGhostscript(pipefd[0], ghostscript_device, outfile_arg,
+        execGhostscript(pipefd[0], ghostscriptDevice, outfileArg,
                         xsize, ysize, xres, yres, textalphabits,
-                        inputFileName, verbose);
+                        verbose);
     } else {
         pid_t const ghostscriptPid = rc;
         int const pipeToGhostscriptFd = pipefd[1];
         /* parent process */
         close(pipefd[0]);
 
-        gs = fdopen(pipeToGhostscriptFd, "w");
-        if (gs == NULL) 
+        pipeToGsP = fdopen(pipeToGhostscriptFd, "w");
+        if (pipeToGsP == NULL) 
             pm_error("Unable to open stream on pipe to Ghostscript process.");
     
-        infile = pm_openr(inputFileName);
+        ifP = pm_openr(inputFileName);
         /*
           In encapsulated Postscript, we the encapsulator are supposed to
           handle showing the page (which we do by passing a showpage
@@ -822,12 +842,12 @@ executeGhostscript(char                     const pstrans[],
           here, I think, so I boiled it down a bit.  JM 
         */
         if (language == ENCAPSULATED_POSTSCRIPT)
-            fprintf(gs, "\n/b4_Inc_state save def /showpage { } def\n");
+            fprintf(pipeToGsP, "\n/b4_Inc_state save def /showpage { } def\n");
  
         if (verbose) 
             pm_message("Postscript prefix command: '%s'", pstrans);
 
-        fprintf(gs, "%s\n", pstrans);
+        fprintf(pipeToGsP, "%s\n", pstrans);
 
         /* If our child dies, it closes the pipe and when we next write to it,
            we get a SIGPIPE.  We must survive that signal in order to report
@@ -840,34 +860,34 @@ executeGhostscript(char                     const pstrans[],
             char buffer[4096];
             int bytes_read;
             
-            bytes_read = fread(buffer, 1, sizeof(buffer), infile);
+            bytes_read = fread(buffer, 1, sizeof(buffer), ifP);
             if (bytes_read == 0) 
                 eof = TRUE;
             else 
-                fwrite(buffer, 1, bytes_read, gs);
+                fwrite(buffer, 1, bytes_read, pipeToGsP);
         }
-        pm_close(infile);
+        pm_close(ifP);
 
         if (language == ENCAPSULATED_POSTSCRIPT)
-            fprintf(gs, "\nb4_Inc_state restore showpage\n");
+            fprintf(pipeToGsP, "\nb4_Inc_state restore showpage\n");
 
-        fclose(gs);
+        fclose(pipeToGsP);
         
-        waitpid(ghostscriptPid, &gs_exit, 0);
+        waitpid(ghostscriptPid, &gsTermStatus, 0);
         if (rc < 0)
             pm_error("Wait for Ghostscript process to terminated failed.  "
                      "errno = %d (%s)", errno, strerror(errno));
 
-        if (gs_exit != 0) {
-            if (WIFEXITED(gs_exit))
+        if (gsTermStatus != 0) {
+            if (WIFEXITED(gsTermStatus))
                 pm_error("Ghostscript failed.  Exit code=%d\n", 
-                         WEXITSTATUS(gs_exit));
-            else if (WIFSIGNALED(gs_exit))
+                         WEXITSTATUS(gsTermStatus));
+            else if (WIFSIGNALED(gsTermStatus))
                 pm_error("Ghostscript process died due to a signal %d.",
-                         WTERMSIG(gs_exit));
+                         WTERMSIG(gsTermStatus));
             else 
                 pm_error("Ghostscript process died with exit code %d", 
-                         gs_exit);
+                         gsTermStatus);
         }
     }
 }
@@ -877,22 +897,22 @@ executeGhostscript(char                     const pstrans[],
 int
 main(int argc, char ** argv) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     const char * inputFileName;  /* malloc'ed */
         /* The file specification of our Postscript input file */
     unsigned int xres, yres;    /* Resolution in pixels per inch */
     unsigned int xsize, ysize;  /* output image size in pixels */
-    struct box extract_box;
+    struct Box extractBox;
         /* coordinates of the box within the input we are to extract; i.e.
            that will become the output. 
            */
-    struct box bordered_box;
+    struct Box borderedBox;
         /* Same as above, but expanded to include borders */
 
-    enum postscript_language language;
-    enum orientation orientation;
-    const char * ghostscript_device;
-    const char * outfile_arg;
+    enum PostscriptLanguage language;
+    enum Orientation orientation;
+    const char * ghostscriptDevice;
+    const char * outfileArg;
     const char * pstrans;
 
     pnm_init(&argc, argv);
@@ -901,36 +921,36 @@ main(int argc, char ** argv) {
 
     addPsToFileName(cmdline.inputFileName, &inputFileName, cmdline.verbose);
 
-    extract_box = computeBoxToExtract(cmdline.extract_box, inputFileName, 
+    extractBox = computeBoxToExtract(cmdline.extractBox, inputFileName, 
                                       cmdline.verbose);
 
     language = languageDeclaration(inputFileName, cmdline.verbose);
     
-    orientation = computeOrientation(cmdline, extract_box);
+    orientation = computeOrientation(cmdline, extractBox);
 
-    bordered_box = addBorders(extract_box, cmdline.xborder, cmdline.yborder,
-                              cmdline.verbose);
+    borderedBox = addBorders(extractBox, cmdline.xborder, cmdline.yborder,
+                             cmdline.verbose);
 
-    computeSizeRes(cmdline, orientation, bordered_box, 
+    computeSizeRes(cmdline, orientation, borderedBox, 
                    &xsize, &ysize, &xres, &yres);
     
-    pstrans = computePstrans(bordered_box, orientation,
+    pstrans = computePstrans(borderedBox, orientation,
                              xsize, ysize, xres, yres);
 
-    outfile_arg = computeOutfileArg(cmdline);
+    outfileArg = computeOutfileArg(cmdline);
 
-    ghostscript_device = 
-        computeGsDevice(cmdline.format_type, cmdline.forceplain);
+    ghostscriptDevice = 
+        computeGsDevice(cmdline.formatType, cmdline.forceplain);
     
-    pm_message("Writing %s file", ghostscript_device);
+    pm_message("Writing %s format", ghostscriptDevice);
     
-    executeGhostscript(pstrans, ghostscript_device, outfile_arg, 
+    executeGhostscript(pstrans, ghostscriptDevice, outfileArg, 
                        xsize, ysize, xres, yres, cmdline.textalphabits,
                        inputFileName,
                        language, cmdline.verbose);
 
-    pm_strfree(ghostscript_device);
-    pm_strfree(outfile_arg);
+    pm_strfree(ghostscriptDevice);
+    pm_strfree(outfileArg);
     pm_strfree(pstrans);
     
     return 0;
diff --git a/converter/other/winicon.h b/converter/other/winicon.h
new file mode 100644
index 00000000..9ede01f5
--- /dev/null
+++ b/converter/other/winicon.h
@@ -0,0 +1,82 @@
+#include "pm_c_util.h"
+
+#define ICONDIR_TYPE_ICO (1)
+
+/*  windows icon structures  */
+struct IconDirEntry {
+    uint16_t width;               /* image width in pixels 0 == 256 */
+    uint16_t height;              /* image height in pixels 0 == 256 */
+    uint8_t  color_count;         /* 0 if bits_per_pixel >= 8 */
+    uint8_t  zero;                /* 0 */
+    uint16_t color_planes;        /* 1 */
+    uint16_t bits_per_pixel;      /* allowed values: 1, 4, 8, 16 or 32 (1) */
+    uint32_t size;                /* size of image */
+    uint32_t offset;              /* file offset of image */
+
+    uint16_t index;               /* extra field (not in file) */
+};
+
+/*  (1) This is from
+ *  http://blogs.msdn.com/b/oldnewthing/archive/2010/10/19/10077610.aspx.
+ *
+ *  However, the bpp value in the icon directory is used as a hint for
+ *  image selection only.  It seems to be legal to set this value to
+ *  zero, and e.g. in SHELL32.DLL of Win98SE, there are many 8bpp
+ *  images described as 24 bit images in the icon directory.
+ *
+ *  The bpp value of image 1 in icon 150 in SHELL32.DLL of WinXP is 24
+ *  (in header and BMP).  This may be a bug, as the 32 x 32 x 8 image
+ *  is missing, but it shows the Windows icon rendering engine is able
+ *  to cope with 24 bit images).
+ *
+ *  16bpp icons are at least rare in the wild.
+ */
+struct IconDir {
+    uint16_t zero;                /* 0 */
+    uint16_t type;                /* 1 */
+    uint16_t count;               /* number of images in icon */
+
+    unsigned int entriesAllocCt;     /* # of allocated slots in 'entries'*/
+    struct IconDirEntry * entries;   /* one entry for each image */
+};
+
+/*  BMP image structures  */
+
+struct BitmapInfoHeader {
+    uint32_t header_size;         /* >= 40 */
+    int32_t  bm_width;
+    int32_t  bm_height;
+    uint16_t color_planes;
+    uint16_t bits_per_pixel;
+    uint32_t compression_method;
+    uint32_t image_size;
+    int32_t  horizontal_resolution; /* pixels per meter (!) */
+    int32_t  vertical_resolution;   /* pixels per meter (!) */
+    uint32_t colors_in_palette;
+    uint32_t important_colors;
+
+    bool top_down;                /* extra field (not in file) */
+
+};
+
+typedef enum {
+    BI_RGB       = 0,
+    BI_BITFIELDS = 3
+
+} BiCompression;
+
+/*  PNG image structures  */
+#define PNG_HEADER { 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A /* ^Z */, '\n' }
+
+struct PngIhdr {
+    uint32_t length;              /* 13 */
+    uint32_t signature;           /* "IHDR" */
+    uint32_t width;               /* image width in pixels */
+    uint32_t height;              /* image height in pixels */
+    uint8_t  bit_depth;           /* depth per channel */
+    uint8_t  color_type;          /* recognized values: 0, 2, 3, 4 and 6 */
+    uint8_t  compression;
+    uint8_t  filter;
+    uint8_t  interlace;
+    uint32_t crc;
+};
diff --git a/converter/other/winicontopam.c b/converter/other/winicontopam.c
new file mode 100644
index 00000000..9bee8b3c
--- /dev/null
+++ b/converter/other/winicontopam.c
@@ -0,0 +1,1282 @@
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "netpbm/pm_config.h"
+#include "netpbm/pm_c_util.h"
+#include "netpbm/mallocvar.h"
+#include "netpbm/nstring.h"
+#include "netpbm/shhopt.h"
+#include "netpbm/pam.h"
+#include "netpbm/pm_system.h"
+
+#include "winicon.h"
+
+#define RED   0
+#define GRN   1
+#define BLU   2
+#define ALPHA 3
+#define CHANNEL_CHARS "RGBA"
+
+
+
+static bool verbose;
+
+
+
+struct CmdlineInfo {
+    
+    const char * inputFileName;
+    unsigned int allimages;
+    unsigned int imageSpec;
+    unsigned int image;
+    unsigned int andmasks;
+    unsigned int headerdump;
+    unsigned int verbose;
+};
+
+
+
+static void
+parseCommandLine(int argc, const char **argv,
+                 struct CmdlineInfo * const cmdlineP) {
+
+    optEntry *   option_def;
+    unsigned int option_def_index;
+    optStruct3   opt3;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;
+
+    OPTENT3 (0, "allimages",   OPT_FLAG,   NULL,
+             &cmdlineP->allimages,         0);
+    OPTENT3 (0, "image",     OPT_UINT,   &cmdlineP->image,
+             &cmdlineP->imageSpec,         0);
+    OPTENT3 (0, "andmasks",  OPT_FLAG,   NULL,
+             &cmdlineP->andmasks,          0);
+    OPTENT3 (0, "headerdump",   OPT_FLAG,   NULL,
+             &cmdlineP->headerdump,        0);
+    OPTENT3 (0, "verbose",   OPT_FLAG,   NULL,
+             &cmdlineP->verbose,           0);
+
+    opt3.opt_table     = option_def;
+    opt3.short_allowed = false;
+    opt3.allowNegNum   = false;
+
+    pm_optParseOptions3(&argc, (char **)argv, opt3, sizeof(opt3), 0);
+
+    if (cmdlineP->allimages && cmdlineP->imageSpec)
+        pm_error("You cannot specify both -allimages and -image");
+
+    if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else {
+        cmdlineP->inputFileName = argv[1];
+
+        if (argc-1 > 1)
+            pm_error("Too many arguments.  The only possible "
+                     "non-option argument is the input file name");
+    }
+        
+    free(option_def);
+}
+
+
+
+static unsigned char const pngHeader[] = PNG_HEADER;
+
+
+
+struct File {
+
+    FILE *       fileP;
+    const char * name;
+    pm_filepos   pos;
+    
+};
+
+
+
+static uint32_t
+u8_le(const unsigned char * const buf,
+      size_t                const offset) {
+
+    return buf[offset + 0];
+}
+
+
+
+static uint32_t
+u16_le(const unsigned char * const buf,
+       size_t                const offset) {
+
+    return
+        ((uint32_t)buf[offset + 0] << 0) +
+        ((uint32_t)buf[offset + 1] << 8);
+}
+
+
+
+static uint32_t
+u32_le(const unsigned char * const buf,
+       size_t                const offset) {
+
+    return 
+        ((uint32_t)buf[offset + 0] <<  0) +
+        ((uint32_t)buf[offset + 1] <<  8) +
+        ((uint32_t)buf[offset + 2] << 16) +
+        ((uint32_t)buf[offset + 3] << 24);
+}
+
+
+
+static uint32_t
+s32_le(const unsigned char * const buf,
+       size_t                const offset) {
+
+    return 
+        ((uint32_t)buf[offset + 0] <<  0) +
+        ((uint32_t)buf[offset + 1] <<  8) +
+        ((uint32_t)buf[offset + 2] << 16) +
+        ((uint32_t)buf[offset + 3] << 24);
+}
+
+
+
+static uint32_t
+u8_be(const unsigned char * const buf,
+      size_t                const offset) {
+
+    return buf[offset + 0];
+}
+
+
+
+static uint32_t
+u32_be(const unsigned char * const buf,
+       size_t                const offset) {
+    
+    return 
+        ((uint32_t)buf[offset + 0] << 24) +
+        ((uint32_t)buf[offset + 1] << 16) +
+        ((uint32_t)buf[offset + 2] <<  8) +
+        ((uint32_t)buf[offset + 3] <<  0);
+}
+
+
+
+static uint32_t
+u32_xx(const unsigned char * const buf,
+       size_t                const offset) {
+
+    uint32_t u32;
+
+    ((uint8_t*) &u32)[0] = buf[offset + 0];
+    ((uint8_t*) &u32)[1] = buf[offset + 1];
+    ((uint8_t*) &u32)[2] = buf[offset + 2];
+    ((uint8_t*) &u32)[3] = buf[offset + 3];
+
+    return (u32);
+}
+
+
+
+static int
+cmpfn(const void * const aP,
+      const void * const bP) {
+
+    const struct IconDirEntry * const dirEntryAP = aP;
+    const struct IconDirEntry * const dirEntryBP = bP;
+
+    if (dirEntryAP->offset < dirEntryBP->offset)
+        return -1;
+    else if (dirEntryAP->offset > dirEntryBP->offset)
+        return +1;
+    else
+        return 0;
+}
+
+
+
+static void
+dumpIconDir(const struct IconDir * const dirP) {
+
+    unsigned int i;
+
+    pm_message("Type: %u", dirP->type);
+    pm_message("Icon directory has %u images:", dirP->count);
+
+    for (i = 0; i < dirP->count; ++i) {
+        const struct IconDirEntry * const dirEntryP = &dirP->entries[i];
+
+        pm_message("width: %u", dirEntryP->width);
+        pm_message("height: %u", dirEntryP->height);
+        pm_message("color count: %u", dirEntryP->color_count);
+        pm_message("# color planes: %u", dirEntryP->color_planes);
+        pm_message("bits per pixel: %u", dirEntryP->bits_per_pixel);
+        pm_message("offset in file of image: %u", dirEntryP->offset);
+        pm_message("size of image: %u", dirEntryP->size);
+        pm_message("zero field: %u", dirEntryP->zero);
+    }
+}
+
+            
+
+static struct IconDir *
+readIconDir(struct File * const fP,
+            bool          const needHeaderDump) {
+
+    struct IconDir head;
+    struct IconDir * dirP;
+    uint32_t  imageIndex; /* more bits than dir.count */
+
+    pm_readlittleshortu(fP->fileP, &head.zero);
+    pm_readlittleshortu(fP->fileP, &head.type);
+    pm_readlittleshortu(fP->fileP, &head.count);
+    fP->pos += 6;
+
+    if (head.zero != 0 || head.type != ICONDIR_TYPE_ICO)
+        pm_error("Not a valid windows icon file");
+
+    MALLOCVAR(dirP);
+
+    if (dirP == NULL)
+        pm_error("Could't allocate memory for Icon directory");
+
+    MALLOCARRAY(dirP->entries, head.count);
+
+    if (dirP->entries == NULL)
+        pm_error("Could not allocate memory for %u entries in icon directory",
+                 head.count);
+
+    dirP->zero           = head.zero;
+    dirP->type           = head.type;
+    dirP->count          = head.count;
+    dirP->entriesAllocCt = head.count;
+
+    for (imageIndex = 0; imageIndex < head.count; ++imageIndex) {
+        struct IconDirEntry * const dirEntryP = &dirP->entries[imageIndex];
+
+        unsigned char widthField, heightField;
+
+        unsigned long ul;
+
+        pm_readcharu(fP->fileP, &widthField);
+        dirEntryP->width  = (widthField == 0 ? 256 : widthField);
+
+        pm_readcharu(fP->fileP, &heightField);
+        dirEntryP->height = (heightField == 0 ? 256 : heightField);
+        
+        pm_readcharu(fP->fileP, &dirEntryP->color_count);
+
+        pm_readcharu(fP->fileP, &dirEntryP->zero);
+
+        pm_readlittleshortu(fP->fileP, &dirEntryP->color_planes);
+
+        pm_readlittleshortu(fP->fileP, &dirEntryP->bits_per_pixel);
+
+        pm_readlittlelongu(fP->fileP, &ul); dirEntryP->size = ul;
+
+        pm_readlittlelongu(fP->fileP, &ul); dirEntryP->offset = ul;
+
+        fP->pos += 16;
+
+        dirEntryP->index = imageIndex;
+    }
+
+    /* The following is paranoia code only:
+     
+       I've never seen a windows icon file in the wild with having the entries
+       in the directory stored in a different order than the images
+       themselves.  However, the file format allows for it ...
+     */
+    qsort(dirP->entries, dirP->count, sizeof(struct IconDirEntry), cmpfn);
+
+    if (verbose) {
+        pm_message("%s icon directory (%u image%s):",
+                   fP->name,
+                   dirP->count, dirP->count == 1 ? "" : "s");
+        
+        for (imageIndex = 0; imageIndex < dirP->count; ++imageIndex) {
+            const struct IconDirEntry * const dirEntryP =
+                &dirP->entries[imageIndex];
+
+            uint32_t colorCt;
+
+            if (dirEntryP->bits_per_pixel == 0)
+                colorCt = 0;
+            else if (dirEntryP->bits_per_pixel >= 32)
+                colorCt = 1u << 24;
+            else
+                colorCt = 1u << dirEntryP->bits_per_pixel;
+
+            if (dirEntryP->color_count != 0 &&
+                colorCt > dirEntryP->color_count) {
+                colorCt = dirEntryP->color_count;
+            }
+            pm_message ("%5u: %3u x %3u, %8u colors, %5u bytes",
+                        dirEntryP->index,
+                        dirEntryP->width,
+                        dirEntryP->height,
+                        colorCt,
+                        dirEntryP->size);
+        }
+    }
+
+    if (needHeaderDump)
+        dumpIconDir(dirP);
+
+    return dirP;
+}
+
+
+
+static void
+freeIconDir(struct IconDir * const dirP) {
+
+    free(dirP->entries);
+    free(dirP);
+}
+
+
+
+static const unsigned char *
+readImage(struct File *         const fP,
+          struct IconDirEntry * const dirEntryP) {
+
+    size_t rc;
+    unsigned char * image;
+    uint32_t skippedCt;
+
+    /*  Don't try to read an image that is smaller than the
+        BITMAPINFOHEADER of BMP images (40 bytes).
+     
+        PNG compressed images can't be smaller than that either, as the
+        PNG header plus the mandantory IHDR and IEND chunks already take
+        8 + 25 + 12 = 35 bytes, and there is to be a IDAT chunk too.
+     */
+    if (dirEntryP->size < 40) {
+        pm_error("image %2u: format violation: too small as an image.",
+                  dirEntryP->index);
+    }
+    if ((pm_filepos) dirEntryP->offset < fP->pos)
+        pm_error("image %2u: format violation: invalid offset.",
+                 dirEntryP->index);
+
+    /* The following is paranoia code only:
+     
+       I've never seen a windows icon file in the wild with gaps between
+       the images, but the file format allows for it, and Microsoft
+       expects the user to fseek() to the start of each image.
+     */
+    skippedCt = 0;
+
+    while ((pm_filepos) dirEntryP->offset > fP->pos) {
+        if (getc(fP->fileP) == EOF) {
+            pm_error("seeking to image %u: unexpected EOF", dirEntryP->index);
+        }
+        ++fP->pos;
+        ++skippedCt;
+    }
+
+    /*  The additional four bytes are for purify and friends, as the
+        routines reading BMP XOR and AND masks might read (but not
+        evaluate) some bytes beyond the image data.
+     */
+    image = malloc(dirEntryP->size + sizeof(uint32_t));
+    if (image == NULL)
+        pm_error("out of memory.");
+
+    rc = fread (image, 1, dirEntryP->size, fP->fileP);
+    if (rc != dirEntryP->size) {
+        pm_error("reading image %2u: unexpected EOF", dirEntryP->index);
+    }
+    fP->pos += dirEntryP->size;
+
+    return image;
+}
+
+
+
+static uint8_t
+getIdx1(const unsigned char * const bitmap,
+        uint32_t              const offset,
+        int16_t               const col) {
+
+    return u8_le(bitmap, offset + (col >> 3)) >> (7 - (col & 0x07)) & 0x1;
+}
+
+
+
+static uint8_t
+getIdx4(const unsigned char * const bitmap,
+        uint32_t              const offset,
+        int16_t               const col) {
+
+    if ((col & 1) == 0x0000)
+        return u8_le(bitmap, offset + (col >> 1)) >> 4 & 0x0F;
+    else
+        return u8_le(bitmap, offset + (col >> 1)) >> 0 & 0x0F;
+}
+
+
+
+static uint8_t
+getIdx8(const unsigned char * const bitmap,
+        uint32_t              const offset,
+        int16_t               const col) {
+
+    return u8_le(bitmap, offset + col);
+}
+
+
+
+typedef unsigned char PaletteEntry[4];
+
+
+
+static void
+dumpPalette(const PaletteEntry * const palette,
+            unsigned int         const colorCt) {
+
+    unsigned int i;
+
+    for (i = 0; i < colorCt; ++i) {
+        pm_message("Color %u: (%u, %u, %u)",
+                   i, palette[i][2], palette[i][1], palette[i][0]);
+    }
+}
+
+
+
+static void
+readXorPalette(struct BitmapInfoHeader * const hdrP,
+               const unsigned char *     const bitmap,
+               uint32_t                  const maxSize,
+               tuple **                  const tuples,
+               uint16_t                  const index,
+               bool                      const needHeaderDump,
+               uint32_t *                const bytesConsumedP) {
+
+    uint32_t paletteSize;
+
+    int16_t     row;
+    const PaletteEntry * palette;
+    uint32_t    truncatedXorSize;
+    uint32_t    bytesConsumed;
+    uint32_t    bytesPerRow;
+    const unsigned char * bitmapCursor;
+    uint32_t sizeRemaining;
+  
+    uint8_t (*getIdx) (const unsigned char * bitmap,
+                       uint32_t rowOffset,
+                       int16_t col);
+  
+    if (hdrP->compression_method != BI_RGB)
+        pm_error("image %2u: invalid compression method %u.",
+                 index, hdrP->compression_method);
+
+    assert(hdrP->bits_per_pixel < 16);
+
+    switch (hdrP->bits_per_pixel) {
+    case 1:
+        if (hdrP->colors_in_palette == 0)
+            hdrP->colors_in_palette = 2;
+        getIdx = getIdx1;
+        break;
+
+    case 4:
+        if (hdrP->colors_in_palette == 0)
+            hdrP->colors_in_palette = 16;
+        getIdx = getIdx4;
+        break;
+
+    case 8:
+        if (hdrP->colors_in_palette == 0)
+            hdrP->colors_in_palette = 256;
+        getIdx = getIdx8;
+        break;
+
+    default:
+        pm_error("image %2u: "
+                 "bits per pixel is a value we don't understand: %u",
+                  index, hdrP->bits_per_pixel);
+        getIdx = NULL;
+    }
+
+    bitmapCursor = &bitmap[0];  /* initial value */
+    sizeRemaining = maxSize;    /* initial value */
+    bytesConsumed = 0;          /* initial value */
+
+    paletteSize = hdrP->colors_in_palette * 4;
+
+    if (sizeRemaining < paletteSize)
+        pm_error("image %2u: "
+                 "reading palette: image truncated.", index);
+    
+    palette = (const PaletteEntry *) bitmapCursor;
+
+    if (needHeaderDump)
+        dumpPalette(palette, hdrP->colors_in_palette);
+
+    bitmapCursor  += paletteSize;
+    sizeRemaining -= paletteSize;
+    bytesConsumed += paletteSize;
+
+    {
+        uint32_t const xorSize = (uint32_t)
+            (((hdrP->bits_per_pixel * hdrP->bm_width + 31) / 32)
+             * 4 * hdrP->bm_height / 2);
+
+        if (sizeRemaining < xorSize) {
+            pm_message("image %2u: "
+                       "reading XOR mask: image truncated.", index);
+            truncatedXorSize = sizeRemaining;
+        } else
+            truncatedXorSize = xorSize;
+    }
+
+    bytesPerRow = ((hdrP->bits_per_pixel * hdrP->bm_width + 31) / 32) * 4;
+
+    for (row = 0; hdrP->bm_height / 2 > row; ++row) {
+        uint32_t rowOffset;
+
+        if (hdrP->top_down)
+            rowOffset = row * bytesPerRow;
+        else
+            rowOffset = (hdrP->bm_height / 2 - row - 1) * bytesPerRow;
+
+        if (rowOffset + bytesPerRow <= truncatedXorSize) {
+            int16_t col;
+            for (col = 0; hdrP->bm_width > col; ++col) {
+                uint8_t const idx = getIdx(bitmapCursor, rowOffset, col);
+
+                if (idx > hdrP->colors_in_palette)
+                    pm_error("invalid palette index in row %u, column %u.",
+                             row, col);
+
+                /*  The palette is an array of little-endian 32-bit values,
+                    where the RGB value is encoded as follows:
+                 
+                    red:   bits 2^16..2^23
+                    green: bits 2^8 ..2^15
+                    blue:  bits 2^0 ..2^7
+                 */
+                tuples[row][col][PAM_RED_PLANE] = palette[idx][2];
+                tuples[row][col][PAM_GRN_PLANE] = palette[idx][1];
+                tuples[row][col][PAM_BLU_PLANE] = palette[idx][0];
+            }
+        }
+    }
+
+    bitmapCursor  += truncatedXorSize;
+    sizeRemaining -= truncatedXorSize;
+    bytesConsumed += truncatedXorSize;
+
+    *bytesConsumedP = bytesConsumed;
+}
+
+
+
+static void
+readXorBitfields(struct BitmapInfoHeader * const hdrP,
+                 const unsigned char *     const bitmap,
+                 uint32_t                  const maxSize,
+                 tuple **                  const tuples,
+                 uint16_t                  const index,
+                 bool *                    const haveAlphaP,
+                 uint32_t *                const bytesConsumedP) {
+
+    uint32_t   bitfields[4];
+    uint8_t    shift    [4];
+    sample     maxval   [4];
+
+    int16_t      row;
+    uint32_t     bytesConsumed;
+    uint32_t     bytesPerSample;
+    uint32_t     bytesPerRow;
+    const unsigned char * bitmapCursor;
+    uint32_t     sizeRemaining;
+    uint32_t     truncatedXorSize;
+
+    static uint8_t alphas [256];
+    bool         allOpaque;
+    bool         allTransparent;
+
+    bytesConsumed = 0;
+
+    if (hdrP->compression_method != BI_RGB
+        && hdrP->compression_method != BI_BITFIELDS)
+        pm_error("image %2u: invalid compression method %u.",
+                 index, hdrP->compression_method);
+
+    assert(hdrP->bits_per_pixel >= 16);
+
+    switch (hdrP->bits_per_pixel) {
+    case 16:
+        bytesPerSample = 2;
+        bitfields[RED]   = 0x7C00;
+        bitfields[GRN]   = 0x03E0;
+        bitfields[BLU]   = 0x001F;
+        bitfields[ALPHA] = 0x0000;
+        break;
+
+    case 24:
+        bytesPerSample = 3;
+        bitfields[RED]   = 0xFF0000;
+        bitfields[GRN]   = 0x00FF00;
+        bitfields[BLU]   = 0x0000FF;
+        bitfields[ALPHA] = 0x000000;
+        break;
+
+    case 32:
+        bytesPerSample = 4;
+        bitfields[RED]   = 0x00FF0000;
+        bitfields[GRN]   = 0x0000FF00;
+        bitfields[BLU]   = 0x000000FF;
+        bitfields[ALPHA] = 0xFF000000;
+        break;
+
+    default:
+        pm_error("image %2u: bits per pixel is one we don't understand: %u.",
+                 index, hdrP->bits_per_pixel);
+        bytesPerSample = 0;
+    }
+
+    bitmapCursor = &bitmap[0]; /* initial value */
+    sizeRemaining = maxSize;  /* initial value */
+
+    /*  read bit fields from image data  */
+    if (hdrP->compression_method == BI_BITFIELDS) {
+        if (sizeRemaining < 12)
+            pm_error("image %2u: "
+                     "reading bit fields: image truncated.", index);
+
+        bitfields[RED]   = u32_le(bitmapCursor, 0);
+        bitfields[GRN]   = u32_le(bitmapCursor, 4);
+        bitfields[BLU]   = u32_le(bitmapCursor, 8);
+        bitfields[ALPHA] = 0;
+
+        bitmapCursor  += 12;
+        sizeRemaining -= 12;
+        bytesConsumed += 12;
+    }
+
+    /*  determine shift and maxval from bit field for each channel */
+    {
+        unsigned int i;
+
+        for (i = 0; 4 > i; ++i) {
+            if (bitfields[i] == 0) {
+                maxval[i] = 1;
+                shift [i] = 0;
+            } else {
+                unsigned int j;
+
+                maxval[i] = bitfields[i];
+
+                for (j = 0; 32 > j; ++j) {
+                    if ((maxval[i] & 0x1) != 0)
+                        break;
+                    maxval[i] >>= 1;
+                }
+                shift[i] = j;
+            }
+
+        }
+    }
+
+    /*  read the XOR mask */
+    {
+        uint32_t const xorSize = (uint32_t)
+            (((hdrP->bits_per_pixel * hdrP->bm_width + 31) / 32)
+             * 4 * hdrP->bm_height / 2);
+
+        if (sizeRemaining < xorSize) {
+            pm_message("image %2u: "
+                       "reading XOR mask: image truncated.", index);
+            truncatedXorSize = sizeRemaining;
+        } else
+            truncatedXorSize = xorSize;
+    }
+
+    bytesPerRow = ((hdrP->bits_per_pixel * hdrP->bm_width + 31) / 32) * 4;
+    MEMSZERO(alphas);
+
+    for (row = 0, allOpaque = true, allTransparent = true;
+         hdrP->bm_height / 2 > row;
+         ++row) {
+
+        uint32_t offset;
+
+        if (hdrP->top_down)
+            offset = row * bytesPerRow;
+        else
+            offset = (hdrP->bm_height / 2 - row - 1) * bytesPerRow;
+
+        if (offset + bytesPerRow <= truncatedXorSize) {
+            unsigned int col;
+            for (col = 0; col < hdrP->bm_width; ++col) {
+                uint32_t const pixel = u32_le(bitmapCursor, offset);
+                offset += bytesPerSample;
+
+                tuples[row][col][PAM_RED_PLANE] =
+                    pnm_scalesample((pixel & bitfields[RED]) >> shift[RED],
+                                    maxval[RED], 255);
+                tuples[row][col][PAM_GRN_PLANE] =
+                    pnm_scalesample((pixel & bitfields[GRN]) >> shift[GRN],
+                                    maxval[GRN], 255);
+                tuples [row][col][PAM_BLU_PLANE]
+                    = pnm_scalesample((pixel & bitfields[BLU]) >> shift[BLU],
+                                      maxval[BLU], 255);
+
+                if (bitfields [ALPHA] != 0) {
+                    tuples[row][col][PAM_TRN_PLANE]
+                        = pnm_scalesample(
+                            (pixel & bitfields[ALPHA]) >> shift[ALPHA],
+                            maxval[ALPHA], 255);
+
+                    if (tuples[row][col][PAM_TRN_PLANE] != 0)
+                        allTransparent = false;
+
+                    if (tuples [row][col][PAM_TRN_PLANE] != 255)
+                        allOpaque = false;
+
+                    alphas[tuples[row][col][PAM_TRN_PLANE]] = !0;
+                }
+            }
+        }
+    }
+
+    bitmapCursor  += truncatedXorSize;
+    sizeRemaining -= truncatedXorSize;
+    bytesConsumed += truncatedXorSize;
+
+    /*  A fully transparent alpha channel (all zero) in XOR mask is
+        defined to be void by Microsoft, and a fully opaque alpha
+        channel (all maxval) is trivial and will be dropped.
+    */
+    *haveAlphaP = !allTransparent && !allOpaque;
+
+    if (!allTransparent && verbose) {
+        unsigned int i;
+        unsigned int c;
+
+        for (i = 0, c = 0; 256 > i; ++i) {
+            if (alphas[i] != 0)
+                ++c;
+        }
+        pm_message("image %2u: %u distinct transparency value%s",
+                   index, c, (c == 1) ? "": "s");
+    }
+    *bytesConsumedP = bytesConsumed;
+}
+
+
+
+static void
+readAnd(struct BitmapInfoHeader * const hdrP,
+        const unsigned char *     const bitmap,
+        uint32_t                  const maxSize,
+        tuple **                  const tuples,
+        uint16_t                  const index,
+        unsigned int              const plane,
+        sample                    const maxval) {
+
+    int16_t  row;
+    uint32_t bytesConsumed;
+    uint32_t bytesPerRow;
+    uint32_t sizeRemaining;
+    uint32_t truncatedAndSize;
+
+    sizeRemaining = maxSize;  /* initial value */
+    bytesConsumed = 0;  /* initial value */
+
+    {
+        uint32_t const andSize = (uint32_t)
+            (((1 * hdrP->bm_width + 31) / 32) * 4 * hdrP->bm_height / 2);
+
+        if (sizeRemaining < andSize) {
+            pm_message ("image %2u: "
+                        "Input image ends %u bytes into the %u-byte "
+                        "AND mask.  Implying remainder of mask",
+                        index, sizeRemaining, andSize);
+            truncatedAndSize = sizeRemaining;
+        } else
+            truncatedAndSize = andSize;
+    }
+
+    bytesPerRow = ((1 * hdrP->bm_width + 31) / 32) * 4;
+
+    for (row = 0; row < hdrP->bm_height / 2; ++row) {
+        uint32_t offset;
+
+        if (hdrP->top_down)
+            offset = row * bytesPerRow;
+        else
+            offset = (hdrP->bm_height / 2 - row - 1) * bytesPerRow;
+
+        if (offset + bytesPerRow <= sizeRemaining) {
+            unsigned int col;
+            
+            for (col = 0; col < hdrP->bm_width; ++col) {
+                tuples[row][col][plane] =
+                    ((u8_le(bitmap, offset + col/8)
+                      & (1 << (7 - (col & 0x7)))) == 0x00) ?
+                    maxval : 0
+                ;
+            }
+        }
+    }
+    sizeRemaining -= truncatedAndSize;
+    bytesConsumed += truncatedAndSize;
+}
+
+
+
+static void
+dumpBmpHeader(struct BitmapInfoHeader const hdr,
+              unsigned int            const imageIndex) {
+
+    pm_message("BMP header for Image %u:", imageIndex);
+
+    pm_message("header size: %u", hdr.header_size);
+    pm_message("bitmap width: %u", hdr.bm_width);
+    pm_message("bitmap height * 2: %u", hdr.bm_height);
+    pm_message("row order: %s", hdr.top_down ? "top down" : "bottom up");
+    pm_message("# color planes: %u", hdr.color_planes);
+    pm_message("bits per pixel: %u", hdr.bits_per_pixel);
+    pm_message("image size: %u", hdr.image_size);
+    pm_message("horizontal resolution: %u", hdr.horizontal_resolution);
+    pm_message("vertical resolution: %u", hdr.vertical_resolution);
+    pm_message("# colors in palette: %u", hdr.colors_in_palette);
+    pm_message("# important colors: %u", hdr.important_colors);
+}
+
+
+
+static void
+readBmpHeader(const unsigned char *     const image,
+              uint32_t                  const size,
+              unsigned int              const imageIndex,
+              bool                      const needHeaderDump,
+              struct BitmapInfoHeader * const hdrP) {
+
+    /*  BITMAPINFOHEADER structure */
+
+    if (size < 40)
+        pm_error("image %2u: reading BITMAPINFOHEADER: not enough data.",
+                 imageIndex);
+
+    hdrP->header_size           = u32_le(image,  0);
+    hdrP->bm_width              = s32_le(image,  4);
+    hdrP->bm_height             = s32_le(image,  8);
+    hdrP->color_planes          = u16_le(image, 12);
+    hdrP->bits_per_pixel        = u16_le(image, 14);
+    hdrP->compression_method    = u32_le(image, 16);
+    hdrP->image_size            = u32_le(image, 20);
+    hdrP->horizontal_resolution = s32_le(image, 24);
+    hdrP->vertical_resolution   = s32_le(image, 28);
+    hdrP->colors_in_palette     = u32_le(image, 32);
+    hdrP->important_colors      = u32_le(image, 36);
+
+    if (hdrP->bm_height > 0) {
+        hdrP->top_down = false;
+    } else {
+        hdrP->top_down   = true;
+        hdrP->bm_height *= -1;
+    }
+
+    if (hdrP->header_size < 36
+        || hdrP->bm_width == 0 || hdrP->bm_height == 0
+        || (hdrP->bm_height & 1) != 0x0000) {
+        pm_error("image %2u: format violation: invalid BMP header.",
+                 imageIndex);
+    }
+
+    if (needHeaderDump)
+        dumpBmpHeader(*hdrP, imageIndex);
+}
+
+
+
+static void
+readXorMask(struct BitmapInfoHeader * const hdrP,
+            const unsigned char *     const imageCursor,
+            uint32_t                  const imageSize,
+            tuple **                  const tuples,
+            uint16_t                  const index,
+            bool                      const needHeaderDump,
+            bool *                    const haveAlphaP,
+            uint32_t *                const bytesConsumedP) {
+/*----------------------------------------------------------------------------
+   Read the so-called XOR mask (for non-monochrome images, this is the
+   color pixmap)
+-----------------------------------------------------------------------------*/
+    /*  preset the PAM with fully opaque black (just in case the image
+        is truncated and not all pixels are filled in below).
+    */
+    {
+        unsigned int row;
+
+        for (row = 0; row < hdrP->bm_height / 2; ++row) {
+            unsigned int col;
+            for (col = 0; col < hdrP->bm_width; ++col) {
+                tuples[row][col][PAM_RED_PLANE] = 0;
+                tuples[row][col][PAM_GRN_PLANE] = 0;
+                tuples[row][col][PAM_BLU_PLANE] = 0;
+                tuples[row][col][PAM_TRN_PLANE] = 255;
+            }
+        }
+    }
+
+    if (hdrP->bits_per_pixel < 16) {
+        readXorPalette(hdrP, imageCursor, imageSize, tuples, index,
+                       needHeaderDump,
+                       bytesConsumedP);
+        *haveAlphaP = false;
+    } else
+        readXorBitfields(hdrP, imageCursor, imageSize, tuples, index,
+                         haveAlphaP, bytesConsumedP);
+}
+
+
+
+static void
+reportImage(unsigned int            const imageIndex,
+            struct BitmapInfoHeader const hdr,
+            bool                    const haveAlpha) {
+
+    const char * const style = 
+        haveAlpha ? "RGB +alpha" :
+        hdr.bits_per_pixel < 16 ? "RGB/palette" :
+        "RGB"
+        ;
+
+    pm_message("image %2u: "
+               "BMP %3u x %3u x %2u (%s)",
+               imageIndex,
+               hdr.bm_width, hdr.bm_height / 2, hdr.bits_per_pixel,
+               style);
+}
+
+
+
+static void
+convertBmp(const unsigned char * const image,
+           FILE *                const ofP,
+           struct IconDirEntry * const dirEntryP,
+           bool                  const needHeaderDump,
+           bool                  const wantAndMaskPlane) {
+    
+    struct BitmapInfoHeader hdr;
+    uint32_t                offset;
+    bool                    haveAlpha;
+    uint32_t                xorByteCt;
+
+    struct pam outpam;
+    tuple **   tuples;
+
+    readBmpHeader(image, dirEntryP->size, dirEntryP->index, needHeaderDump,
+                  &hdr);
+
+    offset = hdr.header_size;  /* Start after header */
+
+    if ((dirEntryP->width != hdr.bm_width)
+        || (dirEntryP->height != hdr.bm_height / 2)) {
+        pm_message("image %2u: "
+                   "mismatch in header and image dimensions "
+                   "(%u x %u vs. %u x %u)",
+                   dirEntryP->index,
+                   dirEntryP->width,
+                   dirEntryP->height,
+                   hdr.bm_width,
+                   hdr.bm_height / 2);
+    }
+
+    if ((dirEntryP->bits_per_pixel != 0)
+        && (dirEntryP->bits_per_pixel != hdr.bits_per_pixel)) {
+        pm_message("image %2u "
+                   "mismatch in header and image bpp value"
+                   "(%u vs. %u)",
+                   dirEntryP->index,
+                   dirEntryP->bits_per_pixel,
+                   hdr.bits_per_pixel);
+    }
+
+    outpam.size   = sizeof(struct pam);
+    outpam.len    = PAM_STRUCT_SIZE(allocation_depth);
+    outpam.file   = ofP;
+    outpam.format = PAM_FORMAT;
+    outpam.width  = hdr.bm_width;
+    outpam.height = hdr.bm_height / 2;
+    outpam.maxval = 255;
+    outpam.allocation_depth = 5;
+    outpam.depth  = 0;
+        /* Just for tuple array allocation; we set the value for the actual
+           output image below.
+        */
+
+    tuples = pnm_allocpamarray(&outpam);
+
+    readXorMask(&hdr, &image[offset], 
+                dirEntryP->size - offset,
+                tuples, dirEntryP->index, needHeaderDump,
+                &haveAlpha, &xorByteCt);
+
+    offset += xorByteCt;
+
+    {
+        /* If there is no alpha channel in XOR mask, store the AND mask to
+           the transparency plane.  Else, here are two transparency
+           maps. If requested, store the AND mask to a fifth PAM plane
+        */
+        bool haveAnd;
+        unsigned int andPlane;
+
+        if (!haveAlpha) {
+            haveAnd = true;
+            andPlane = PAM_TRN_PLANE;
+            strcpy (outpam.tuple_type, "RGB_ALPHA");
+            outpam.depth  = 4;
+        } else if (wantAndMaskPlane) {
+            haveAnd = true;
+            andPlane = PAM_TRN_PLANE + 1;
+            outpam.depth  = 5;
+            strcpy(outpam.tuple_type, "RGB_ALPHA_ANDMASK");
+        } else {
+            haveAnd = false;
+            strcpy (outpam.tuple_type, "RGB_ALPHA");
+            outpam.depth  = 4;
+        }
+        if (haveAnd) {
+            readAnd(&hdr, &image[offset], dirEntryP->size - offset,
+                    tuples, dirEntryP->index, andPlane, outpam.maxval);
+        }
+    }
+    pnm_writepam(&outpam, tuples);
+    pnm_freepamarray(tuples, &outpam);
+
+    reportImage(dirEntryP->index, hdr, haveAlpha);
+}
+
+
+
+static void
+reportPngInfo(const unsigned char * const image,
+              struct IconDirEntry * const dirEntryP) {
+    
+    struct PngIhdr ihdr;
+
+    ihdr.length      = u32_be (image, sizeof(pngHeader)  +0);
+    ihdr.signature   = u32_xx (image, sizeof(pngHeader)  +4);
+    ihdr.width       = u32_be (image, sizeof(pngHeader)  +8);
+    ihdr.height      = u32_be (image, sizeof(pngHeader) +12);
+    ihdr.bit_depth   = u8_be  (image, sizeof(pngHeader) +16);
+    ihdr.color_type  = u8_be  (image, sizeof(pngHeader) +17);
+    ihdr.compression = u8_be  (image, sizeof(pngHeader) +18);
+    ihdr.filter      = u8_be  (image, sizeof(pngHeader) +19);
+    ihdr.interlace   = u8_be  (image, sizeof(pngHeader) +20);
+
+    if ((ihdr.length != 13)
+        || ihdr.signature != *(uint32_t*)"IHDR") {
+        pm_message("image %2u: PNG (uncommonly formatted)",
+                   dirEntryP->index);
+    } else {
+        uint32_t depth;
+        const char * colorType;
+
+        switch (ihdr.color_type) {
+        case 0:
+            colorType = "grayscale";
+            depth     = ihdr.bit_depth;
+            break;
+
+        case 2:
+            colorType = "RGB";
+            depth     = ihdr.bit_depth * 3;
+            break;
+
+        case 3:
+            colorType = "RGB/palette";
+            depth     = 8;
+            break;
+
+        case 4:
+            colorType = "grayscale + alpha";
+            depth     = ihdr.bit_depth * 2;
+            break;
+
+        case 6:
+            colorType = "RGB + alpha";
+            depth     = ihdr.bit_depth * 4;
+            break;
+
+        default:
+            colorType = "unknown color system";
+            depth     = 0;
+            break;
+        }
+        pm_message("image %2u: PNG %3u x %3u x %2u (%s)",
+                   dirEntryP->index,
+                   ihdr.width, ihdr.height, depth, colorType);
+
+        if ((dirEntryP->width != ihdr.width)
+            || (dirEntryP->height != ihdr.height)) {
+            pm_message("image %2u:"
+                       " mismatch in header and image dimensions"
+                       " (%u x %u vs %u x %u)",
+                       dirEntryP->index, dirEntryP->width, dirEntryP->height,
+                       ihdr.width, ihdr.height);
+        }
+        /* Mismatch between dirEntryP->bits_per_pixel and 'depth' is
+           normal, because the creator of the winicon file doesn't necessarily
+           know the true color resolution.
+        */
+    }
+}
+
+
+
+static void
+convertPng(const unsigned char * const image,
+           FILE *                const ofP,
+           struct IconDirEntry * const dirEntryP) {
+
+    struct bufferDesc imageBuffer;
+
+    reportPngInfo(image, dirEntryP);
+
+    imageBuffer.size = dirEntryP->size;
+    imageBuffer.buffer = (unsigned char *)image;
+
+    fflush (stdout);
+    pm_system(pm_feed_from_memory, &imageBuffer,
+              NULL /* stdout accepter */, NULL,
+              "pngtopam -alphapam");
+}
+
+
+
+static uint32_t
+bestImage(struct IconDir * const dirP) {
+
+    uint32_t imageIndex;
+    uint32_t bestPixelCt;
+    uint32_t bestColorCt;
+    uint16_t best;
+
+    bestPixelCt = 0;  /* initial value */
+    bestColorCt = 0;  /* initial value */
+    best        = 0;  /* initial value */
+    
+    for (imageIndex = 0; dirP->count > imageIndex; ++imageIndex) {
+        struct IconDirEntry * const dirEntryP = &dirP->entries[imageIndex];
+
+        uint32_t const pixelCt = dirEntryP->width * dirEntryP->height;
+
+        uint32_t colorCt;
+
+        /*  32-bit icons have 24 bit color information only.
+         
+            Since NT 5.1 (aka WinXP), it is allowed to place 8-bit
+            transparency information in the remaining bits (to check,
+            you have to read all these bits in the image!), so I prefer
+            32-bit images over 24-bit images (which violate the
+            spec. anyway).
+        */
+        if (dirEntryP->bits_per_pixel > 24)
+            colorCt = 1u << 25;
+        else
+            colorCt = 1u << dirEntryP->bits_per_pixel;
+
+        if (dirEntryP->color_count != 0 && colorCt > dirEntryP->color_count)
+            colorCt = dirEntryP->color_count;
+
+        if ((pixelCt > bestPixelCt)
+            || ((pixelCt == bestPixelCt) && (colorCt > bestColorCt))) {
+            /* This is a new best */
+            bestPixelCt = pixelCt;
+            bestColorCt = colorCt;
+            best        = imageIndex;
+        }
+    }
+    return best;
+}
+
+
+
+static void
+convertImage(struct File *         const icoP,
+             struct IconDirEntry * const dirEntryP,
+             FILE *                const ofP,
+             bool                  const needHeaderDump,
+             bool                  const wantAndMaskPlane) {
+
+    const unsigned char * image;  /* malloced */
+
+    image = readImage(icoP, dirEntryP);
+
+    if (MEMEQ(image, pngHeader, sizeof (pngHeader)))
+        convertPng(image, ofP, dirEntryP);
+    else
+        convertBmp(image, ofP, dirEntryP, needHeaderDump, wantAndMaskPlane);
+
+    free((void *)image);
+}
+
+
+
+int
+main (int argc, const char *argv []) {
+
+    struct File ico;
+    struct IconDir * dirP;
+    struct CmdlineInfo cmdline;
+
+    pm_proginit (&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    verbose = cmdline.verbose;
+
+    ico.name =
+        streq(cmdline.inputFileName, "-") ?  "<stdin>" : cmdline.inputFileName;
+    ico.pos   = 0;
+    ico.fileP = pm_openr(cmdline.inputFileName);
+
+    dirP = readIconDir(&ico, cmdline.headerdump);
+
+    if (cmdline.allimages) {
+        unsigned int i;
+        for (i = 0; i < dirP->count; ++i)
+            convertImage(&ico, &dirP->entries[i], stdout,
+                         cmdline.headerdump, cmdline.andmasks);
+    } else if (cmdline.imageSpec) {
+        unsigned int i;
+        bool found;
+        for (i = 0, found = false; i < dirP->count; ++i) {
+            if (dirP->entries[i].index == cmdline.image) {
+                found = true;
+                convertImage(&ico, &dirP->entries[i], stdout,
+                             cmdline.headerdump, cmdline.andmasks);
+            }
+        }
+        if (!found)
+            pm_error("no image index %u in.input", cmdline.image);
+    } else {
+        convertImage(&ico, &dirP->entries[bestImage(dirP)], stdout,
+                     cmdline.headerdump, cmdline.andmasks);
+    }
+    
+    freeIconDir(dirP);
+
+    if (ico.fileP != stdin)
+        pm_close(ico.fileP);
+
+    return 0;
+}
+
+
+
diff --git a/converter/pbm/pbmtolj.c b/converter/pbm/pbmtolj.c
index 89dcb76c..0cceb4fe 100644
--- a/converter/pbm/pbmtolj.c
+++ b/converter/pbm/pbmtolj.c
@@ -545,7 +545,7 @@ main(int argc, char * argv[]) {
 
     struct cmdlineInfo cmdline;
     FILE * ifP;
-    bool eof;
+    int eof;
 
     pbm_init(&argc, argv);
 
diff --git a/converter/pbm/pbmtopsg3.c b/converter/pbm/pbmtopsg3.c
index 2878686b..8163b70a 100644
--- a/converter/pbm/pbmtopsg3.c
+++ b/converter/pbm/pbmtopsg3.c
@@ -323,7 +323,7 @@ doPages(FILE *         const ifP,
         unsigned int * const pagesP,
         double         const dpi) {
 
-    bool eof;
+    int eof;
     unsigned int pagesDone;
 
     eof = FALSE;
diff --git a/converter/ppm/411toppm.c b/converter/ppm/411toppm.c
index b5e3c03b..eb2372a5 100644
--- a/converter/ppm/411toppm.c
+++ b/converter/ppm/411toppm.c
@@ -192,6 +192,7 @@ YUVtoPPM(FILE  * const ifP,
 int
 main(int argc, const char **argv) {
 
+    pixval const maxval = 255;
     struct CmdlineInfo cmdline;
     FILE  * ifP;
     pixel * pixrow;
@@ -208,13 +209,16 @@ main(int argc, const char **argv) {
 
     ifP = pm_openr(cmdline.inputFileName);
 
-    ppm_writeppminit(stdout, cmdline.width, cmdline.height, 255, 0);
+    ppm_writeppminit(stdout, cmdline.width, cmdline.height, maxval, 0);
 
-    for (row = 0; row < cmdline.height; row++) {
+    for (row = 0; row < cmdline.height; ++row) {
         YUVtoPPM(ifP, cmdline.width, cmdline.height, pixrow);
-        ppm_writeppmrow(stdout, pixrow, cmdline.width, 255, 0);
+        ppm_writeppmrow(stdout, pixrow, cmdline.width, maxval, 0);
     }
 
+    if (fgetc(ifP) != EOF)
+        pm_message("Extraneous data at end of image.");
+
     pm_close(ifP);
     ppm_freerow(pixrow);
 
diff --git a/converter/ppm/ppmtompeg/bframe.c b/converter/ppm/ppmtompeg/bframe.c
index 1dbc1846..f5009d6c 100644
--- a/converter/ppm/ppmtompeg/bframe.c
+++ b/converter/ppm/ppmtompeg/bframe.c
@@ -523,7 +523,7 @@ makeNonSkipBlock(int              const y,
                  MpegFrame *      const curr, 
                  MpegFrame *      const prev, 
                  MpegFrame *      const next,
-                 boolean          const specificsOn,
+                 bool             const specificsOn,
                  int              const mbAddress,
                  int              const QScale,
                  const LumBlock * const currentBlockP,
diff --git a/converter/ppm/ppmtompeg/frame.c b/converter/ppm/ppmtompeg/frame.c
index 09f46f66..75b209f8 100644
--- a/converter/ppm/ppmtompeg/frame.c
+++ b/converter/ppm/ppmtompeg/frame.c
@@ -753,7 +753,7 @@ Frame_AllocHalf(MpegFrame * const frameP) {
  *===========================================================================*/
 void
 Frame_AllocDecoded(MpegFrame * const frameP,
-                   boolean     const makeReference) {
+                   bool        const makeReference) {
 
     if (frameP->decoded_y != NULL) {
         /* already allocated */
diff --git a/converter/ppm/ppmtompeg/headers/frames.h b/converter/ppm/ppmtompeg/headers/frames.h
index f2bcf6ae..966d9214 100644
--- a/converter/ppm/ppmtompeg/headers/frames.h
+++ b/converter/ppm/ppmtompeg/headers/frames.h
@@ -255,7 +255,6 @@ extern int gopSize;
 extern int slicesPerFrame;
 extern int blocksPerSlice;
 extern int referenceFrame;
-extern boolean specificsOn;
 extern int quietTime;       /* shut up for at least quietTime seconds;
                  * negative means shut up forever
                  */
diff --git a/converter/ppm/ppmtompeg/headers/param.h b/converter/ppm/ppmtompeg/headers/param.h
index c7f57b44..0c6d8e5c 100644
--- a/converter/ppm/ppmtompeg/headers/param.h
+++ b/converter/ppm/ppmtompeg/headers/param.h
@@ -51,7 +51,7 @@ extern char machineName[MAX_MACHINES][256];
 extern char userName[MAX_MACHINES][256];
 extern char executable[MAX_MACHINES][1024];
 extern char remoteParamFile[MAX_MACHINES][1024];
-extern boolean remote[MAX_MACHINES];
+extern bool remote[MAX_MACHINES];
 extern char currentPath[MAXPATHLEN];
 extern char currentFramePath[MAXPATHLEN];
 extern char currentGOPPath[MAXPATHLEN];
@@ -62,12 +62,21 @@ extern int realWidth, realHeight;
 extern char ioConversion[1024];
 extern char slaveConversion[1024];
 extern FILE * bitRateFile;
-extern boolean showBitRatePerFrame;
-extern boolean computeMVHist;
 extern const double VidRateNum[9];
-extern boolean keepTempFiles;
+extern bool keepTempFiles;
+extern int outputWidth, outputHeight;
+extern bool specificsOn;
+extern char specificsFile[256];
+extern char specificsDefines[1024];
+extern bool GammaCorrection;
+extern float GammaValue;
+extern char userDataFileName[256];
 
 
+/* Defined in ppmtompeg.c; computed from command line */
+extern bool showBitRatePerFrame;
+extern bool computeMVHist;
+
 /*
  * Copyright (c) 1995 The Regents of the University of California.
  * All rights reserved.
diff --git a/converter/ppm/ppmtompeg/parallel.c b/converter/ppm/ppmtompeg/parallel.c
index 50381271..2835c67c 100644
--- a/converter/ppm/ppmtompeg/parallel.c
+++ b/converter/ppm/ppmtompeg/parallel.c
@@ -968,7 +968,7 @@ IoServer(struct inputSource * const inputSourceP,
 -----------------------------------------------------------------------------*/
     int       ioPortNum;
     int       serverSocket;
-    boolean   done;
+    bool   done;
     unsigned char   *bigBuffer;
         /* A work buffer that we keep around permanently.  We increase
            its size as needed, but never shrink it.
diff --git a/converter/ppm/ppmtompeg/param.c b/converter/ppm/ppmtompeg/param.c
index 15f13473..45605981 100644
--- a/converter/ppm/ppmtompeg/param.c
+++ b/converter/ppm/ppmtompeg/param.c
@@ -73,14 +73,14 @@
 #define LAST_OPTION           15
 
 /* put any non-required options after LAST_OPTION */
-#define OPTION_RESIZE	      16
+#define OPTION_RESIZE         16
 #define OPTION_IO_CONVERT     17
 #define OPTION_SLAVE_CONVERT  18
-#define OPTION_IQTABLE	      19
-#define OPTION_NIQTABLE	      20
+#define OPTION_IQTABLE        19
+#define OPTION_NIQTABLE       20
 #define OPTION_FRAME_RATE     21
 #define OPTION_ASPECT_RATIO   22
-#define OPTION_YUV_SIZE	      23
+#define OPTION_YUV_SIZE       23
 #define OPTION_SPECIFICS      24
 #define OPTION_DEFS_SPECIFICS 25
 #define OPTION_BUFFER_SIZE    26
@@ -98,48 +98,49 @@
  * GLOBAL VARIABLES *
  *==================*/
 
-extern char currentPath[MAXPATHLEN];
-char	outputFileName[256];
-int	outputWidth, outputHeight;
+char outputFileName[256];
+int outputWidth, outputHeight;
 char inputConversion[1024];
 char ioConversion[1024];
 char slaveConversion[1024];
 char yuvConversion[256];
 char specificsFile[256],specificsDefines[1024]="";
-boolean GammaCorrection=FALSE;
-float   GammaValue;
+bool GammaCorrection=FALSE;
+float GammaValue;
 char userDataFileName[256]={0};
-boolean specificsOn = FALSE;
+bool specificsOn = FALSE;
 char currentGOPPath[MAXPATHLEN];
 char currentFramePath[MAXPATHLEN];
-boolean keepTempFiles;
+bool keepTempFiles;
+int numMachines;
+char machineName[MAX_MACHINES][256];
+char userName[MAX_MACHINES][256];
+char executable[MAX_MACHINES][1024];
+char remoteParamFile[MAX_MACHINES][1024];
+bool remote[MAX_MACHINES];
+int mult_seq_headers = 0;  /* 0 for none, N for header/N GOPs */
+
+
+extern char currentPath[MAXPATHLEN];
 
 static const char * const optionText[LAST_OPTION+1] = { 
     "GOP_SIZE", "PATTERN", "PIXEL", "PQSCALE",
     "OUTPUT", "RANGE", "PSEARCH_ALG", "IQSCALE", "INPUT_DIR",
     "INPUT_CONVERT", "INPUT", "BQSCALE", "BASE_FILE_FORMAT",
     "SLICES_PER_FRAME", "BSEARCH_ALG", "REFERENCE_FRAME"};
-static boolean optionSeen[NUM_OPTIONS+1];
+static bool optionSeen[NUM_OPTIONS+1];
     /* optionSeen[x] means we have seen option x in the parameter file we've
        been reading.
     */
 
-int numMachines;
-char	machineName[MAX_MACHINES][256];
-char	userName[MAX_MACHINES][256];
-char	executable[MAX_MACHINES][1024];
-char	remoteParamFile[MAX_MACHINES][1024];
-boolean	remote[MAX_MACHINES];
-int mult_seq_headers = 0;  /* 0 for none, N for header/N GOPs */
-
 
 /*===========================================================================*
  *
  * SkipSpacesTabs
  *
- *	skip all spaces and tabs
+ *  skip all spaces and tabs
  *
- * RETURNS:	point to next character not a space or tab
+ * RETURNS: point to next character not a space or tab
  *
  * SIDE EFFECTS:    none
  *
@@ -172,13 +173,13 @@ static int
 GetAspectRatio(const char * const p)
 {
   float   ratio;
-  int	  ttRatio;
+  int     ttRatio;
   int     retval;
 
   sscanf(p, "%f", &ratio);
   ttRatio = (int)(0.5+ratio*10000.0);
 
-  if ( ttRatio == 10000 )	      retval = 1;
+  if ( ttRatio == 10000 )         retval = 1;
   else if ( ttRatio ==  6735 )    retval = 2;
   else if ( ttRatio ==  7031 )    retval = 3;
   else if ( ttRatio ==  7615 )    retval = 4;
@@ -205,9 +206,9 @@ GetAspectRatio(const char * const p)
  *
  * ReadMachineNames
  *
- *	read a list of machine names for parallel execution
+ *  read a list of machine names for parallel execution
  *
- * RETURNS:	nothing
+ * RETURNS: nothing
  *
  * SIDE EFFECTS:    machine info updated
  *
@@ -219,7 +220,7 @@ ReadMachineNames(FILE * const fpointer)
   const char *charPtr;
 
   while ( (fgets(input, 256, fpointer) != NULL) &&
-	 (strncmp(input, "END_PARALLEL", 12) != 0) ) {
+     (strncmp(input, "END_PARALLEL", 12) != 0) ) {
     if ( input[0] == '#' || input[0] == '\n') {
       continue;
     }
@@ -229,13 +230,13 @@ ReadMachineNames(FILE * const fpointer)
       remote[numMachines] = TRUE;
 
       sscanf(charPtr, "%s %s %s %s", machineName[numMachines],
-	     userName[numMachines], executable[numMachines],
-	     remoteParamFile[numMachines]);
+         userName[numMachines], executable[numMachines],
+         remoteParamFile[numMachines]);
     } else {
       remote[numMachines] = FALSE;
 
       sscanf(input, "%s %s %s", machineName[numMachines],
-	     userName[numMachines], executable[numMachines]);
+         userName[numMachines], executable[numMachines]);
     }
 
     numMachines++;
@@ -259,13 +260,13 @@ static int
 GetFrameRate(const char * const p)
 {
   float   rate;
-  int	  thouRate;
+  int     thouRate;
   int     retval;
 
   sscanf(p, "%f", &rate);
   thouRate = (int)(0.5+1000.0*rate);
 
-  if ( thouRate == 23976 )	       retval = 1;
+  if ( thouRate == 23976 )         retval = 1;
   else if ( thouRate == 24000 )    retval = 2;
   else if ( thouRate == 25000 )    retval = 3;
   else if ( thouRate == 29970 )    retval = 4;
diff --git a/converter/ppm/ppmtompeg/ppmtompeg.c b/converter/ppm/ppmtompeg/ppmtompeg.c
index 6e7e9833..b8ef37f1 100644
--- a/converter/ppm/ppmtompeg/ppmtompeg.c
+++ b/converter/ppm/ppmtompeg/ppmtompeg.c
@@ -65,7 +65,8 @@ int main _ANSI_ARGS_((int argc, char **argv));
  * GLOBAL VARIABLES *
  *==================*/
 
-boolean showBitRatePerFrame;
+bool showBitRatePerFrame;
+bool computeMVHist = FALSE;
 boolean frameSummary;
 
 extern time_t IOtime;
@@ -79,9 +80,7 @@ boolean noFrameSummaryOption = FALSE;
 boolean debugSockets = FALSE;
 boolean debugMachines = FALSE;
 boolean bitRateInfoOption = FALSE;
-boolean computeMVHist = FALSE;
 int     baseFormat;
-extern  boolean specificsOn;
 extern  FrameSpecList *fsl;
 boolean pureDCT=FALSE;
 char    encoder_name[1024];
diff --git a/converter/ppm/ppmtompeg/readframe.c b/converter/ppm/ppmtompeg/readframe.c
index 112ebdf0..cac6bdad 100644
--- a/converter/ppm/ppmtompeg/readframe.c
+++ b/converter/ppm/ppmtompeg/readframe.c
@@ -67,9 +67,6 @@ struct YuvLine {
  * Global VARIABLES *
  *==================*/
 
-extern boolean GammaCorrection;
-extern float GammaValue;
-extern int outputWidth,outputHeight;
 boolean resizeFrame;
 const char *CurrFile;
 
@@ -828,7 +825,7 @@ MpegFrame *mf;
 int w,h;
 {
   static int GammaVal[256];
-  static boolean init_done=FALSE;
+  static bool init_done=FALSE;
   int i,j;
 
   if (!init_done) {
@@ -882,7 +879,7 @@ DoKillDim(mf, w, h)
 MpegFrame *mf;
 int w,h;
 {
-  static boolean init_done=FALSE;
+  static bool init_done=FALSE;
   static unsigned char mapper[256];
   register int i,j;
   double slope, intercept;
diff --git a/converter/ppm/ppmtompeg/specifics.c b/converter/ppm/ppmtompeg/specifics.c
index d2093e7f..ffbce80a 100644
--- a/converter/ppm/ppmtompeg/specifics.c
+++ b/converter/ppm/ppmtompeg/specifics.c
@@ -46,14 +46,12 @@
 #include <stdio.h>
 #include <string.h>
 #include "prototypes.h"
+#include "param.h"
 
 /*==================*
  * GLOBAL VARIABLES *
  *==================*/
 
-extern boolean specificsOn;
-extern char specificsFile[];
-extern char specificsDefines[];
 FrameSpecList *fsl;
 
 /*=====================*
diff --git a/converter/ppm/ppmtopjxl.c b/converter/ppm/ppmtopjxl.c
index 91cd1a45..ddf49638 100644
--- a/converter/ppm/ppmtopjxl.c
+++ b/converter/ppm/ppmtopjxl.c
@@ -12,6 +12,7 @@
  *
  */
 
+#include <assert.h>
 #include <stdio.h>
 #include <math.h>
 #include <string.h>
@@ -33,7 +34,7 @@ const char * const usage="[-nopack] [-gamma <n>] [-presentation] [-dark]\n\
 #define PCL_MAXHEIGHT 32767
 #define PCL_MAXVAL 255
 
-static int nopack = 0;
+static bool nopack = false;
 static int dark = 0;
 static int diffuse = 0;
 static int dither = 0;
@@ -73,16 +74,28 @@ static const struct options {
    {"-nopack",       BOOL, &nopack },
 };
 
-#define putword(w) (putchar(((w)>>8) & 255), putchar((w) & 255))
 
-static int 
-bitsperpixel(int v) {
-   int bpp = 0;
-   while (v > 0) {  /* calculate # bits for value */
-      ++bpp;
-      v>>=1;
-   }
-   return (bpp);
+
+static void
+putword(unsigned short const w) {
+    putchar((w >> 8) & 0xff);
+    putchar((w >> 0) & 0xff);
+}
+
+
+
+static unsigned int
+bitsperpixel(unsigned int v) {
+
+    unsigned int bpp;
+
+    /* calculate # bits for value */
+    
+    for (bpp = 0; v > 0; ) {
+        ++bpp;
+        v >>= 1;
+    }
+    return bpp;
 }
 
 
@@ -94,101 +107,117 @@ static char *outrow = NULL;
 static signed char *runcnt = NULL;
 
 static void 
-putbits(b, n) {
-    /* put #n bits in b out, packing into bytes; n=0 flushes bits */
-    /* n should never be > 8 */
-
-   static int out = 0;
-   static int cnt = 0;
-   static int num = 0;
-   static int pack = 0;
-   if (n) {
-      int xo = 0;
-      int xc = 0;
-      if (cnt+n > 8) {  /* overflowing current byte? */
-     xc = cnt + n - 8;
-     xo = (b & ~(-1 << xc)) << (8-xc);
-     n -= xc;
-     b >>= xc;
-      }
-      cnt += n;
-      out |= (b & ~(-1 << n)) << (8-cnt);
-      if (cnt >= 8) {
-     inrow[num++] = out;
-     out = xo;
-     cnt = xc;
-      }
-   } else { /* flush row */
-      int i;
-      if (cnt) {
-     inrow[num++] = out;
-     out = cnt = 0;
-      }
-      for (; num > 0 && inrow[num-1] == 0; num--); /* remove trailing zeros */
-      printf("\033*b"); 
-      if (num && !nopack) {            /* TIFF 4.0 packbits encoding */
-     int start = 0;
-     int next;
-     runcnt[start] = 0;
-     for (i = 1; i < num; i++) {
-        if (inrow[i] == inrow[i-1]) {
-           if (runcnt[start] <= 0 && runcnt[start] > -127)
-          runcnt[start]--;
-           else
-          runcnt[start = i] = 0;
-        } else {
-           if (runcnt[start] >= 0 && runcnt[start] < 127)
-          runcnt[start]++;
-           else
-          runcnt[start = i] = 0;
+putbits(int const bArg,
+        int const nArg) {
+/*----------------------------------------------------------------------------
+  Put 'n' bits in 'b' out, packing into bytes; n=0 flushes bits.
+
+  n should never be > 8 
+-----------------------------------------------------------------------------*/
+    static int out = 0;
+    static int cnt = 0;
+    static int num = 0;
+    static bool pack = false;
+
+    int b;
+    int n;
+
+    b = bArg;
+    n = nArg;
+
+    if (n) {
+        int xo = 0;
+        int xc = 0;
+
+        assert(n <= 8);
+
+        if (cnt + n > 8) {  /* overflowing current byte? */
+            xc = cnt + n - 8;
+            xo = (b & ~(-1 << xc)) << (8-xc);
+            n -= xc;
+            b >>= xc;
         }
-     }
-     start = 0;
-     for (i = 0; i < num; i = next) {
-        int count = runcnt[i];
-        int from = i;
-        if (count >= 0) { /* merge two-byte runs */
-           for (;;) {
-          next = i+1+runcnt[i];
-          if(next >= num || runcnt[next] < 0 ||
-             count+runcnt[next]+1 > 127)
-             break;
-          count += runcnt[next]+1;
-          i = next;
-           }
+        cnt += n;
+        out |= (b & ~(-1 << n)) << (8-cnt);
+        if (cnt >= 8) {
+            inrow[num++] = out;
+            out = xo;
+            cnt = xc;
         }
-        next =  i + 1 + ((runcnt[i] < 0) ? -runcnt[i] : runcnt[i]);
-        if (next < num && count > 0 &&
-        runcnt[next] < 0 && runcnt[next] > -127) {
-           count--;
-           next--;
-           runcnt[next] = runcnt[next+1]-1;
+    } else { /* flush row */
+        if (cnt) {
+            inrow[num++] = out;
+            out = cnt = 0;
         }
-        outrow[start++] = count;
-        if (count >= 0) {
-           while (count-- >= 0)
-          outrow[start++] = inrow[from++];
-        } else
-           outrow[start++] = inrow[from];
-     }
-     if (start < num) {
-        num = start;
-        if (!pack) {
-           printf("2m");
-           pack = 1;
+        for (; num > 0 && inrow[num-1] == 0; --num);
+            /* remove trailing zeros */
+        printf("\033*b"); 
+        if (num && !nopack) {            /* TIFF 4.0 packbits encoding */
+            unsigned int i;
+            int start = 0;
+            int next;
+            runcnt[start] = 0;
+            for (i = 1; i < num; ++i) {
+                if (inrow[i] == inrow[i-1]) {
+                    if (runcnt[start] <= 0 && runcnt[start] > -127)
+                        runcnt[start]--;
+                    else
+                        runcnt[start = i] = 0;
+                } else {
+                    if (runcnt[start] >= 0 && runcnt[start] < 127)
+                        runcnt[start]++;
+                    else
+                        runcnt[start = i] = 0;
+                }
+            }
+            for (i = 0, start = 0; i < num; i = next) {
+                int count = runcnt[i];
+                int from = i;
+                if (count >= 0) { /* merge two-byte runs */
+                    for (;;) {
+                        next = i+1+runcnt[i];
+                        if(next >= num || runcnt[next] < 0 ||
+                           count+runcnt[next]+1 > 127)
+                            break;
+                        count += runcnt[next]+1;
+                        i = next;
+                    }
+                }
+                next =  i + 1 + ((runcnt[i] < 0) ? -runcnt[i] : runcnt[i]);
+                if (next < num && count > 0 &&
+                    runcnt[next] < 0 && runcnt[next] > -127) {
+                    --count;
+                    --next;
+                    runcnt[next] = runcnt[next+1]-1;
+                }
+                outrow[start++] = count;
+                if (count >= 0) {
+                    while (count-- >= 0)
+                        outrow[start++] = inrow[from++];
+                } else
+                    outrow[start++] = inrow[from];
+            }
+            if (start < num) {
+                num = start;
+                if (!pack) {
+                    printf("2m");
+                    pack = true;
+                }
+            } else {
+                if (pack) {
+                    printf("0m");
+                    pack = false;
+                }
+            }
         }
-     } else {
-        if (pack) {
-           printf("0m");
-           pack = 0;
+        printf("%dW", num);
+        {
+            unsigned int i;
+            for (i = 0; i < num; ++i)
+                putchar(pack ? outrow[i] : inrow[i]);
         }
-     }
-      }
-      printf("%dW", num);
-      for (i = 0; i < num; i++)
-     putchar(pack ? outrow[i] : inrow[i]);
-      num = 0; /* new row */
-   }
+        num = 0; /* new row */
+    }
 }
 
 
diff --git a/converter/ppm/ppmtoyuv.c b/converter/ppm/ppmtoyuv.c
index 7d843cc0..75f79c1e 100644
--- a/converter/ppm/ppmtoyuv.c
+++ b/converter/ppm/ppmtoyuv.c
@@ -19,79 +19,102 @@
 
 #include "ppm.h"
 
-int
-main(argc, argv)
-char **argv;
-{
-	FILE *ifp;
-	pixel          *pixelrow;
-	register pixel *pP;
-	int             rows, cols, format, row;
-	register int    col;
-	pixval          maxval;
-	unsigned long   y1, y2=0, u=0, v=0, u0=0, u1, u2, v0=0, v1, v2;
-	unsigned char  *yuvbuf;
-
-
-	ppm_init(&argc, argv);
 
-	if (argc > 2) pm_usage("[ppmfile]");
 
-	if (argc == 2) ifp = pm_openr(argv[1]);
-	else ifp = stdin;
-
-	ppm_readppminit(ifp, &cols, &rows, &maxval, &format);
+static void
+convertRow(const pixel *   const pixelrow,
+           unsigned int    const cols,
+           unsigned char * const yuvBuf,
+           unsigned long * const uP,
+           unsigned long * const vP,
+           unsigned long * const u0P,
+           unsigned long * const v0P,
+           unsigned long * const y2CarryP) {
+
+    unsigned int col;
+    unsigned char * yuvptr;
+
+    for (col = 0, yuvptr = &yuvBuf[0]; col < cols; col += 2) {
+        unsigned long y1, y2, u1, u2, v1, v2;
+
+        {
+            /* first pixel gives Y and 0.5 of chroma */
+            pixval const r = PPM_GETR(pixelrow[col]);
+            pixval const g = PPM_GETG(pixelrow[col]);
+            pixval const b = PPM_GETB(pixelrow[col]);
+            
+            y1 = 16829 * r + 33039 * g +  6416 * b + (*y2CarryP & 0xffff);
+            u1 = -4853 * r -  9530 * g + 14383 * b;
+            v1 = 14386 * r - 12046 * g -  2340 * b;
+        }
+        {
+            /* second pixel gives Y and 0.25 of chroma */
+            pixval const r = PPM_GETR(pixelrow[col + 1]);
+            pixval const g = PPM_GETG(pixelrow[col + 1]);
+            pixval const b = PPM_GETB(pixelrow[col + 1]);
+
+            y2 = 16829 * r + 33039 * g + 6416 * b + (y1 & 0xffff);
+            u2 = -2426 * r -  4765 * g + 7191 * b;
+            v2 =  7193 * r -  6023 * g - 1170 * b;
+        }
+        /* filter the chroma */
+        *uP = *u0P + u1 + u2 + (*uP & 0xffff);
+        *vP = *v0P + v1 + v2 + (*vP & 0xffff);
+
+        *u0P = u2;
+        *v0P = v2;
+
+        *yuvptr++ = (*uP >> 16) + 128;
+        *yuvptr++ = (y1  >> 16) +  16;
+        *yuvptr++ = (*vP >> 16) + 128;
+        *yuvptr++ = (y2  >> 16) +  16;
+
+        *y2CarryP = y2;
+    }
+}
 
-    if (cols % 2 != 0)
-        pm_error("Image must have even number of columns.\n"
-                 "This image is %d columns wide.  Try Pnmcut.", cols);
 
-	pixelrow = ((pixel*) pm_allocrow( cols, sizeof(pixel) ));
-	yuvbuf = (unsigned char *) pm_allocrow( cols, 2 );
 
-	for (row = 0; row < rows; ++row) {
-		unsigned char *yuvptr;
+int
+main(int argc, const char **argv) {
 
-		ppm_readppmrow(ifp, pixelrow, cols, maxval, format);
+    FILE * ifP;
+    pixel * pixelrow;
+    int rows, cols, format;
+    pixval maxval;
+    unsigned int row;
+    unsigned char  * yuvBuf;
+    unsigned long u, v, u0, v0, y2Carry;
 
-		for (col = 0, pP = pixelrow, yuvptr=yuvbuf; col < cols; col += 2, ++pP) {
-			pixval r, g, b;
+    pm_proginit(&argc, argv);
 
-			/* first pixel gives Y and 0.5 of chroma */
-			r = PPM_GETR(*pP);
-			g = PPM_GETG(*pP);
-			b = PPM_GETB(*pP);
+    if (argc-1 > 1)
+        pm_error("Too many arguments: %u.  The only possible argument "
+                 "is the name of the input file", argc-1);
 
-			y1 = 16829 * r + 33039 * g + 6416 * b + (0xffff & y2);
-			u1 = -4853 * r - 9530 * g + 14383 * b;
-			v1 = 14386 * r - 12046 * g - 2340 * b;
+    if (argc-1 == 1)
+        ifP = pm_openr(argv[1]);
+    else
+        ifP = stdin;
 
-			pP++;
-			/* second pixel just yields a Y and 0.25 U, 0.25 V */
-			r = PPM_GETR(*pP);
-			g = PPM_GETG(*pP);
-			b = PPM_GETB(*pP);
+    ppm_readppminit(ifP, &cols, &rows, &maxval, &format);
 
-			y2 = 16829 * r + 33039 * g + 6416 * b + (0xffff & y1);
-			u2 = -2426 * r - 4765 * g + 7191 * b;
-			v2 = 7193 * r - 6023 * g - 1170 * b;
+    if (cols % 2 != 0)
+        pm_error("Image must have even number of columns.\n"
+                 "This image is %u columns wide.  Try Pamcut.", cols);
 
-			/* filter the chroma */
-			u = u0 + u1 + u2 + (0xffff & u);
-			v = v0 + v1 + v2 + (0xffff & v);
+    pixelrow = ppm_allocrow(cols);
+    yuvBuf = (unsigned char *) pm_allocrow(cols, 2);
 
-			u0 = u2;
-			v0 = v2;
+    for (row = 0, u = v = u0 = v0 = y2Carry = 0; row < rows; ++row) {
+        ppm_readppmrow(ifP, pixelrow, cols, maxval, format);
 
-			*yuvptr++ = (u >> 16) + 128;
-			*yuvptr++ = (y1 >> 16) + 16;
-			*yuvptr++ = (v >> 16) + 128;
-			*yuvptr++ = (y2 >> 16) + 16;
-		}
-		fwrite(yuvbuf, cols*2, 1, stdout);
-	}
+        convertRow(pixelrow, cols, yuvBuf, &u, &v, &u0, &v0, &y2Carry);
+        
+        fwrite(yuvBuf, cols*2, 1, stdout);
+    }
 
-	pm_close(ifp);
+    pm_close(ifP);
 
-	exit(0);
+    return 0;
 }
diff --git a/converter/ppm/sldtoppm.c b/converter/ppm/sldtoppm.c
index ad16a649..6ba4cb40 100644
--- a/converter/ppm/sldtoppm.c
+++ b/converter/ppm/sldtoppm.c
@@ -26,23 +26,20 @@
 #include <string.h>
 #include <math.h>
 
+#include "pm_c_util.h"
 #include "ppm.h"
 #include "ppmdraw.h"
 #include "nstring.h"
-#ifdef DEBUG
 #include <assert.h>
-#else
-#define assert(x)
-#endif
+
+#include "autocad.h"                  /* AutoCAD standard color assignments */
+
 
 /*  Define a variable type accepting numbers -127 <= n <= 127.  But note
     that we still expect it to act UNSIGNED. */
 
 #define smallint unsigned char        /* Small integers */
 
-#define TRUE     1
-#define FALSE    0
-
 #define EOS     '\0'
 
 /* Screen point */
@@ -70,18 +67,17 @@ typedef void (slvecfn)(struct svector * vec, int color);
 typedef void (slfloodfn)(struct spolygon * poly, int color);
 
 
+static unsigned long const pixmaxval = 255;  /* Largest pixel value */
+
 static int ixdots, iydots;        /* Screen size in dots */
-static FILE *slfile;              /* Slide file descriptor */
-static int blither = FALSE;       /* Dump slide file information ? */
-static int info = FALSE;          /* Print header information */
+static FILE * slfile;             /* Slide file descriptor */
+static bool blither;              /* Dump slide file information ? */
+static bool info;                 /* Print header information */
 static pixel **pixels;            /* Pixel map */
-static int pixcols, pixrows;          /* Pixel map size */
-#define pixmaxval 255             /* Largest pixel value */
+static int pixcols, pixrows;      /* Pixel map size */
 static double uscale = -1;        /* Uniform scale factor */
 static int sxsize = -1, sysize = -1;  /* Scale to X, Y size ? */
 
-#include "autocad.h"                  /* AutoCAD standard color assignments */
-
 /*  Local variables  */
 
 struct slhead {
@@ -94,11 +90,11 @@ struct slhead {
     char spad;                /* Pad to even byte length */
 };
 
-static int adjust = FALSE;        /* Adjust to correct aspect ratio ? */
-static struct slhead slfrof;          /* Slide file header */
-static long xfac, yfac;           /* Aspect ratio scale factors */
+static bool adjust;           /* Adjust to correct aspect ratio ? */
+static struct slhead slfrof;  /* Slide file header */
+static long xfac, yfac;       /* Aspect ratio scale factors */
 
-static int sdrawkcab;
+static bool sdrawkcab;
     /* Slide drawing kinematic conversion of ass-backwards data flag */
 
 
@@ -108,7 +104,7 @@ static int sdrawkcab;
 */
 
 static int
-extend(smallint ch) {
+extend(unsigned char const ch) {
     return ((int) ((ch & 0x80) ? (ch | ~0xFF) : ch));
 }
 
@@ -136,9 +132,9 @@ sli(void) {
 
 static int 
 slib(void) {
-    smallint ch = 0;
+    unsigned char ch;
 
-    if (fread(&ch, sizeof ch, 1, slfile) != 1) {
+    if (fread(&ch, sizeof(ch), 1, slfile) != 1) {
         pm_error("error reading slide file");
     }
     return extend(ch);
@@ -171,22 +167,28 @@ slidefind(const char * const sname,
     char uname[32];
     unsigned char libent[36];
     long pos;
+    bool found;
+    bool eof;
 
     if (dironly)
         pm_message("Slides in library:");
     else {
-        int i;
+        unsigned int i;
         const char * ip;
         
         ip = sname; /* initial value */
         
-        for (i = 0; i < 31; i++) {
-            char ch = *ip++;
+        for (i = 0; i < 31; ++i) {
+            char const ch = *ip++;
             if (ch == EOS)
                 break;
-            if (ucasen && ISLOWER(ch))
-                ch = TOUPPER(ch);
-            uname[i] = ch;
+
+            {
+                char const upperCh =
+                    ucasen && islower(ch) ? toupper(ch) : ch;
+                
+                uname[i] = upperCh;
+            }
         }
         uname[i] = EOS;
     }
@@ -199,31 +201,38 @@ slidefind(const char * const sname,
     }
     pos = 32;
     
-    /* Search for a slide with the requested name. */
+    /* Search for a slide with the requested name or list the directory */
     
-    while (TRUE) {
-        if ((fread(libent, 36, 1, slfile) != 1) ||
-            (strlen((char *)libent) == 0)) {
-            if (dironly) {
-                return;
-            }
-            pm_error("slide %s not in library.", sname);
-        }
+    for (found = false, eof = false; !found && !eof; ) {
+        size_t readCt;
+        readCt = fread(libent, 36, 1, slfile);
+        if (readCt != 1)
+            eof = true;
+        else if (strlen((char *)libent) == 0)
+            eof = true;
+    }
+    if (!eof) {
         pos += 36;
         if (dironly) {
             pm_message("  %s", libent);
         } else if (streq((char *)libent, uname)) {
-            long dpos = (((((libent[35] << 8) | libent[34]) << 8) |
-                          libent[33]) << 8) | libent[32];
+            long dpos;
+
+            dpos = (((((libent[35] << 8) | libent[34]) << 8) |
+                     libent[33]) << 8) | libent[32];
+
             if ((slfile == stdin) || (fseek(slfile, dpos, 0) == -1)) {
                 dpos -= pos;
         
                 while (dpos-- > 0)
                     getc(slfile);
             }
-            break;
+            found = true;
         }
     }
+
+    if (!found && !dironly)
+        pm_error("slide '%s' not in library.", sname);
 }
 
 
@@ -329,7 +338,7 @@ slider(slvecfn   slvec,
     
     /* Process the header of the slide file.  */
     
-    sdrawkcab = FALSE;            /* Initially guess byte order is OK */
+    sdrawkcab = false;            /* Initially guess byte order is OK */
     fread(slfrof.slh, 17, 1, slfile);
     fread(&slfrof.sntype, sizeof(char), 1, slfile);
     fread(&slfrof.slevel, sizeof(char), 1, slfile);
@@ -364,12 +373,12 @@ slider(slvecfn   slvec,
     */
 
     if (btest != rtest) {
-        sdrawkcab = TRUE;
-#define rshort(x) x = ((x >> 8) & 0xFF) | (x << 8)
+        sdrawkcab = true;
+        #define rshort(x) x = ((x >> 8) & 0xFF) | (x << 8)
         rshort(slfrof.sxdots);
         rshort(slfrof.sydots);
         rshort(slfrof.shwfill);
-#undef rshort
+        #undef rshort
     }
     
     /* Dump the header if we're blithering. */
@@ -413,7 +422,7 @@ slider(slvecfn   slvec,
         ixdots = slfrof.sxdots;
         iydots = slfrof.sydots;
         dsar = slfrof.sdsar;
-        adjust = FALSE;           /* Mark no adjustment needed */
+        adjust = false;           /* Mark no adjustment needed */
     }
 
     /* If there's a uniform scale factor specified, apply it. */
@@ -571,32 +580,42 @@ slider(slvecfn   slvec,
 /*  Main program. */
 
 int
-main(int    argc,
-     char * argv[]) {
+main(int          argc,
+     const char * argv[]) {
 
     int argn;
     const char * const usage = "[-verbose] [-info] [-adjust] [-scale <s>]\n\
 [-dir] [-lib|-Lib <name>]\n\
 [-xsize|-width <x>] [-ysize|-height <y>] [sldfile]";
-    int scalespec = FALSE, widspec = FALSE, hgtspec = FALSE, dironly = FALSE,
-        ucasen;
+    bool dironly;
+    bool hgtspec;
+    bool widspec;
+    bool scalespec;
+    bool ucasen;
     const char * slobber;       /* Slide library item */
 
+    pm_proginit(&argc, argv);
+    argn = 1;
 
     slobber = NULL;
-
-    ppm_init(&argc, argv);
-    argn = 1;
+    dironly = false;
+    hgtspec = false;
+    widspec = false;
+    scalespec = false;
+    ucasen = false;
+    blither = false;
+    info = false;
+    adjust = false;
 
     while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
         if (pm_keymatch(argv[argn], "-verbose", 2)) {
-            blither = TRUE;
+            blither = true;
         } else if (pm_keymatch(argv[argn], "-adjust", 2)) {
-            adjust = TRUE;
+            adjust = true;
         } else if (pm_keymatch(argv[argn], "-dir", 2)) {
-            dironly = TRUE;
+            dironly = true;
         } else if (pm_keymatch(argv[argn], "-info", 2)) {
-            info = TRUE;
+            info = true;
         } else if (pm_keymatch(argv[argn], "-lib", 2)) {
             if (slobber)
                 pm_error("already specified a library item");
@@ -616,7 +635,7 @@ main(int    argc,
             if (uscale <= 0.0) {
                 pm_error("scale factor must be greater than 0");
             }
-            scalespec = TRUE;
+            scalespec = true;
         } else if (pm_keymatch(argv[argn], "-xsize", 2) ||
                    pm_keymatch(argv[argn], "-width", 2)) {
             if (widspec) {
@@ -625,7 +644,7 @@ main(int    argc,
             argn++;
             if ((argn == argc) || (sscanf(argv[argn], "%d", &sxsize) != 1))
                 pm_usage(usage);
-            widspec = TRUE;
+            widspec = true;
         } else if (pm_keymatch(argv[argn], "-ysize", 2) ||
                    pm_keymatch(argv[argn], "-height", 2)) {
             if (hgtspec) {
@@ -634,7 +653,7 @@ main(int    argc,
             argn++;
             if ((argn == argc) || (sscanf(argv[argn], "%d", &sysize) != 1))
                 pm_usage(usage);
-            hgtspec = TRUE;
+            hgtspec = true;
         } else {
             pm_usage(usage);
         }
@@ -665,7 +684,7 @@ main(int    argc,
  
     if (!dironly) {
         slider(draw, flood);
-        ppm_writeppm(stdout, pixels, pixcols, pixrows, pixmaxval, FALSE);
+        ppm_writeppm(stdout, pixels, pixcols, pixrows, pixmaxval, 0);
     }
     pm_close(slfile);
     pm_close(stdout);
diff --git a/converter/ppm/winicontoppm.c b/converter/ppm/winicontoppm.c
index 014eab40..6b1376b2 100644
--- a/converter/ppm/winicontoppm.c
+++ b/converter/ppm/winicontoppm.c
@@ -31,10 +31,9 @@
 #define MAJVERSION 0
 #define MINVERSION 4
 
-static int file_offset = 0;    /* not actually used, but useful for debug */
+static int fileOffset = 0;    /* not actually used, but useful for debug */
 static const char     er_read[] = "%s: read error";
 static const char *   infname;
-static FILE *   ifp;
 
 struct cmdlineInfo {
     /* All the information the user supplied in the command line,
@@ -53,8 +52,8 @@ struct cmdlineInfo {
 
 
 static void
-parseCommandLine ( int argc, char ** argv,
-                   struct cmdlineInfo *cmdlineP ) {
+parseCommandLine (int argc, const char ** argv,
+                  struct cmdlineInfo *cmdlineP ) {
 /*----------------------------------------------------------------------------
    parse program command line described in Unix standard form by argc
    and argv.  Return the information in the options as *cmdlineP.  
@@ -65,13 +64,15 @@ parseCommandLine ( int argc, char ** argv,
    Note that the strings we return are stored in the storage that
    was passed to us as the argv array.  We also trash *argv.
 -----------------------------------------------------------------------------*/
-    optEntry *option_def = malloc(100*sizeof(optEntry));
+    optEntry * option_def;
         /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
 
     unsigned int option_def_index;
 
+    MALLOCARRAY(option_def, 100);
+
     option_def_index = 0;   /* incremented by OPTENT3 */
     OPTENT3(0, "allicons",     OPT_FLAG,   NULL,                  
             &cmdlineP->allicons,       0 );
@@ -88,10 +89,9 @@ parseCommandLine ( int argc, char ** argv,
     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, argv, opt, sizeof(opt), 0);
+    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->inputFilespec = "-";
     else
@@ -116,37 +116,37 @@ parseCommandLine ( int argc, char ** argv,
 
 
 static int 
-GetByte(void) {
+GetByte(FILE * const ifP) {
+
     int v;
    
-    if ((v = getc(ifp)) == EOF)
-    {
+    v = getc(ifP);
+    if (v == EOF)
         pm_error(er_read, infname);
-    }
    
     return v;
 }
+
+
    
 static short 
-GetShort(void) {
+GetShort(FILE * const ifP) {
+
     short v;
    
-    if (pm_readlittleshort(ifp, &v) == -1)
-    {
-        pm_error(er_read, infname);
-    }
-   
+    pm_readlittleshort(ifP, &v);
+
     return v;
 }
+
+
    
 static long 
-GetLong(void) {
+GetLong(FILE * const ifP) {
+
     long v;
    
-    if (pm_readlittlelong(ifp, &v) == -1)
-    {
-        pm_error(er_read, infname);
-    }
+    pm_readlittlelong(ifP, &v);
    
     return v;
 }
@@ -158,14 +158,18 @@ GetLong(void) {
  * functions.
  */
 static u1 
-readU1 (void) {
-    file_offset++;
-    return GetByte();
+readU1(FILE * const ifP) {
+
+    ++fileOffset;
+
+    return GetByte(ifP);
 }
 
+
+
 static u1 * 
-readU1String (int length)
-{
+readU1String (FILE *       const ifP,
+              unsigned int const length) {
    
     u1 * string;
     
@@ -173,150 +177,173 @@ readU1String (int length)
     if (string == NULL)
         pm_error("out of memory");
 
-    fread(string,sizeof(u1),length,ifp);
+    fread(string, sizeof(u1), length, ifP);
     string[length] = 0;
-    file_offset += length * sizeof(u1);
+    fileOffset += length * sizeof(u1);
+
     return string;
 }
 
+
+
 static u2 
-readU2 (void) {
-    file_offset +=2;
-    return GetShort();
+readU2 (FILE * const ifP) {
+
+    fileOffset +=2;
+
+    return GetShort(ifP);
 }
 
+
+
 static u4 
-readU4 (void) {
-    file_offset += 4;
-    return GetLong();
+readU4 (FILE * const ifP) {
+
+    fileOffset += 4;
+
+    return GetLong(ifP);
 }
 
+
+
 static IC_Entry 
-readICEntry (void) 
-{
-    IC_Entry entry;
+readICEntry(FILE * const ifP) {
+
+    IC_Entry entryP;
 
-    MALLOCVAR(entry);
+    MALLOCVAR(entryP);
 
-    if (entry == NULL)
+    if (entryP == NULL)
         pm_error("Unable to allcoate memory for IC entry");
 
-    entry->width         = readU1();
-    entry->height        = readU1();
-    entry->color_count   = readU1();
-    entry->reserved      = readU1();
-    entry->planes        = readU2();
-    entry->bitcount      = readU2();
-    entry->size_in_bytes = readU4();
-    entry->file_offset   = readU4();
-    entry->colors        = NULL;
-    entry->ih            = NULL;
-    entry->xorBitmap     = NULL;
-    entry->andBitmap     = NULL;
+    entryP->width         = readU1(ifP);
+    entryP->height        = readU1(ifP);
+    entryP->color_count   = readU1(ifP);
+    entryP->reserved      = readU1(ifP);
+    entryP->planes        = readU2(ifP);
+    entryP->bitcount      = readU2(ifP);
+    entryP->size_in_bytes = readU4(ifP);
+    entryP->file_offset   = readU4(ifP);
+    entryP->colors        = NULL;
+    entryP->ih            = NULL;
+    entryP->xorBitmap     = NULL;
+    entryP->andBitmap     = NULL;
     
-    return entry;
+    return entryP;
 }
 
 
 
 static IC_InfoHeader 
-readInfoHeader (IC_Entry entry) 
-{
-    IC_InfoHeader ih;
+readInfoHeader (FILE *   const ifP,
+                IC_Entry const entryP) {
+
+    IC_InfoHeader ihP;
 
-    MALLOCVAR(ih);
+    MALLOCVAR(ihP);
     
-    if (ih == NULL)
+    if (ihP == NULL)
         pm_error("Unable to allocate memory for info header");
 
-    ih->size            = readU4();
-    ih->width           = readU4();
-    ih->height          = readU4();
-    ih->planes          = readU2();
-    ih->bitcount        = readU2();
-    ih->compression     = readU4();
-    ih->imagesize       = readU4();
-    ih->x_pixels_per_m  = readU4();
-    ih->y_pixels_per_m  = readU4();
-    ih->colors_used     = readU4();
-    ih->colors_important = readU4();
+    ihP->size             = readU4(ifP);
+    ihP->width            = readU4(ifP);
+    ihP->height           = readU4(ifP);
+    ihP->planes           = readU2(ifP);
+    ihP->bitcount         = readU2(ifP);
+    ihP->compression      = readU4(ifP);
+    ihP->imagesize        = readU4(ifP);
+    ihP->x_pixels_per_m   = readU4(ifP);
+    ihP->y_pixels_per_m   = readU4(ifP);
+    ihP->colors_used      = readU4(ifP);
+    ihP->colors_important = readU4(ifP);
     
-    if (!entry->bitcount) entry->bitcount = ih->bitcount;
-    if (entry->color_count == 0 && 
-        entry->bitcount <= 8) entry->color_count = 256;
-    if (ih->compression) {
+    if (!entryP->bitcount)
+        entryP->bitcount = ihP->bitcount;
+    
+    if (entryP->color_count == 0 && entryP->bitcount <= 8)
+        entryP->color_count = 256;
+
+    if (ihP->compression) {
         pm_error("Can't handle compressed icons");
     }
-    return ih;
+    return ihP;
 }
 
-/*
- * I don't know why this isn't the same as the spec, it just <b>isn't</b>
- * The colors honestly seem to be stored BGR.  Bizarre.
- * 
- * I've checked this in the BMP code for bmptoppm and the gimp.  Guess the
- * spec I have is just plain wrong.
- */
+
+
 static IC_Color 
-readICColor (void) 
-{
-    IC_Color col;
+readICColor(FILE * const ifP)  {
+
+    IC_Color colorP;
 
-    MALLOCVAR(col);
+    MALLOCVAR(colorP);
 
-    if (col == NULL)
+    if (colorP == NULL)
         pm_error("Unable to allocate memory for color");
 
-    col->blue     = readU1();
-    col->green    = readU1();
-    col->red      = readU1();
-    col->reserved = readU1();
-    return col;
+    /* I don't know why this isn't the same as the spec, it just isn't.
+       The colors honestly seem to be stored BGR.  Bizarre.
+      
+       I've checked this in the BMP code for bmptoppm and the gimp.  Guess the
+       spec I have is just plain wrong.
+    */
+
+    colorP->blue     = readU1(ifP);
+    colorP->green    = readU1(ifP);
+    colorP->red      = readU1(ifP);
+    colorP->reserved = readU1(ifP);
+
+    return colorP;
 }
    
 
 
-/*
- * Depending on if the image is stored as 1bpp, 4bpp or 8bpp, the 
- * encoding mechanism is different.
- * 
- * 8bpp => 1 byte/palette index.
- * 4bpp => High Nibble, Low Nibble
- * 1bpp => 1 palette value per bit, high bit 1st.
- */
 static u1 * 
-read1Bitmap (int width, int height) 
-{
-    int tmp;
-    int xBytes;
+read1Bitmap (FILE *       const ifP,
+             unsigned int const width,
+             unsigned int const height) {
+
+    unsigned int row;
+    unsigned int xByteCt;
     u1 * bitmap;
-    int wt = width;
+    unsigned int wt;
 
     MALLOCARRAY(bitmap, width * height);
     if (bitmap == NULL)
         pm_error("out of memory");
 
-    wt >>= 3;
-    if (wt & 3) {
-        wt = (wt & ~3) + 4;
+    /* Depending on if the image is stored as 1bpp, 4bpp or 8bpp, the 
+       encoding mechanism is different.
+  
+       8bpp => 1 byte/palette index.
+       4bpp => High Nibble, Low Nibble
+       1bpp => 1 palette value per bit, high bit 1st.
+    */
+
+    wt = width >> 3;
+
+    if ((wt & 0x3) != 0) {
+        wt = (wt & ~0x3) + 4;
     }
-    xBytes = wt;
-    for (tmp = 0; tmp<height; tmp++ ) {
-        int x;
-        int rowByte = 0;
-        int xOrVal = 128;
-        u1 * row = readU1String(xBytes);
-        for (x = 0; x< width; x++) {
-            *(bitmap+((height-tmp-1)*width) + (x)) = 
-                (row[rowByte] & xOrVal) / xOrVal;
-            if (xOrVal == 1) {
-                xOrVal = 128;
-                rowByte++;
-            } else {
+    xByteCt = wt;
+
+    for (row = 0; row < height; ++row) {
+        u1 * const imgRow = readU1String(ifP, xByteCt);
+
+        unsigned int col;
+        unsigned int rowByte;
+        unsigned int xOrVal;
+        
+        for (col = 0, rowByte = 0, xOrVal = 0x80; col < width; ++col) {
+            *(bitmap+((height - row - 1) * width) + col) = 
+                (imgRow[rowByte] & xOrVal) / xOrVal;
+            if (xOrVal == 0x01) {
+                xOrVal = 0x80;
+                ++rowByte;
+            } else
                 xOrVal >>= 1;
-            }
         }
-        free(row);
+        free(imgRow);
     }
     return bitmap;
 }
@@ -324,43 +351,46 @@ read1Bitmap (int width, int height)
 
    
 static u1 * 
-read4Bitmap (int width, int height) 
-{
-    int tmp;
+read4Bitmap (FILE *       const ifP,
+             unsigned int const width,
+             unsigned int const height) {
+
+    unsigned int row;
     u1 * bitmap;
 
-    int wt = width;
-    int xBytes;
+    unsigned int wt;
+    unsigned int xByteCt;
 
     MALLOCARRAY(bitmap, width * height);
     if (bitmap == NULL)
         pm_error("out of memory");
 
+    wt = width >> 1;
 
-    wt >>= 1;
-    if (wt & 3) {
-        wt = (wt & ~3) + 4;
+    if (wt & 0x3) {
+        wt = (wt & ~0x3) + 4;
     }
-    xBytes = wt;
-    for (tmp = 0; tmp<height ; tmp++ ) {
-        int rowByte = 0;
-        int bottom = 1;
-        int x;
-        u1 * row = readU1String(xBytes);
-        for (x = 0; x< width; x++) {
-            /*
-             * 2 nibbles, 2 values.
-             */
+    xByteCt = wt;
+
+    for (row = 0; row < height; ++row) {
+        u1 * const imgRow = readU1String(ifP, xByteCt);
+
+        unsigned int rowByte;
+        bool bottom;
+        unsigned int col;
+        for (col = 0, rowByte = 0, bottom = true; col < width; ++col) {
+            /* 2 nibbles, 2 values */
             if (bottom) {
-                *(bitmap+((height-tmp-1)*width) + (x)) = 
-                    (row[rowByte] & 0xF0) >> 4;
+                *(bitmap + ((height - row - 1) * width) + col) = 
+                    (imgRow[rowByte] & 0xF0) >> 4;
             } else {
-                *(bitmap+((height-tmp-1)*width) + (x)) = (row[rowByte] & 0xF);
-                rowByte++;
+                *(bitmap + ((height - row -1) * width) + col) =
+                    (imgRow[rowByte] & 0xF);
+                ++rowByte;
             }
             bottom = !bottom;
         }
-    free(row);
+        free(imgRow);
     }
     return bitmap;
 }
@@ -368,52 +398,57 @@ read4Bitmap (int width, int height)
 
    
 static u1 * 
-read8Bitmap (int width, int height) 
-{
-    int tmp;
-    unsigned int xBytes;
-    unsigned int wt = width;
+read8Bitmap (FILE *       const ifP,
+             unsigned int const width,
+             unsigned int const height) {
+
+    unsigned int row;
+    unsigned int xByteCt;
+    unsigned int wt;
     u1 * bitmap;
    
     MALLOCARRAY(bitmap, width * height);
     if (bitmap == NULL)
         pm_error("out of memory");
 
-    if (wt & 3) {
-        wt = (wt & ~3) + 4;
+    wt = width;
+    if (wt & 0x3) {
+        wt = (wt & ~0x3) + 4;
     }
-    xBytes = wt;
-    for (tmp = 0; tmp<height ; tmp++ ) {
-        int rowByte = 0;
-        int x;
-        u1 * row = readU1String(xBytes);
-        for ( x = 0; x< width; x++) {
-            *(bitmap+((height-tmp-1)*width) + (x)) = row[rowByte];
-            rowByte++;
-        }
-        free(row);
+    xByteCt = wt;
+
+    for (row = 0; row < height; ++row) {
+        u1 * imgRow = readU1String(ifP, xByteCt);
+
+        unsigned int rowByte;
+        unsigned int col;
+        for (col = 0, rowByte = 0; col < width; ++col)
+            *(bitmap + ((height - row - 1) * width) + col) = imgRow[rowByte++];
+
+        free(imgRow);
     }
     return bitmap;
 }
 
 
 
-/*
- * Read a true color bitmap. (24/32 bits)
- * 
- * The output routine deplanarizes it for us, we keep it flat here.
- */
 static u1 *
-readXBitmap (int const width, 
-             int const height, 
-             int const bpp) {
-    int          const bytes  = bpp >> 3;
-    unsigned int const xBytes = width * bytes;
+readXBitmap (FILE *       const ifP,
+             unsigned int const width, 
+             unsigned int const height, 
+             unsigned int const bpp) {
+/*----------------------------------------------------------------------------
+  Read a true color bitmap. (24/32 bits)
+  
+  The output routine deplanarizes it for us, we keep it flat here.
+-----------------------------------------------------------------------------*/
+    unsigned int const byteCt = bpp >> 3;
+    unsigned int const xByteCt = width * byteCt;
 
     u1 * bitmap;
         /* remember - bmp (dib) stored upside down, so reverse */
 
-    MALLOCARRAY(bitmap, bytes * width * height);
+    MALLOCARRAY(bitmap, byteCt * width * height);
     if (bitmap == NULL)
         pm_error("out of memory allocating bitmap array");
 
@@ -421,12 +456,12 @@ readXBitmap (int const width,
         unsigned int i;
         u1 * bitcurptr;
 
-        for (i = 0, bitcurptr = &bitmap[bytes * width * (height-1)];
+        for (i = 0, bitcurptr = &bitmap[byteCt * width * (height-1)];
              i < height; 
-             ++i, bitcurptr -= xBytes) {
+             ++i, bitcurptr -= xByteCt) {
 
-            u1 * const row = readU1String(xBytes);
-            memcpy(bitcurptr, row, xBytes);
+            u1 * const row = readU1String(ifP, xByteCt);
+            memcpy(bitcurptr, row, xByteCt);
             free(row);
         }
     }
@@ -436,80 +471,70 @@ readXBitmap (int const width,
 
 
 static MS_Ico 
-readIconFile (bool const verbose) {
-    int iter,iter2;
+readIconFile(FILE * const ifP,
+             bool   const verbose) {
+
+    unsigned int i;
 
     MS_Ico MSIconData;
 
     MALLOCVAR(MSIconData);
    
-    /*
-     * reserved - should equal 0.
-     */
-    MSIconData->reserved = readU2();
-    /*
-     * Type - should equal 1
-     */
-    MSIconData->type     = readU2();
-    /*
-     * count - no of icons in file..
-     */
-    MSIconData->count    = readU2();
-    /*
-     * Allocate "count" array of entries.
-     */
+    MSIconData->reserved = readU2(ifP);  /* should be 0 */
+    MSIconData->type     = readU2(ifP);  /* should be 1 */
+    MSIconData->count    = readU2(ifP);  /* # icons in file */
+
     if (verbose) 
         pm_message("Icon file contains %d icons.", MSIconData->count);
 
     MALLOCARRAY(MSIconData->entries, MSIconData->count);
     if (MSIconData->entries == NULL)
         pm_error("out of memory");
-    /*
-     * Read in each of the entries
-     */
-    for (iter = 0;iter < MSIconData->count ; iter++ ) {
-        MSIconData->entries[iter] = readICEntry();
-    }
-    /* After that, we have to read in the infoheader, color map (if
-     * any) and the actual bit/pix maps for the icons.  
-     */
+
+    /* Read in each of the entries */
+    for (i = 0; i < MSIconData->count; ++i)
+        MSIconData->entries[i] = readICEntry(ifP);
+
+    /* Read in the infoheader, color map (if any) and the actual bit/pix maps
+       for the icons.
+    */
     if (verbose) 
-        fprintf (stderr,"#\tColors\tBPP\tWidth\tHeight\n");
-    for (iter = 0;iter < MSIconData->count ; iter++ ) {
-        int bpp;
-        MSIconData->entries[iter]->ih =
-            readInfoHeader (MSIconData->entries[iter]);
+        pm_message("#\tColors\tBPP\tWidth\tHeight\n");
+
+    for (i = 0; i < MSIconData->count; ++i) {
+        unsigned int bpp;  /* bits per pixel */
+
+        MSIconData->entries[i]->ih =
+            readInfoHeader(ifP, MSIconData->entries[i]);
        
-        /* What's the bits per pixel? */
-        bpp = MSIconData->entries[iter]->bitcount; 
+        bpp = MSIconData->entries[i]->bitcount; 
+
         /* Read the palette, if appropriate */
         switch (bpp) {
         case 24:
         case 32:
             /* 24/32 bpp icon has no palette */
             break;
-        default:
-            MALLOCARRAY(MSIconData->entries[iter]->colors, 
-                        MSIconData->entries[iter]->color_count);
-            if (MSIconData->entries[iter]->colors == NULL)
+        default: {
+            unsigned int j;
+
+            MALLOCARRAY(MSIconData->entries[i]->colors, 
+                        MSIconData->entries[i]->color_count);
+            if (MSIconData->entries[i]->colors == NULL)
                 pm_error("out of memory");
 
-            for (iter2 = 0;
-                 iter2 < MSIconData->entries[iter]->color_count ; 
-                 iter2++ ) {
-                MSIconData->entries[iter]->colors[iter2] = readICColor();
-            }
-            break;
+            for (j = 0; j < MSIconData->entries[i]->color_count; ++j)
+                MSIconData->entries[i]->colors[j] = readICColor(ifP);
+        }
         }
         if (verbose) {
-            char cols_text[10];
-            sprintf (cols_text, "%d", MSIconData->entries[iter]->color_count);
-            fprintf (stderr,
-                     "%d\t%s\t%d\t%d\t%d\n", iter,
-                     MSIconData->entries[iter]->color_count ? 
-                     cols_text : "TRUE",
-                     bpp, MSIconData->entries[iter]->width, 
-                     MSIconData->entries[iter]->height);
+            char colsText[10];
+            sprintf (colsText, "%d", MSIconData->entries[i]->color_count);
+            pm_message("%d\t%s\t%d\t%d\t%d\n", i,
+                       MSIconData->entries[i]->color_count ? 
+                       colsText : "TRUE",
+                       bpp, MSIconData->entries[i]->width, 
+                       MSIconData->entries[i]->height);
         }
         /* Pixels are stored bottom-up, left-to-right. Pixel lines are
          * padded with zeros to end on a 32bit (4byte) boundary. Every
@@ -528,35 +553,40 @@ readIconFile (bool const verbose) {
              */
             switch (bpp) {
             case 1:
-                MSIconData->entries[iter]->xorBitmap = 
-                    read1Bitmap(MSIconData->entries[iter]->width,
-                                MSIconData->entries[iter]->height);
+                MSIconData->entries[i]->xorBitmap = 
+                    read1Bitmap(ifP,
+                                MSIconData->entries[i]->width,
+                                MSIconData->entries[i]->height);
                 break;
             case 4:
-                MSIconData->entries[iter]->xorBitmap = 
-                    read4Bitmap(MSIconData->entries[iter]->width,
-                                MSIconData->entries[iter]->height);
+                MSIconData->entries[i]->xorBitmap = 
+                    read4Bitmap(ifP,
+                                MSIconData->entries[i]->width,
+                                MSIconData->entries[i]->height);
                 break;
             case 8:
-                MSIconData->entries[iter]->xorBitmap = 
-                    read8Bitmap(MSIconData->entries[iter]->width,
-                                MSIconData->entries[iter]->height);
+                MSIconData->entries[i]->xorBitmap = 
+                    read8Bitmap(ifP,
+                                MSIconData->entries[i]->width,
+                                MSIconData->entries[i]->height);
                 break;
             case 24:
             case 32:
-                MSIconData->entries[iter]->xorBitmap = 
-                    readXBitmap(MSIconData->entries[iter]->width,
-                                MSIconData->entries[iter]->height,bpp);
+                MSIconData->entries[i]->xorBitmap = 
+                    readXBitmap(ifP,
+                                MSIconData->entries[i]->width,
+                                MSIconData->entries[i]->height,bpp);
                 break;
             default:
-                pm_error("Uncatered bit depth %d",bpp);
+                pm_error("Uncatered bit depth %u", bpp);
             }
             /*
              * Read AND Bitmap
              */
-            MSIconData->entries[iter]->andBitmap = 
-                read1Bitmap(MSIconData->entries[iter]->width,
-                            MSIconData->entries[iter]->height);
+            MSIconData->entries[i]->andBitmap = 
+                read1Bitmap(ifP,
+                            MSIconData->entries[i]->width,
+                            MSIconData->entries[i]->height);
         }
       
     }
@@ -566,15 +596,14 @@ readIconFile (bool const verbose) {
 
 
 static char * 
-trimOutputName(const char inputName[])
-{
+trimmedOutputName(const char inputName[]) {
     /*
      * Just trim off the final ".ppm", if there is one, else return as is.
      * oh, for =~ ... :)
      */
-    char * outFile = strdup(inputName);
-    if (streq(outFile + (strlen (outFile) - 4), ".ppm")) {
-        *(outFile + (strlen (outFile) - 4)) = 0;
+    char * const outFile = strdup(inputName);
+    if (streq(outFile + (strlen(outFile) - 4), ".ppm")) {
+        *(outFile + (strlen(outFile) - 4)) = 0;
     }
     return outFile;
 
@@ -585,29 +614,34 @@ trimOutputName(const char inputName[])
 static int 
 getBestQualityIcon(MS_Ico MSIconData)
 {
-    int x,best,best_size,best_bpp,bpp,size;
-    IC_Entry entry;
-
-    best_size = best_bpp = 0;
-    for (x = 0; x < MSIconData->count; x++) {
-        entry =  MSIconData->entries[x];
-        size = entry->width * entry->height;
-        bpp  = entry->bitcount ? entry->bitcount : entry->ih->bitcount;
-        if (size > best_size) {
-            best = x;
-            best_size = size;
-        } else if (size == best_size && bpp > best_bpp) {
-            best = x;
-            best_bpp = bpp;
+    unsigned int i;
+    unsigned int best;
+    unsigned int bestSize;
+    unsigned int bestBpp;
+
+    for (i = 0, bestSize = 0, bestBpp = 0; i < MSIconData->count; ++i) {
+        IC_Entry const entryP = MSIconData->entries[i];
+        unsigned int const size = entryP->width * entryP->height;
+        unsigned int const bpp  =
+            entryP->bitcount ? entryP->bitcount : entryP->ih->bitcount;
+
+        if (size > bestSize) {
+            best = i;
+            bestSize = size;
+        } else if (size == bestSize && bpp > bestBpp) {
+            best = i;
+            bestBpp = bpp;
         }
     }
     return best;
 }
 
+
+
 static void
 writeXors(FILE *   const multiOutF,
-          char           outputFileBase[], 
-          IC_Entry const entry,
+          char *   const outputFileBase,
+          IC_Entry const entryP,
           int      const entryNum,
           bool     const multiple, 
           bool     const xor) {
@@ -625,85 +659,79 @@ writeXors(FILE *   const multiOutF,
    we are to open a file using outputFileBase[] and 'entryNum' and 'xor'
    to derive its name, and close it afterward.
 -----------------------------------------------------------------------------*/
-    FILE * outF;
-    pixel ** ppm_array;
-    int row;
-    int pel_size;
-    const char *outputFile;
-    int maxval;
-    int forcetext;
+    FILE * ofP;
+    pixel ** pixArray;
+    unsigned int row;
+    const char * outputFileName;
 
     if (multiOutF) {
-        outF = multiOutF;
-        outputFile = strdup("");
+        ofP = multiOutF;
+        outputFileName = strdup("");
     } else {
         if (outputFileBase) {
             if (multiple) {
-                pm_asprintf(&outputFile, "%s%s_%d.ppm",
+                pm_asprintf(&outputFileName, "%s%s_%d.ppm",
                             outputFileBase,(xor ? "_xor" : ""), entryNum);
             } else { 
-                pm_asprintf(&outputFile, "%s%s.ppm",
+                pm_asprintf(&outputFileName, "%s%s.ppm",
                             outputFileBase,(xor ? "_xor" : ""));
             }
         } else
-            outputFile = strdup("-");
+            outputFileName = strdup("-");
         
-        outF = pm_openw(outputFile);
+        ofP = pm_openw(outputFileName);
     }
     /* 
-     * allocate an array to save the bmp data into.
-     * note that entry->height will be 1/2 entry->ih->height,
-     * as the latter adds "and" and "xor" height.
-     */
-    ppm_array = ppm_allocarray(entry->width, entry->height);
-    for (row=0; row < entry->height; row++) {
-        u1 * xorRow;
-        int col;
-        switch (entry->bitcount) {
+       Allocate an array to save the bmp data into.
+       note that entry->height will be 1/2 entry->ih->height,
+       as the latter adds "and" and "xor" height.
+    */
+    pixArray = ppm_allocarray(entryP->width, entryP->height);
+    for (row = 0; row < entryP->height; ++row) {
+        switch (entryP->bitcount) {
         case 24:
-        case 32:
-            pel_size = entry->bitcount >> 3;
-            xorRow = entry->xorBitmap + row * entry->width * pel_size;
-            for (col=0; col < entry->width*pel_size;col+=pel_size) {
-                PPM_ASSIGN(ppm_array[row][col/pel_size],
-                           xorRow[col+2],xorRow[col+1],xorRow[col]);
-            }
-            break;
-        default:
-            xorRow = entry->xorBitmap + row * entry->width;
-            for (col=0; col < entry->width; col++) {
-                int colorIndex;
-                IC_Color color;
-                colorIndex  = xorRow[col];
-                color = entry->colors[colorIndex];
-                PPM_ASSIGN(ppm_array[row][col],
-                           color->red,color->green,color->blue);
+        case 32: {
+            unsigned int const pixelSize = entryP->bitcount >> 3;
+            u1 * const xorRow =
+                entryP->xorBitmap + row * entryP->width * pixelSize;
+            unsigned int col;
+            for (col = 0; col < entryP->width * pixelSize; col += pixelSize)
+                PPM_ASSIGN(pixArray[row][col/pixelSize],
+                           xorRow[col+2], xorRow[col+1], xorRow[col]);
+        } break;
+        default: {
+            u1 * const xorRow = entryP->xorBitmap + row * entryP->width;
+            unsigned int col;
+            for (col = 0; col < entryP->width; ++col) {
+                unsigned int const colorIndex = xorRow[col];
+                IC_Color const colorP = entryP->colors[colorIndex];
+                PPM_ASSIGN(pixArray[row][col],
+                           colorP->red, colorP->green, colorP->blue);
             }
-            break;
+        } break;
         }
     }    
     
-    maxval = 255;
-    forcetext = 0;
-
-    ppm_writeppm(outF,ppm_array,entry->width, entry->height, 
-                 (pixval) maxval, forcetext);
-    ppm_freearray(ppm_array,entry->height);
+    ppm_writeppm(ofP, pixArray, entryP->width, entryP->height, 
+                 255 /* maxval */, false /* text */);
+    ppm_freearray(pixArray, entryP->height);
 
-    pm_strfree(outputFile);
+    pm_strfree(outputFileName);
     
     if (!multiOutF) 
-        pm_close(outF);
+        pm_close(ofP);
 }
             
 
 
 static void
-writeAnds(FILE * const multiOutF, 
-          char outputFileBase[], IC_Entry const entry, int const entryNum, 
-          bool multiple) {
+writeAnds(FILE *       const multiOutF, 
+          char         const outputFileBase[],
+          IC_Entry     const entryP,
+          unsigned int const entryNum, 
+          bool         const multiple) {
 /*----------------------------------------------------------------------------
-   Write the "and" image (i.e. the alpha mask) of the image 'IC_Entry' out.
+   Write the "and" image (i.e. the alpha mask) of the image *entryP out.
 
    'multiple' means this is one of multiple images that are being written.
    'entryNum' is the sequence number within the winicon file of the image
@@ -714,115 +742,122 @@ writeAnds(FILE * const multiOutF,
    we are to open a file using outputFileBase[] and 'entryNum' and 'xor'
    to derive its name, and close it afterward.
 -----------------------------------------------------------------------------*/
-    FILE * outF;
-    bit ** pbm_array;
-    u1 * andRow;
-    int row;
+    FILE * ofP;
+    bit ** bitArray;
+    unsigned int row;
 
     if (multiOutF)
-        outF = multiOutF;
+        ofP = multiOutF;
     else {
-        const char *outputFile;
+        const char * outputFileName;
 
         assert(outputFileBase);
 
         if (multiple) 
-            pm_asprintf(&outputFile, "%s_and_%d.pbm",
+            pm_asprintf(&outputFileName, "%s_and_%u.pbm",
                         outputFileBase, entryNum);
         else 
-            pm_asprintf(&outputFile, "%s_and.pbm", outputFileBase);
-        outF = pm_openw(outputFile);
-        pm_strfree(outputFile);
+            pm_asprintf(&outputFileName, "%s_and.pbm", outputFileBase);
+        ofP = pm_openw(outputFileName);
+        pm_strfree(outputFileName);
     }
-    pbm_array = pbm_allocarray(entry->width, entry->height);
-    for (row=0; row < entry->height; row++) {
-        int col;
-        andRow = entry->andBitmap + row * entry->width;
-        for (col=0; col < entry->width; col++) {
+    bitArray = pbm_allocarray(entryP->width, entryP->height);
+    for (row = 0; row < entryP->height; ++row) {
+        u1 * const andRow = entryP->andBitmap + row * entryP->width;
+        unsigned int col;
+        for (col = 0; col < entryP->width; ++col) {
             /* Note: black is transparent in a Netpbm alpha mask */
-            pbm_array[row][col] = andRow[col] ? PBM_BLACK: PBM_WHITE;
+            bitArray[row][col] = andRow[col] ? PBM_BLACK: PBM_WHITE;
         }
     }
 
-    pbm_writepbm(outF, pbm_array, entry->width, entry->height, 0);
+    pbm_writepbm(ofP, bitArray, entryP->width, entryP->height, 0);
 
-    pbm_freearray(pbm_array, entry->height);
+    pbm_freearray(bitArray, entryP->height);
     if (!multiOutF)
-        pm_close (outF);     
+        pm_close(ofP);
 }
 
 
 
 static void
-openMultiXor(char          outputFileBase[], 
+openMultiXor(char    const outputFileBase[], 
              bool    const writeands,
              FILE ** const multiOutFP) {
 
-    const char *outputFile;
+    const char * outputFileName;
 
     if (outputFileBase) {
-        pm_asprintf(&outputFile, "%s%s.ppm",
+        pm_asprintf(&outputFileName, "%s%s.ppm",
                     outputFileBase, (writeands ? "_xor" : ""));
     } else
-        outputFile = strdup("-");
+        outputFileName = strdup("-");
 
-    /*
-     * Open the output file now, it'll stay open the whole time.
-     */
-    *multiOutFP = pm_openw(outputFile);
+    *multiOutFP = pm_openw(outputFileName);
 
-    pm_strfree(outputFile);
+    pm_strfree(outputFileName);
 }
 
 
 
 static void
-openMultiAnd(char outputFileBase[], FILE ** const multiAndOutFP) {
+openMultiAnd(char    const outputFileBase[],
+             FILE ** const multiAndOutFP) {
 
-    const char *outputFile;
+    const char * outputFileName;
 
     assert(outputFileBase);
 
-    pm_asprintf(&outputFile, "%s_and.pbm", outputFileBase);
+    pm_asprintf(&outputFileName, "%s_and.pbm", outputFileBase);
     
-    *multiAndOutFP = pm_openw(outputFile);
+    *multiAndOutFP = pm_openw(outputFileName);
 
-    pm_strfree(outputFile);
+    pm_strfree(outputFileName);
 }
 
-static void free_iconentry(IC_Entry entry) {
-    int x;
-    if (entry->colors && entry->color_count) {
-        for (x=0;x<entry->color_count;x++) free(entry->colors[x]);
-        free(entry->colors);
+
+
+static void
+freeIconentry(IC_Entry const entryP) {
+
+    if (entryP->colors && entryP->color_count) {
+        unsigned int i;
+        for (i = 0; i <entryP->color_count; ++i)
+            free(entryP->colors[i]);
+        free(entryP->colors);
     }
-    if (entry->andBitmap) free(entry->andBitmap);
-    if (entry->xorBitmap) free(entry->xorBitmap);
-    if (entry->ih) free(entry->ih);
-    free(entry);
+    if (entryP->andBitmap) free(entryP->andBitmap);
+    if (entryP->xorBitmap) free(entryP->xorBitmap);
+    if (entryP->ih) free(entryP->ih);
+    free(entryP);
 }
 
-static void free_icondata(MS_Ico MSIconData)
-{
-    int x;
-    for (x=0;x<MSIconData->count;x++) {
-    free_iconentry(MSIconData->entries[x]);
-    }
-    free(MSIconData);
+
+
+static void
+freeIcondata(MS_Ico const MSIconDataP) {
+
+    unsigned int i;
+    for (i = 0; i < MSIconDataP->count; ++i)
+        freeIconentry(MSIconDataP->entries[i]);
+
+    free(MSIconDataP);
 }
 
 
+
 int 
-main(int argc, char *argv[]) {
+main(int argc, const char *argv[]) {
 
     struct cmdlineInfo cmdline;
-    int startEntry, endEntry;
-    MS_Ico MSIconData;
+    FILE * ifP;
+    unsigned int startEntry, endEntry;
+    MS_Ico MSIconDataP;
     char * outputFileBase;
     FILE * multiOutF;
     FILE * multiAndOutF;
    
-    ppm_init (&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
@@ -833,13 +868,13 @@ main(int argc, char *argv[]) {
     if (streq(cmdline.outputFilespec, "-"))
         outputFileBase = NULL;
     else
-        outputFileBase = trimOutputName(cmdline.outputFilespec);
+        outputFileBase = trimmedOutputName(cmdline.outputFilespec);
 
-    ifp = pm_openr(cmdline.inputFilespec);
+    ifP = pm_openr(cmdline.inputFilespec);
 
     infname = cmdline.inputFilespec;
 
-    MSIconData = readIconFile(cmdline.verbose);
+    MSIconDataP = readIconFile(ifP, cmdline.verbose);
     /*
      * Now we've read the icon file in (Hopefully! :)
      * Go through each of the entries, and write out files of the
@@ -853,18 +888,15 @@ main(int argc, char *argv[]) {
     /*
      * If allicons is set, we want everything, if not, just go through once.
      */
-    startEntry = 0;
-    if (cmdline.allicons) {
-        endEntry = MSIconData->count;
-    } else {
-        endEntry = 1;
-    }
-    /*
-     * If bestqual is set, find the icon with highest size & bpp.
-     */
     if (cmdline.bestqual) {
-        startEntry = getBestQualityIcon(MSIconData);
+        startEntry = getBestQualityIcon(MSIconDataP);
         endEntry = startEntry+1;
+    } else {
+        startEntry = 0;
+        if (cmdline.allicons)
+            endEntry = MSIconDataP->count;
+        else
+            endEntry = 1;
     }
    
     if (cmdline.multippm) 
@@ -878,24 +910,25 @@ main(int argc, char *argv[]) {
         multiAndOutF = NULL;
 
     {
-        int entryNum;
+        unsigned int entryNum;
 
-        for (entryNum = startEntry ; entryNum < endEntry ; entryNum++ ) {
-            IC_Entry const entry = MSIconData->entries[entryNum];
+        for (entryNum = startEntry; entryNum < endEntry; ++entryNum) {
+            IC_Entry const entryP = MSIconDataP->entries[entryNum];
 
-            writeXors(multiOutF, outputFileBase, entry, entryNum, 
+            writeXors(multiOutF, outputFileBase, entryP, entryNum, 
                       cmdline.allicons, cmdline.writeands);
             if (cmdline.writeands)
                 writeAnds(multiAndOutF, outputFileBase, 
-                          entry, entryNum, cmdline.allicons);
+                          entryP, entryNum, cmdline.allicons);
         }
     }
     if (multiOutF)
-        pm_close (multiOutF);    
+        pm_close(multiOutF);    
     if (multiAndOutF)
         pm_close(multiAndOutF);
     
     /* free up the image data here. */
-    free_icondata(MSIconData);
+    freeIcondata(MSIconDataP);
+
     return 0;
 }
diff --git a/converter/ppm/yuvtoppm.c b/converter/ppm/yuvtoppm.c
index 2b44c65f..151ff9f9 100644
--- a/converter/ppm/yuvtoppm.c
+++ b/converter/ppm/yuvtoppm.c
@@ -20,96 +20,201 @@
 ** implied warranty.
 */
 
-#include "ppm.h"
+#include "pm_c_util.h"
 #include "mallocvar.h"
+#include "shhopt.h"
+#include "ppm.h"
 
-/* x must be signed for the following to work correctly */
-#define limit(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
 
-int
-main(argc, argv)
-	char          **argv;
-{
-	FILE           *ifp;
-	pixel          *pixrow;
-	int             argn, rows, cols, row;
-	const char     * const usage = "<width> <height> [yuvfile]";
-    struct yuv {
-        /* This is an element of a YUV file.  It describes two 
-           side-by-side pixels.
-        */
-        unsigned char u;
-        unsigned char y1;
-        unsigned char v;
-        unsigned char y2;
-    } *yuvbuf;
-
-	ppm_init(&argc, argv);
-
-	argn = 1;
-
-	if (argn + 2 > argc)
-		pm_usage(usage);
-
-	cols = atoi(argv[argn++]);
-	rows = atoi(argv[argn++]);
-	if (cols <= 0 || rows <= 0)
-		pm_usage(usage);
-
-	if (argn < argc) {
-		ifp = pm_openr(argv[argn]);
-		++argn;
-	} else
-		ifp = stdin;
-
-	if (argn != argc)
-		pm_usage(usage);
-
-    if (cols % 2 != 0) {
-        pm_error("Number of columns (%d) is odd.  A YUV image must have an "
-                 "even number of columns.", cols);
+
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    unsigned int cols;
+    unsigned int rows;
+    const char * inputFileName;  /* Name of input file */
+};
+
+
+
+static void
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo * const cmdlineP) {
+
+    optEntry * option_def;
+        /* Instructions to OptParseOptions3 on how to parse our options */
+    optStruct3 opt;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    OPTENTINIT;
+
+    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 < 2)
+        pm_error("You need at least two arguments: width and height in "
+                 "pixels.  You specified %u", argc-1);
+    else {
+        int const widthArg  = atoi(argv[1]);
+        int const heightArg = atoi(argv[2]);
+
+        if (widthArg < 0)
+            pm_error("Negative number for width: %d", widthArg);
+        if (heightArg < 0)
+            pm_error("Negative number for height: %d", heightArg);
+
+        cmdlineP->cols = widthArg;
+        cmdlineP->rows = heightArg;
+                 
+        if (cmdlineP->cols % 2 != 0)
+            pm_error("Number of columns (%u) is odd.  "
+                     "A YUV image must have an "
+                     "even number of columns.", cmdlineP->cols);
+
+        if (argc-1 < 3)
+            cmdlineP->inputFileName = "-";
+        else {
+            cmdlineP->inputFileName = argv[3];
+
+            if (argc-1 > 3)
+                pm_error("Too many arguments: %u.  "
+                         "The only possible arguments are "
+                         "width, height, and input file name", argc-1);
+        }
     }
+}
 
-	ppm_writeppminit(stdout, cols, rows, (pixval) 255, 0);
-	pixrow = ppm_allocrow(cols);
-    MALLOCARRAY(yuvbuf, (cols+1)/2);
-    if (yuvbuf == NULL)
-        pm_error("Unable to allocate YUV buffer for %d columns.", cols);
 
-	for (row = 0; row < rows; ++row) {
-		int    col;
 
-		fread(yuvbuf, cols * 2, 1, ifp);
+static int
+limit(int const x) {
 
-		for (col = 0; col < cols; col += 2) {
-            /* Produce two pixels in pixrow[] */
-            int y1, u, v, y2, r, g, b;
+    if (x > 0xffffff)
+        return 0xff;
+    else if (x <= 0xffff)
+        return 0;
+    else
+        return ((x >> 16) & 0xff);
+}
+
+
+
+static int
+nonneg(int const x) {
+/*----------------------------------------------------------------------------
+  Raise 'x' to 0 if negative
+-----------------------------------------------------------------------------*/
+    return x < 0 ? 0 : x;
+}
+
+
+
+struct Yuv {
+/*----------------------------------------------------------------------------
+  This is an element of a YUV file.  It describes two side-by-side pixels.
+
+  This is the actual layout of the data in the file (4 bytes).
+-----------------------------------------------------------------------------*/
+    unsigned char u;
+    unsigned char y1;
+    unsigned char v;
+    unsigned char y2;
+};
 
-			u = yuvbuf[col/2].u-128;
 
-            y1 = yuvbuf[col/2].y1 - 16;
-			if (y1 < 0) y1 = 0;
 
-            v = yuvbuf[col/2].v - 128;
+static void
+readYuv(FILE *       const ifP,
+        struct Yuv * const yuvP) {
 
-            y2 = yuvbuf[col/2].y2 - 16;
-			if (y2 < 0) y2 = 0;
+    size_t readCt;
 
-			r = 104635 * v;
-			g = -25690 * u + -53294 * v;
-			b = 132278 * u;
+    readCt = fread(yuvP, sizeof(*yuvP), 1, ifP);
 
-			y1*=76310; y2*=76310;
+    if (readCt != 1) {
+        if (feof(ifP))
+            pm_error("Premature end of input.");
+        else
+            pm_error("Error reading input.");
+    }
+}
+
+
+
+static void
+yuvtoppm(FILE *       const ifP,
+         unsigned int const cols,
+         unsigned int const rows,
+         FILE *       const ofP) {
+
+    pixval const maxval = 255;
+
+    pixel * pixrow;
+    unsigned int row;
+
+    ppm_writeppminit(ofP, cols, rows, maxval, 0);
+
+    pixrow = ppm_allocrow(cols);
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        for (col = 0; col < cols; col += 2) {
+            /* Produce two pixels in pixrow[] */
+            struct Yuv yuv;
+            int     y1, u, v, y2, r, g, b;
+
+            readYuv(ifP, &yuv);
+
+            u = yuv.u - 128;
+            y1 = nonneg (yuv.y1 - 16);
+            v = yuv.v - 128;
+            y2 = nonneg (yuv.y2 - 16);
+
+            r = 104635 * v;
+            g = -25690 * u + -53294 * v;
+            b = 132278 * u;
+
+            y1 *= 76310;
+            y2 *= 76310;
+
+            PPM_ASSIGN(pixrow[col],
+                       limit(r + y1), limit(g + y1), limit(b + y1));
+            PPM_ASSIGN(pixrow[col + 1],
+                       limit(r + y2), limit(g + y2), limit(b + y2));
+        }
+        ppm_writeppmrow(ofP, pixrow, cols, maxval, 0);
+    }
 
-			PPM_ASSIGN(pixrow[col], limit(r+y1), limit(g+y1), limit(b+y1));
-			PPM_ASSIGN(pixrow[col+1], limit(r+y2), limit(g+y2), limit(b+y2));
-		}
-		ppm_writeppmrow(stdout, pixrow, cols, (pixval) 255, 0);
-	}
-    free(yuvbuf);
     ppm_freerow(pixrow);
-	pm_close(ifp);
-	pm_close(stdout);
 
-	exit(0);
+    if (fgetc(ifP) != EOF)
+        pm_message("Extraneous data at end of image.");
+}
+
+
+
+int
+main (int argc, const char ** argv) {
+
+    FILE * ifP;
+    struct CmdlineInfo cmdline;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    yuvtoppm(ifP, cmdline.cols, cmdline.rows, stdout);
+    
+    pm_close(ifP);
+    pm_close(stdout);
+
+    return 0;
 }
diff --git a/doc/HISTORY b/doc/HISTORY
index 16f04d14..30be7d5c 100644
--- a/doc/HISTORY
+++ b/doc/HISTORY
@@ -4,51 +4,37 @@ Netpbm.
 CHANGE HISTORY 
 --------------
 
-13.06.27 BJH  Release 10.62.09
+13.06.29 BJH  Release 10.63.00
 
-              libnetpbm: fix bug: pnm_readpaminit and pnm_writepaminit set
-              'opacity_plane' member of struct pam incorrectly.  No Netpbm
-              programs are affected.
+              Add pamtowinicon, winicontopam.  Thanks Ludolf Holzheid
+              (lholzheid@bihl-wiedemann.de).
 
-13.06.14 BJH  Release 10.62.08
+              pgmnoise: add -maxval, speed up.  Thanks Prophet of the Way
+              <afu@wta.att.ne.jp>.
 
-              giftopnm: fix bug: erroneously claims GIF ends prematurely.
-              Broken in Netpbm 10.38 (March 2007).  This affects all GIfs, but
-              the problem does not manifest when Netpbm was built with Gcc
-              from 2007 and later.
+              Perl programs: make them shell programs that reinvoke themselves
+              as perl so we can get the Perl interpreter from the PATH.
 
-              libnetpbm: fix bug: ppm_freecolornames() has wild pointer
-              dereference when the color name table was generated empty
-              because the color dictionary file was not openable.  ppmtoxpm
-              suffers from this.  Broken in 10.15 (April 2003).
+              yuvtoppm: check for inconsistencies between specified
+              width and height and size of input.
 
-              ppmtoxpm: fix bug: ignores inability to open the specified color
-              dictionary file (-rgb) and just doesn't use color names.
-              Introduced in Netpbm 10.15 (April 2003).
+              411toppm: check for inconsistencies between specified
+              width and height and size of input.
 
-              ppmforge. fix crash when -mesh is 1 or less.  Always broken
-              (program was added in Pbmplus (October 1991).  Thanks Prophet of
-              the Way <afu@wta.att.ne.jp>.
+              Ignore -plain when program generates PAM.  Before, programs
+              failed if the user specified -plain to a program that generates
+              a PAM image.
 
-              ppmforge: fix array bounds violation.  Always broken (program
-              was added in Pbmplus (October 1991).  Thanks Prophet of the Way
-              <afu@wta.att.ne.jp>.
-
-13.05.27 BJH  Release 10.62.07
+              giftopnm: fix bug: erroneously claims GIF ends prematurely.
+              Broken in Netpbm 10.38 (March 2007).  This affects all GIFs, but
+              the problem does not manifest when Netpbm was built with Gcc
+              from 2007 and later.
 
               pnmtops: Fix bug: only first image gets converted.  Broken in
               Netpbm 10.56 (September 2011).
 
-13.05.20 BJH  Release 10.62.06
-
-              pnmremap (ergo pnmquant): fix bug: incorrect output with
-              -norandom and floyd-steinberg dithering.  Always broken.
-              (-norandom was introduced in Netpbm 10.39 (June 2007)).
-
-13.05.11 BJH  Release 10.62.05
-
               pnmtopng: fix bug: incorrect output when output should have
-              an alpha mask.  Broken Netpbm in 10.55 (June 2011).  Thanks
+              an alpha mask.  Broken in Netpbm 10.55 (June 2011).  Thanks
               Ludolf Holzheid (lholzheid@bihl-wiedemann.de).
 
               pnmtopng: fix bug: output bigger than it needs to be when the
@@ -57,32 +43,55 @@ CHANGE HISTORY
               (September 2003).  Thanks Ludolf Holzheid
               (lholzheid@bihl-wiedemann.de).
 
+              pnmremap (ergo pnmquant): fix bug: incorrect output with
+              -norandom and floyd-steinberg dithering.  Always broken.
+              (-norandom was introduced in Netpbm 10.39 (June 2007)).
+
               pamtilt: fix bug: incorrect output or invalid memory access
               crash.  Always broken (program was new in Netpbm 10.30
               (October 2005)).
 
-13.05.02 BJH  Release 10.62.04
+              pnmpsnr: fix bug: says types aren't the same when they are.
+              Introduced in Netpbm 10.61 (December 2012).
+              
+              ppmtowinicon: fix bug: sometimes creates image truncated in the
+              middle of the AND mask.  Always broken (program was new in
+              Netpbm 9.3 (June 2000)).
+
+              ppmtoxpm: fix bug: ignores inability to open the specified color
+              dictionary file (-rgb) and just doesn't use color names.
+              Introduced in Netpbm 10.15 (April 2003).
+
+              libnetpbm: fix bug: ppm_freecolornames() has wild pointer
+              dereference when the color name table was generated empty
+              because the color dictionary file was not openable.  ppmtoxpm
+              suffers from this.  Broken in 10.15 (April 2003).
+
+              libnetpbm: fix bug: pnm_readpaminit and pnm_writepaminit set
+              'opacity_plane' member of struct pam incorrectly.  No Netpbm
+              programs are affected.  Always broken (member was added in
+              Netpbm 10.56 (September 2011)).
 
               sparc64 pbmtog3: fix bug that causes crash due to unaligned
               memory access.
 
-13.04.18 BJH  Release 10.62.03
+              ppmforge. fix crash when -mesh is 1 or less.  Always broken
+              (program was added in Pbmplus (October 1991).  Thanks Prophet of
+              the Way <afu@wta.att.ne.jp>.
 
-              build: fix problem with creating lib/util that already exists.
-              Broken in 10.62.
+              ppmforge: fix array bounds violation.  Always broken (program
+              was added in Pbmplus (October 1991).  Thanks Prophet of the Way
+              <afu@wta.att.ne.jp>.
 
-13.04.13 BJH  Release 10.62.02
+              install: fix Perl warning in installnetpbm.  Broken in 
+              Netpbm 10.61.
 
-              ppmtowinicon: fix bug: sometimes creates image truncated in the
-              middle of the AND mask.  Always broken (program was new in
-              Netpbm 9.3 (June 2000)).
+              build: Use <stdbool.h> when available.
 
-              install: fix Perl warning in installnetpbm.  Broken in 10.61.
+              build: fix problem with creating lib/util that already exists.
+              Broken in Netpbm 10.62.
 
-              pnmpsnr: fix bug: says types aren't the same when they are.
-              Introduced in 10.61 (December 2012).
-              
-13.03.28 BJH  Release 10.62.00
+12.03.28 BJH  Release 10.62.00
 
               pnmtorast: set don't care bytes to zero to make output
               repeatable.
@@ -90,16 +99,16 @@ CHANGE HISTORY
               rasttopnm: add -dumpheader, dumpcolormap.
 
               pamstereogram: change -guidesize default from 10 to 20
-              (relevant since 10.61).
+              (relevant since Netpbm 10.61).
 
               rasttopnm: fix bug: incorrect output due to used-before-set
-              variable.  Introduced in 10.56 (September 2011).
+              variable.  Introduced in Netpbm 10.56 (September 2011).
 
               pamstereogram: fix bug: doesn't reject negative guidesize.
-              Broken since 10.61.
+              Broken since Netpbm 10.61.
 
               pamstereogram: fix bug: garbage in -verbose listing.  Broken
-              since 10.61
+              since Netpbm 10.61
 
               MinGW build: various fixes.
 
@@ -127,7 +136,7 @@ CHANGE HISTORY
               libpam, pamcomp: fix bug: treats tuple type GRAYSCALE_ALPHA like
               GRAYSCALE on 32-bit machine.  Actually, looks only at first 4
               characters (8 characters on machine with 64 bit addressess) of
-              the tuple type.  Broken since 10.56 (September 2011).
+              the tuple type.  Broken since Netpbm 10.56 (September 2011).
 
               pngtopam -alphapam with grayscale input: fix bug: generates
               invalid output: tuple type GRAYSCALE_ALPHA, but depth 1.  Depth
@@ -135,7 +144,7 @@ CHANGE HISTORY
               Netpbm 10.44 (September 2008)).
               
               pamtotiff: fix bug: XRESOLUTION, YRESOLUTION, and RESOLUTIONUNIT
-              not allowed in -tags.  Broken at least since 10.35.
+              not allowed in -tags.  Broken at least since Netpbm 10.35.
 
               pnmpsnr: fix crash when invoked (invalidly) with only one
               argument.  Always broken.
@@ -146,29 +155,30 @@ CHANGE HISTORY
               cmuwmtopbm: fix incorrect determination of whether input is
               a CMU window manager bitmap on 64 bit systems.  Always broken.
 
-              pnmmontage: fix totally wrong output.  Broken in 10.44
+              pnmmontage: fix totally wrong output.  Broken in Netpbm 10.44
               (August 2008).
 
               pnmmontage: fix random stuff placed in unoccupied space in the
-              output image.  Always broken (program was new in 9.10 (January
-              2001).
+              output image.  Always broken (program was new in Netpbm 9.10
+              (January 2001).
 
-              pbmpscale, pgmhist, pampick, pamtompfont: fix wild pointer
-              in command line parsing.  Bug has always been there in 
-              pampick, pamtompfont, since 10.50 (March 2010) in pbmpscale,
-              since 10.44 (September 2008) in pgmhist.              
+              pbmpscale, pgmhist, pampick, pamtompfont: fix wild pointer in
+              command line parsing.  Bug has always been there in pampick,
+              pamtompfont, since Netpbm 10.50 (March 2010) in pbmpscale, since
+              10.44 (September 2008) in pgmhist.
 
               xbmtopbm: fix incorrect output, memory leak.  Thanks Prophet of
               the Way <afu@wta.att.ne.jp>.
 
               sunicontopnm: Fix incorrect output for depth 8.  Always broken
-              (depth = 8 capability was added in 10.53 (December 2010).
+              (depth = 8 capability was added in Netpbm 10.53 (December 2010).
 
               pamgauss: Fix bug: erroneously says -maxval is too big on 64 bit
-              system.  Always broken (Pamgauss was added in 10.23 (July 2004).
+              system.  Always broken (Pamgauss was added in Netpbm 10.23 (July
+              2004).
 
-              ppmpat: Fix bug: wrong output with -poles.  Broken in 10.47
-              (June 2009).
+              ppmpat: Fix bug: wrong output with -poles.  Broken in Netpbm
+              10.47 (June 2009).
 
               Add tests.  Thanks Prophet of the Way <afu@wta.att.ne.jp>.
 
@@ -179,19 +189,20 @@ CHANGE HISTORY
               linear search or direct index, go row by row.
 
               xpmtoppm: fix bogus "color number too large" failure.  Broken
-              in 10.49 (December 2009).
+              in Netpbm 10.49 (December 2009).
 
               pnm_hashtuple: slight performance improvement from new hash
               function.  Thanks Prophet of the Way <afu@wta.att.ne.jp>.
 
               ppmtospu: wild memory accesses.  Always broken (program added in
-              10.58 (March 2012).
+              Netpbm 10.58 (March 2012).
 
               pamtosrf: fix storage corruption.  Always broken (program added
-              in 10.55 (June 2011).
+              in Netpbm 10.55 (June 2011).
 
-              Build: change _XOPEN_SOURCE 500 to 600 because on a Mac OSX 10.8
-              system, this is necessary to get 'strdup' into <strings.h>.
+              Build: change _XOPEN_SOURCE 500 to 600 because on a Mac OSX
+              Netpbm 10.8 system, this is necessary to get 'strdup' into
+              <strings.h>.
 
               Build: rename getline() in xpmtoppm.c to avoid collision
               with some libc.  Always broken.
@@ -214,20 +225,23 @@ CHANGE HISTORY
               pamstereogram: improve verbose output.  Thanks Scott Pakin
               (scott@pakin.org).
 
-              pamstereogram: fix crash introduced in 10.54 (March 2011).
+              pamstereogram: fix crash introduced in Netpbm 10.54 (March 2011).
 
-              pamstereogram: fix crash introduced in 10.53 (December 2010).
+              pamstereogram: fix crash introduced in Netpbm 10.53 (December
+              2010).
 
-              Build: fix bug: declines to build pnmtops.  Broken in 10.58.
+              Build: fix bug: declines to build pnmtops.  Broken in Netpbm
+              10.58.
 
-              Build: move -lm to end of -l's.  Broken at least since 10.35.
+              Build: move -lm to end of -l's.  Broken at least since Netpbm
+              10.35.
 
 12.03.29 BJH  Release 10.58.00
 
               Add ppmtospu, 22 years late.
 
               pngtopam: fix incorrect output when PNG has 16 bits per pixel.
-              Broken in 10.56.
+              Broken in Netpbm 10.56.
 
               pgmtexture: fix integer overflow in difference variance.
               Always broken.
@@ -244,7 +258,7 @@ CHANGE HISTORY
               to Perl.
 
               Windows/Mingw: fix bug: temporary file creation fails
-              consistently.  Broken in 10.34.
+              consistently.  Broken in Netpbm 10.34.
 
               Windows/Mingw: set binary mode on files.
 
@@ -272,7 +286,8 @@ CHANGE HISTORY
 
               pngtopam: fix crash with invalid tIME chunk.  Always broken.
 
-              pamarith: fix wrong result with -multiply.  Broken in 10.41.
+              pamarith: fix wrong result with -multiply.  Broken in Neptbm
+              10.41.
 
               pamscale: fix all black output with resampling.  Always broken.
 
@@ -306,17 +321,17 @@ CHANGE HISTORY
 
               libnetpbm, many programs: fix bug in pm_allocarray(): returns
               NULL when can't get memory.  Calling programs thus crash on
-              very large images.  Introduced in 10.51.
+              very large images.  Introduced in Netpbm 10.51.
               
               pnmtopng: fix bug: with -alpha specifying a mask which contains
               no fully transparent area, output PNG is fully opaque.
-              Introduced in 10.29.
+              Introduced in Netpbm 10.29.
 
               pnmtops: fix message: says "from top edge" where it means
               "from bottom edge."
 
               ppmcie: fix bug: fails with "X coordinate out of range" error.
-              Introduced in 10.51.
+              Introduced in Neptbm 10.51.
 
               bmptopnm: Fail properly with BMP that indicates an illegal bits
               per pixel.
@@ -336,18 +351,18 @@ CHANGE HISTORY
               pgmtexture: fix wrong sum variance result.  Wrong since the
               beginning.  Thanks Francois P. S. Luus <fpsluus@gmail.com>.
 
-              pamrubber: fix crash.  Introduced in 10.54.
+              pamrubber: fix crash.  Introduced in Netpbm 10.54.
 
               libnetpbm: pm_system(): fix bug - program always takes
               Standard Input from invoker's Standard Input when you don't
-              supply a Standard Output accepter.  Introduced in 10.40.
+              supply a Standard Output accepter.  Introduced in Netpbm 10.40.
 
               ppmtobmp: fix bug: crash ("internal error") or bogus failure or
               incorrect output on image without palette (e.g. black and
-              white).  Introduced in 10.54.
+              white).  Introduced in Netpbm 10.54.
 
               pnmtops: fix floating point exception or bogus width/height
-              too large error.  Introduced in 10.53.
+              too large error.  Introduced in Netpbm 10.53.
 
               pnmcat: Fix garbage output when multiple input image are from
               Standard Input (now it just fails gracefully).
@@ -360,12 +375,12 @@ CHANGE HISTORY
               structure.
 
               Build: fix undefined "strsol" and "vsnprintfN" failure on
-              systems without vasprintf().  Introduced in 10.53.
+              systems without vasprintf().  Introduced in Netpbm 10.53.
 
               Build: fix compiler warning in pbmtocmuwm.
 
               configure: fix selection of mingw compiler.  Introduced in
-              10.48.
+              Netpbm 10.48.
 
 11.03.30 BJH  Release 10.54.00
 
@@ -386,7 +401,7 @@ CHANGE HISTORY
               Add libpamd (PAM version of classic libppmd drawing routines).
 
               Rename pbmtoicon to pbmtosunicon, to go with change
-              of icontopbm to sunicontopnm in 10.53.
+              of icontopbm to sunicontopnm in Netpbm 10.53.
 
               g3topbm: correct error message: codes go up to 13 bits.
 
@@ -420,11 +435,11 @@ CHANGE HISTORY
               the BMP header of a compressed file.  Always broken.
               
               bmptopnm: don't crash on large invalid value of 'colorsused' in
-              the BMP header.  Introduced in 9.11.
+              the BMP header.  Introduced in Netpbm 9.11.
 
               pm_mallocarray2: fix wild pointers when image is too big to fit
               in a single chunk of malloc memory.  Affects many Netpbm
-              programs.  Introduced in 10.51.00.
+              programs.  Introduced in Netpbm 10.51.00.
 
               ilbmtoppm: Don't crash on image that has a transparent color
               index, but no color map.
@@ -455,7 +470,7 @@ CHANGE HISTORY
               fitstopnm: Deal properly with NaN in input image.
 
               pm_floatFromBigendFloat, pm_doubleFromBigendFloat, fitstopnm:
-              fix corrupted output.  Broken in 10.46.
+              fix corrupted output.  Broken in Netpbm 10.46.
 
               pamtopdbimg: fix corrupted output image.  Thanks Scott Pakin.
 
@@ -497,10 +512,10 @@ CHANGE HISTORY
               bits).
 
               pnmconvol: fix reversed sense of -nooffset.  Introduced in
-              10.49.
+              Netpbm 10.49.
 
               ppmtompeg: fix crash with free of unallocated memory.
-              Broken after 10.18, not later than 10.26.
+              Broken after Netpbm 10.18, not later than 10.26.
 
               Build: fix parallel make - multiple simultaneous attempts to
               build lib/util/importinc.
@@ -539,19 +554,19 @@ CHANGE HISTORY
               Prophet of the Way <afu@wta.att.ne.jp>.
 
               pbmtext/libpbmfont: Fix wild pointer; probably asymptomatic.
-              Introduced in 10.39.
+              Introduced in Netpbm 10.39.
 
               pbmtext/libpbmfont: Fix some error messages for bad fonts.
 
               pbmtext/libpbmfont: fix crash with a BDF font with negative
-              left or bottom border.  Introduced in 10.39.
+              left or bottom border.  Introduced in Netpbm 10.39.
 
-              pamarith: fix memory leak.  Introduced in 10.41.
+              pamarith: fix memory leak.  Introduced in Netpbm 10.41.
 
               pnm_bytespersample(): fix bogus assertion on 64 bit system.
 
               pnmtops: fix bug: 12 bits per sample output when 8 would do.
-              Introduced in 10.40.
+              Introduced in Netpbm 10.40.
 
               palmtopnm: fix for pixel size 16.  Thanks Paul Bolle
               <pebolle@tiscali.nl>.
@@ -567,17 +582,18 @@ CHANGE HISTORY
               <afu@wta.att.ne.jp>.
 
               pnmsmooth: fix wild pointer: causes wrong arguments to
-              'pnmconvol'.  Introduced in 10.50.  Thanks Prophet of the Way
-              <afu@wta.att.ne.jp>.
+              'pnmconvol'.  Introduced in Netpbm 10.50.  Thanks Prophet of the
+              Way <afu@wta.att.ne.jp>.
 
-              pamscale: fix -reduce.  Introduced in 10.27.
+              pamscale: fix -reduce.  Introduced in Netpbm 10.27.
 
               pampaintspill: fix incorrect output.
 
               libnetpbm text drawing: fix incorrect output in all cases.
-              Introduced in 10.47.
+              Introduced in Netpbm 10.47.
 
-              libnetpbm line drawing: fix bogus assertion, introduced in 10.47.
+              libnetpbm line drawing: fix bogus assertion, introduced in
+              Netpbm 10.47.
 
               build: fix incorrect determination of when vasprintf() exists
               in libc.
@@ -635,14 +651,14 @@ CHANGE HISTORY
               pnmhistmap: Fix crash with -width.  Always broken.
 
               libppmd/ppmpat: fix wild pointer in ppmd_fill_drawprocp();
-              broken in 10.47.
+              broken in Netpbm 10.47.
 
               palmtopnm: fix incorrect "PALM_DIRECT_COLOR_FLAG is not valid
               for version 3 encoding type" failure.  Thanks Paul Bolle
               <pebolle@tiscali.nl>.
 
               pamtosvg: fix bug: occasional crash with out of range error.
-              Introduced in 10.42.
+              Introduced in Netpbm 10.42.
 
               palmtopnm: fix incorrect output with version 3 direct color.
               Thanks Paul Bolle <pebolle@tiscali.nl>.
@@ -695,7 +711,7 @@ CHANGE HISTORY
               pnmtofiasco, fiascotopnm: fix bug on bigendian machine.
 
               pngtopam: use png_create_read_struct() instead of
-              png_create_write_struct().  Broken since 10.48.
+              png_create_write_struct().  Broken since Netpbm 10.48.
 
               configure: advise if adding -lz -lm fixes libpng link problem.
 
@@ -786,7 +802,7 @@ CHANGE HISTORY
               problems.
 
               ilbmtoppm: fix some bug in interpreting ILBM input.
-              (due to wrong pm_uintFromBigend16()).  From 10.46.
+              (due to wrong pm_uintFromBigend16()).  From Netpbm 10.46.
 
               ximtoppm: fix crash in command line processing.
 
@@ -797,7 +813,7 @@ CHANGE HISTORY
               ppmquantall: don't use 'set' to set Bourne shell variable.
 
               pnmtile: fix reference to arbitrary storage in option
-              processing.  Introduced in 10.42.
+              processing.  Introduced in Netpbm 10.42.
 
               pamstereogram: fix tuple type in output file (and crash
               with -verbose) with -patfile .
@@ -837,23 +853,23 @@ CHANGE HISTORY
               the background color (i.e. the color of added margins).
 
               pnmscale: finally make it just an alias of pamscale, which
-              obsoleted it in 10.20.
+              obsoleted it in Netpbm 10.20.
               
               pnmcut: finally make it just an alias of pamcut, which
-              obsoleted it in 9.20.
+              obsoleted it in Netpbm 9.20.
 
               tifftopnm: fix orientation problem on big-endian machines.
-              Introduced in 10.42.
+              Introduced in Netpbm 10.42.
 
               pnmcrop: various fixes.
 
-              g3topbm: fix array bound violation.  Introduced in 10.32.
+              g3topbm: fix array bound violation.  Introduced in Netpbm 10.32.
 
               pnmcat: fix array bound violation with PBM top/bottom
-              concatenation.  Introduced in 10.44.
+              concatenation.  Introduced in Netpbm 10.44.
 
               ilbmtoppm: Fix array bound violation with compressed ILBM.
-              Introduced in 10.18.
+              Introduced in Netpbm 10.18.
 
               fitstopnm: fix garbage output when input is little endian
               floating point FITS.
@@ -864,7 +880,7 @@ CHANGE HISTORY
               picttoppm: Improve error/informational messages.
 
               picttoppm: Don't fail if 'fontdir' file doesn't exist.  Bug
-              from 10.44.
+              from Netpbm 10.44.
 
               ppmtopict: Use two-byte length field when image width > 200
               instead of > 250.  Former is what Picttoppm has been assuming
@@ -873,11 +889,11 @@ CHANGE HISTORY
 
               ilbmtoppm: fix bug: appends color map PPM to output if input
               has color map; fails if input doesn't have color map.  Broken
-              in 10.18.
+              in Netpbm 10.18.
 
               leaftoppm: fix bug: uses red channel as all three channels;
-              (produces grayscale output).  Broken between 10.19 and 10.26,
-              inclusive.
+              (produces grayscale output).  Broken between Netpbm 10.19 and
+              10.26, inclusive.
 
               pbmtomrf, mrftopbm: fix crashes, incorrect output in all
               cases.  Broken forever.
@@ -918,7 +934,7 @@ CHANGE HISTORY
 
               Build: Move LDFLAGS later so that a -L in LDFLAGS doesn't
               interfere with finding the built libnetpbm.  (The common
-              link rule is already this way in 10.44.00; all the other
+              link rule is already this way in Netpbm 10.44.00; all the other
               link rules are now the same).
 
               Build: Rename Makefile.common, Makefile.config, to common.mk,
@@ -964,13 +980,13 @@ CHANGE HISTORY
 
               pamtosvg: remove "needed exchange" debug trace.
 
-              Add pbmminkowski (source code has been in package since 10.12
-              but not documented or built by default).
+              Add pbmminkowski (source code has been in package since Netpbm
+              10.12 but not documented or built by default).
 
               pnmmontage: don't corrupt file names when they contain
               colons.
 
-              pamflip: fix bug: garbage output for PBMs, since 10.42.
+              pamflip: fix bug: garbage output for PBMs, since Netpbm 10.42.
 
               pngtopnm: fix gamma correction.
 
@@ -1013,7 +1029,7 @@ CHANGE HISTORY
               pamtohtmltbl: fix output error: contains holes due to
               uninitialized memory.
 
-              xvminitoppm: fix.  Totally broken since 10.34.
+              xvminitoppm: fix.  Totally broken since Netpbm 10.34.
 
               pnmtopclxl: fix crash with Standard Input input.
 
@@ -1029,7 +1045,7 @@ CHANGE HISTORY
               height, width.
 
               Add back ppmd_fill_init() for backward compatibility;
-              removed in 10.29.
+              removed in Netpbm 10.29.
 
               Build: make it work with Gcc 4.3 and -sse.
 
diff --git a/doc/INSTALL b/doc/INSTALL
index 474b61cf..f8397ca2 100644
--- a/doc/INSTALL
+++ b/doc/INSTALL
@@ -52,6 +52,29 @@ and it will attempt to build whatever it hasn't successfully built
 yet.
 
 
+CHECKING THE BUILD
+------------------
+
+The package comes with a test facility, which you can run after packaging,
+against the package you created.  The typical sequence is
+
+    make
+
+    make package
+
+    make check
+
+    ./installnetpbm
+
+To capture all the messages from "make check" do:
+
+    make check > test.log  2>&1
+
+The test facility was new in Netpbm 10.61 (December 2012).
+
+For further information on the tests read the document TESTS.
+
+
 AUTOMATING THE BUILD
 --------------------
 
diff --git a/doc/TESTS b/doc/TESTS
new file mode 100644
index 00000000..3196a8fb
--- /dev/null
+++ b/doc/TESTS
@@ -0,0 +1,302 @@
+Contents
+========
+
+1. Running the tests
+  1.1 Standard test procedure
+  1.2 Summary report
+  1.3 Prerequisites
+  1.4 Repeatability
+  1.5 Execution time
+  1.6 Testing package in designated directory
+  1.7 Post-install check
+  1.8 Skipping test items
+  1.9 Valgrind
+
+2. Troubleshooting
+  2.1 Missing programs
+  2.2 Broken programs
+  2.3 Color name file
+  2.4 Multiple versions
+  2.5 System dependent issues
+
+3. Reporting test failures
+
+------------------------------------------------------------------------------
+
+1. Running the tests
+====================
+
+1.1 Standard test procedure
+===========================
+
+The recommended method of running the tests is after packaging:
+
+   make
+   make package
+   make check
+
+To capture the output do:
+
+   make check 2>&1 | less
+
+Or:
+
+   make check > check.log  2>&1
+
+
+
+1.2 Summary report
+==================
+
+Like most other test routines, these produce much output.  A summary will
+appear at the end:
+
+  Test summary:
+  ==================
+  SUCCESS 83
+  FAILURE 1
+  TOTAL SUPPORTED 84
+  ==================
+  All tests done.
+  Sat, 08 Jun 2013 09:30:33 +0000
+  make: *** [check] Error 1
+
+
+
+1.3 Prerequisites
+=================
+
+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.
+
+The tests also use the following utilities:
+
+  - awk 
+  - cat
+  - cmp
+  - egrep
+  - head
+  - mktemp
+  - sed
+  - seq
+  - tee
+
+
+
+1.4 Repeatability
+=================
+
+The current version of the test package produces identical results if you run
+"make check" repeatedly.  The tests contain no random elements; some
+Netpbm programs use randomness internally, but the tests seed their random
+number generators with fixed values so that they too have repeatable results.
+
+
+
+1.5 Execution time
+==================
+
+Currently "make check" takes no more time to execute than "make package",
+and much less than "make".
+
+
+
+1.6 Testing package in designated directory
+===========================================
+
+If you specify the package directory when you do "make package",
+you must do the same with "make check":
+
+   make
+   make package pkgdir=/tmp/package
+   make check pkgdir=/tmp/package
+
+
+
+1.7 Post-install check
+======================
+
+You can run the tests after installation as well as from the package
+directory.  Just set $PBM_TESTPREFIX to the bin directory.  For example, if
+the Netpbm executables are in /usr/local/bin/ do
+
+   PBM_TESTPREFIX=/usr/local/bin make check
+
+If you want to test the executables in the default search path do
+
+   PBM_TESTPREFIX="" make check
+
+If the color dictionary file rgb.txt is in a non-standard location, you must
+set RGBDEF.  If you don't, the tests will report several false positives.
+
+   PBM_TESTPREFIX=/usr/local/bin RGBDEF=/etc/colors/rgb.txt make check
+
+
+
+1.8 Skipping test items
+=======================
+
+The file test/Test-Order is a list of tests which are run.  If you want to
+skip any test, remove the line or comment it out with a "#".
+
+
+
+1.9 Valgrind
+============
+
+You can run the whole test under Valgrind.  This is an advanced feature
+intended for programmers who work on Netpbm code.
+
+To turn on Valgrind, uncomment this line in test/Execute:
+
+# export PBM_TESTPREFIX="valgrind --log-fd=4 "${PBM_TESTPREFIX}
+
+   make check 4> valgrind.log
+
+Note that Valgrind output is directed to file descriptor 4.
+
+Valgrind version 3.5.0 or newer is recommended.  Older versions do
+not report the command that is being executed.
+
+You can add any options for Valgrind should by editing the above mentioned
+line.  To run "valgrind --track-origins=yes", you must make two changes in
+config.mk:
+
+  - Add -g to CFLAGS.
+  - Turn stripping off.
+
+Valgrind significantly increases execution time.  You should consider paring
+down the items in Test-Order.  You probably don't need to run
+"all-in-place.test", which has restrictions in the way errors are reported
+when PBM_TESTPREFIX is not a simple directory path.  Another test
+"pamslice-roundtrip.test" is time-consuming, you may want to skip this one
+too.
+
+
+
+2. Troubleshooting
+==================
+
+2.1 Missing programs
+====================
+
+The first test run, "all-in-place.test" detects missing programs.
+
+If you work around a build glitch with "make --keep-going" you
+will get a few errors here.
+
+A wholesale failure with "all-in-place.test" indicates a systemic
+problem, such as a misconfigured dynamic library or a directory-wide
+permission issue.  This kind of failure is known to happen when N is
+set too high with "make -jN" (overambitious parallel make.) 
+
+The current test routines assume a typical build configuration - they are not
+aware of the actual configuration you chose.  If a choice you make during
+configure causes "make" to skip compilation of certain programs, the test
+routines won't know and will report failures.
+
+For details read 'Netpbm Library Prerequisites':
+http://netpbm.sourceforge.net/prereq.html .
+
+
+
+2.2 Broken programs
+===================
+
+Broken programs will invariably lead to failures.  Certain programs
+(for instance, image generators pbmmake pgmmake) are used in numerous
+test scripts.  Problem in them will lead to multiple failures.
+
+To aid you in this situation each test routine lists the necessary programs
+near the top.
+
+Each test routine comes in two parts, a ".test" file which is a
+shell script and a ".ok" file which denotes its proper output.
+When a test fails, a ".out" file will be produced in the
+/tmp/netpbm-test/ directory.  By comparing ".ok" and ".out" you
+can tell exactly what went wrong.  Often one does not need to
+go this far; the error messages tell enough.
+
+
+
+2.3 Color dictionary file
+=========================
+
+If you get the following error message, it indicates a problem with
+the color dictionary file rgb.txt.
+
+  ppmmake: can't open color names dictionary file from the path '/usr/share/
+  netpbm/rgb.txt:/usr/lib/X11/rgb.txt:/usr/share/X11/rgb.txt:/usr/X11R6/lib/
+  X11/rgb.txt' and Environment variable RGBDEF not set.  Set RGBDEF to the
+  pathname of your rgb.txt file or don't use color names.
+
+This is highly unlikely to occur with "make check" right after packaging,
+but may appear after installation.
+
+To check manually after installation, execute the following and see
+whether the proper output or the error message appears:
+
+   ppmmake red 1 1 -plain
+
+Proper output:
+
+   P3
+   1 1
+   255
+   255 0 0
+
+The simple remedy is properly setting the environment value RGBDEF to
+the location of rgb.txt.
+
+If you want to hardcode the path, modify RGB_DB_PATH in pm_config.h
+and run "make" again.  Note that running "configure" will cause
+pm_config.h to be overwritten; changes by editing will be lost.
+
+
+
+2.4 Multiple versions
+=====================
+
+If multiple versions of Netpbm executables are installed on your
+system, you should do a post-installation check to ensure that
+the newly built version is in place and in working condition.
+
+The test routines can test binaries other than the intended
+target, for example pre-compiled binaries distributed in .rpm
+or .deb format.  If PBM_TESTPREFIX is explicitly set to a directory
+that contains programs from such a source, you should expect multiple
+failures due to missing programs, missing features, etc.  If
+PBM_TEXTPREFIX is set to "" (null), the outcome will depend heavily
+on what version has precedence in PATH.
+
+Netpbm distributed with Debian or Ubuntu is called "Netpbm-Free" and
+is based on a fork which broke off in 2002.  There are many differences.
+Many tests will fail.  However, the test framework itself is valid for
+these distributions.
+
+
+
+2.5 System dependent issues
+===========================
+
+The tests have worked on x86 and x86_64 GNU/Linux systems, with several
+versions of GCC and Clang.  Reports from users of other systems including Mac
+OS, Sun SPARC and BSD and compilers other than GCC are highly welcome.
+
+Floating point math precision seems to be an issue.  Some discrepancies
+have been observed between x86 32 bit and 64 bit; the tests are written to
+work around them as much as possible.  The use of the "--fast-math"
+flag by default may also be a factor.
+
+The current test framework checks whether the random number generator
+is the one from glibc and skips certain tests if a different one is
+detected.
+
+
+3. Reporting test failures
+==========================
+
+When reporting problems with the tests, please give both
+the output of "make check" and the contents of the "netpbm-test"
+directory.
diff --git a/doc/patent_summary b/doc/patent_summary
index 271f227c..324fec0d 100644
--- a/doc/patent_summary
+++ b/doc/patent_summary
@@ -48,12 +48,27 @@ do their JPEG work via a JPEG library not distributed with Netpbm.
 Your JPEG-related liability for using Netpbm is limited to your 
 liability for using your JPEG library.
 
+Note that it is possible to use Ppmtompeg without involving JPEG and to
+build it without the ability to involve JPEG.
+
 The next best alternative to JPEG is probably PNG and maybe JBIG for
 bilevel (black and white) images.
 
 http://burnalljpegs.org contains information on this issue.
 
 
+MPEG patents
+------------
+
+The original University of California distributeion of the Ppmtompeg code
+conatins this statement in a README file:
+
+  ... patents are held by several companies on various aspects of the MPEG
+  video standard.  Companies or individuals who want to develop commercial
+  products that include this code must acquire licenses from these companies.
+  For information on licensing, see Appendix F in the standard.
+
+
 Expired LZW patents
 -------------------
 
diff --git a/editor/pamcut.c b/editor/pamcut.c
index 068ad377..03573796 100644
--- a/editor/pamcut.c
+++ b/editor/pamcut.c
@@ -675,7 +675,7 @@ main(int argc, const char *argv[]) {
 
     struct cmdlineInfo cmdline;
     FILE * ifP;
-    bool eof;
+    int eof;
 
     pm_proginit(&argc, argv);
 
diff --git a/editor/pamscale.c b/editor/pamscale.c
index 1b3ab8f0..485ae27f 100644
--- a/editor/pamscale.c
+++ b/editor/pamscale.c
@@ -1392,7 +1392,7 @@ outputOneResampledRow(const struct pam * const outpamP,
 -----------------------------------------------------------------------------*/
     unsigned int col;
 
-    bool haveOpacity;           /* There is an opacity plane */
+    int haveOpacity;           /* There is an opacity plane */
     unsigned int opacityPlane;  /* Plane number of opacity plane, if any */
 
     pnm_getopacity(outpamP, &haveOpacity, &opacityPlane);
@@ -2205,7 +2205,7 @@ main(int argc, const char **argv ) {
 
     struct cmdlineInfo cmdline;
     FILE * ifP;
-    bool eof;
+    int eof;
 
     pm_proginit(&argc, argv);
 
diff --git a/editor/pamthreshold.c b/editor/pamthreshold.c
index 8369602d..8d28bc4a 100644
--- a/editor/pamthreshold.c
+++ b/editor/pamthreshold.c
@@ -658,7 +658,7 @@ main(int argc, char **argv) {
     FILE * ifP; 
     struct cmdlineInfo cmdline;
     struct pam inpam, outpam;
-    bool eof;  /* No more images in input stream */
+    int eof;  /* No more images in input stream */
 
     pnm_init(&argc, argv);
 
diff --git a/editor/pnmcrop.c b/editor/pnmcrop.c
index 042e9e20..c6aabff1 100644
--- a/editor/pnmcrop.c
+++ b/editor/pnmcrop.c
@@ -870,8 +870,8 @@ main(int argc, const char *argv[]) {
         */
     FILE * bdfP;
         /* The border file.  NULL if none. */
-    bool eof;    /* no more images in input stream */
-    bool beof;   /* no more images in borderfile stream */
+    int eof;    /* no more images in input stream */
+    int beof;   /* no more images in borderfile stream */
 
     pm_proginit(&argc, argv);
 
diff --git a/editor/pnmflip b/editor/pnmflip
index 44d95b45..07d4ddb9 100755
--- a/editor/pnmflip
+++ b/editor/pnmflip
@@ -1,5 +1,28 @@
-#!/usr/bin/perl -w
+#!/bin/sh
 
+##############################################################################
+# This is essentially a Perl program.  We exec the Perl interpreter specifying
+# this same file as the Perl program and use the -x option to cause the Perl
+# interpreter to skip down to the Perl code.  The reason we do this instead of
+# just making /usr/bin/perl the script interpreter (instead of /bin/sh) is
+# that the user may have multiple Perl interpreters and the one he wants to
+# use is properly located in the PATH.  The user's choice of Perl interpreter
+# may be crucial, such as when the user also has a PERL5LIB environment
+# variable and it selects modules that work with only a certain main
+# interpreter program.
+#
+# An alternative some people use is to have /usr/bin/env as the script
+# interpreter.  We don't do that because we think the existence and
+# compatibility of /bin/sh is more reliable.
+#
+# Note that we aren't concerned about efficiency because the user who needs
+# high efficiency can use directly the programs that this program invokes.
+#
+##############################################################################
+
+exec perl -w -x -S -- "$0" "$@"
+
+#!/usr/bin/perl
 #============================================================================
 #  This is a compatibility interface to Pamflip.
 #
diff --git a/editor/pnmnlfilt.c b/editor/pnmnlfilt.c
index bde0cd82..f55a67bd 100644
--- a/editor/pnmnlfilt.c
+++ b/editor/pnmnlfilt.c
@@ -990,7 +990,7 @@ main(int argc, char *argv[]) {
 
     FILE * ifP;
     struct cmdlineInfo cmdline;
-	bool eof;  /* We've hit the end of the input stream */
+	int eof;  /* We've hit the end of the input stream */
     unsigned int imageSeq;  /* Sequence number of image, starting from 0 */
 
     pnm_init(&argc, argv);
diff --git a/editor/pnmquant b/editor/pnmquant
index ae461a3d..93d452cd 100755
--- a/editor/pnmquant
+++ b/editor/pnmquant
@@ -1,6 +1,29 @@
-#!/usr/bin/perl -w
+#!/bin/sh
 
 ##############################################################################
+# This is essentially a Perl program.  We exec the Perl interpreter specifying
+# this same file as the Perl program and use the -x option to cause the Perl
+# interpreter to skip down to the Perl code.  The reason we do this instead of
+# just making /usr/bin/perl the script interpreter (instead of /bin/sh) is
+# that the user may have multiple Perl interpreters and the one he wants to
+# use is properly located in the PATH.  The user's choice of Perl interpreter
+# may be crucial, such as when the user also has a PERL5LIB environment
+# variable and it selects modules that work with only a certain main
+# interpreter program.
+#
+# An alternative some people use is to have /usr/bin/env as the script
+# interpreter.  We don't do that because we think the existence and
+# compatibility of /bin/sh is more reliable.
+#
+# Note that we aren't concerned about efficiency because the user who needs
+# high efficiency can use directly the programs that this program invokes.
+#
+##############################################################################
+
+exec perl -w -x -S -- "$0" "$@"
+
+#!/usr/bin/perl
+##############################################################################
 #                         pnmquant 
 ##############################################################################
 #  By Bryan Henderson, San Jose CA; December 2001.
diff --git a/editor/pnmquantall b/editor/pnmquantall
index b7bb03d7..0890383e 100755
--- a/editor/pnmquantall
+++ b/editor/pnmquantall
@@ -1,3 +1,27 @@
+#!/bin/sh
+
+##############################################################################
+# This is essentially a Perl program.  We exec the Perl interpreter specifying
+# this same file as the Perl program and use the -x option to cause the Perl
+# interpreter to skip down to the Perl code.  The reason we do this instead of
+# just making /usr/bin/perl the script interpreter (instead of /bin/sh) is
+# that the user may have multiple Perl interpreters and the one he wants to
+# use is properly located in the PATH.  The user's choice of Perl interpreter
+# may be crucial, such as when the user also has a PERL5LIB environment
+# variable and it selects modules that work with only a certain main
+# interpreter program.
+#
+# An alternative some people use is to have /usr/bin/env as the script
+# interpreter.  We don't do that because we think the existence and
+# compatibility of /bin/sh is more reliable.
+#
+# Note that we aren't concerned about efficiency because the user who needs
+# high efficiency can use directly the programs that this program invokes.
+#
+##############################################################################
+
+exec perl -w -x -S -- "$0" "$@"
+
 #!/usr/bin/perl
 ##############################################################################
 #                                  pnmquantall  
diff --git a/editor/pnmremap.c b/editor/pnmremap.c
index ec381f32..b2448cbb 100644
--- a/editor/pnmremap.c
+++ b/editor/pnmremap.c
@@ -749,7 +749,7 @@ lookupThroughHash(struct pam *            const pamP,
         } else 
             searchColormapClose(pamP, tuple, colorFinderP, colormapIndexP);
         if (*usehashP) {
-            bool fits;
+            int fits;
             pnm_addtotuplehash(pamP, colorhash, tuple, *colormapIndexP, 
                                &fits);
             if (!fits) {
@@ -1063,7 +1063,7 @@ remap(FILE *             const ifP,
    same as that of the input even though the individual pixels have different
    colors.
 -----------------------------------------------------------------------------*/
-    bool eof;
+    int eof;
     eof = FALSE;
     while (!eof) {
         struct pam inpam, outpam;
diff --git a/editor/ppmdraw.c b/editor/ppmdraw.c
index ba513581..c733ffcb 100644
--- a/editor/ppmdraw.c
+++ b/editor/ppmdraw.c
@@ -44,7 +44,7 @@ struct cmdlineInfo {
 
 
 static void
-parseCommandLine (int argc, char ** argv,
+parseCommandLine (int argc, const char ** argv,
                   struct cmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    parse program command line described in Unix standard form by argc
@@ -80,7 +80,7 @@ parseCommandLine (int argc, char ** argv,
     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, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
     
     if (!scriptSpec && !scriptfileSpec)
@@ -899,14 +899,14 @@ doOneImage(FILE *          const ifP,
 
 
 int
-main(int argc, char * argv[]) {
+main(int argc, const char * argv[]) {
 
     struct cmdlineInfo cmdline;
     FILE * ifP;
     struct script * scriptP;
-    bool eof;
+    int eof;
 
-    ppm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
diff --git a/editor/ppmfade b/editor/ppmfade
index fbc62968..027fc793 100755
--- a/editor/ppmfade
+++ b/editor/ppmfade
@@ -1,5 +1,31 @@
-#!/usr/bin/perl -w
-#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+#!/bin/sh
+
+##############################################################################
+# This is essentially a Perl program.  We exec the Perl interpreter specifying
+# this same file as the Perl program and use the -x option to cause the Perl
+# interpreter to skip down to the Perl code.  The reason we do this instead of
+# just making /usr/bin/perl the script interpreter (instead of /bin/sh) is
+# that the user may have multiple Perl interpreters and the one he wants to
+# use is properly located in the PATH.  The user's choice of Perl interpreter
+# may be crucial, such as when the user also has a PERL5LIB environment
+# variable and it selects modules that work with only a certain main
+# interpreter program.
+#
+# An alternative some people use is to have /usr/bin/env as the script
+# interpreter.  We don't do that because we think the existence and
+# compatibility of /bin/sh is more reliable.
+#
+# Note that we aren't concerned about efficiency because the user who needs
+# high efficiency can use directly the programs that this program invokes.
+#
+##############################################################################
+
+exec perl -w -x -S -- "$0" "$@"
+
+#!/usr/bin/perl
+##############################################################################
+#                                  ppmfade
+##############################################################################
 #
 #  This program creates a fade (a sequence of frames) between two images.
 #
@@ -12,7 +38,7 @@
 #  much the same thing, but handles non-Netpbm formats too, and is 
 #  implemented in a more primitive language.
 #
-#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+##############################################################################
 use strict;
 
 my $SPREAD =  1;
diff --git a/editor/ppmquant b/editor/ppmquant
index 08f4c187..57963982 100755
--- a/editor/ppmquant
+++ b/editor/ppmquant
@@ -1,4 +1,28 @@
-#!/usr/bin/perl -w
+#!/bin/sh
+
+##############################################################################
+# This is essentially a Perl program.  We exec the Perl interpreter specifying
+# this same file as the Perl program and use the -x option to cause the Perl
+# interpreter to skip down to the Perl code.  The reason we do this instead of
+# just making /usr/bin/perl the script interpreter (instead of /bin/sh) is
+# that the user may have multiple Perl interpreters and the one he wants to
+# use is properly located in the PATH.  The user's choice of Perl interpreter
+# may be crucial, such as when the user also has a PERL5LIB environment
+# variable and it selects modules that work with only a certain main
+# interpreter program.
+#
+# An alternative some people use is to have /usr/bin/env as the script
+# interpreter.  We don't do that because we think the existence and
+# compatibility of /bin/sh is more reliable.
+#
+# Note that we aren't concerned about efficiency because the user who needs
+# high efficiency can use directly the programs that this program invokes.
+#
+##############################################################################
+
+exec perl -w -x -S -- "$0" "$@"
+
+#!/usr/bin/perl
 ##############################################################################
 #  This is nothing but a compatibility interface for Pnmquant.
 #  An old program coded to call Ppmquant will continue working because
diff --git a/editor/ppmshadow b/editor/ppmshadow
index 2a32fca0..62cdf8b8 100755
--- a/editor/ppmshadow
+++ b/editor/ppmshadow
@@ -1,15 +1,40 @@
-#!/usr/bin/perl -w
+#!/bin/sh
 
-#                         P P M S H A D O W
+##############################################################################
+# This is essentially a Perl program.  We exec the Perl interpreter specifying
+# this same file as the Perl program and use the -x option to cause the Perl
+# interpreter to skip down to the Perl code.  The reason we do this instead of
+# just making /usr/bin/perl the script interpreter (instead of /bin/sh) is
+# that the user may have multiple Perl interpreters and the one he wants to
+# use is properly located in the PATH.  The user's choice of Perl interpreter
+# may be crucial, such as when the user also has a PERL5LIB environment
+# variable and it selects modules that work with only a certain main
+# interpreter program.
+#
+# An alternative some people use is to have /usr/bin/env as the script
+# interpreter.  We don't do that because we think the existence and
+# compatibility of /bin/sh is more reliable.
+#
+# Note that we aren't concerned about efficiency because the user who needs
+# high efficiency can use directly the programs that this program invokes.
+#
+##############################################################################
+
+exec perl -w -x -S -- "$0" "$@"
 
+#!/usr/bin/perl
+##############################################################################
+#                              ppmshadow
+##############################################################################
+#
 #            by John Walker  --  http://www.fourmilab.ch/
 #                          version = 1.2;
 #   --> with minor changes by Bryan Henderson to adapt to Netbpm.  
 #   See above web site for the real John Walker work, named pnmshadow.
-
+#
 #   Bryan Henderson later made some major style changes (use strict, etc) and
 #   eliminated most use of shells.  See Netbpm HISTORY file.
-
+#
 #   Pnmshadow is a brutal sledgehammer implemented in Perl which
 #   adds attractive shadows to images, as often seen in titles
 #   of World-Wide Web pages.  This program does not actually
@@ -20,7 +45,7 @@
 #
 #               This program is in the public domain.
 #
-#
+##############################################################################
 
 use strict;
 require 5.0;
diff --git a/editor/specialty/ppmntsc.c b/editor/specialty/ppmntsc.c
index 2585662f..a721b891 100644
--- a/editor/specialty/ppmntsc.c
+++ b/editor/specialty/ppmntsc.c
@@ -51,9 +51,6 @@
 #include "mallocvar.h"
 #include "shhopt.h"
 
-#define TRUE 1
-#define FALSE 0
-
 enum legalize {RAISE_SAT, LOWER_SAT, ALREADY_LEGAL};
    /* The actions that make a legal pixel */
 
@@ -70,6 +67,61 @@ struct cmdlineInfo {
 
 
 
+static void
+parseCommandLine(int argc, const char ** argv,
+                 struct cmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Note that many of the strings that this function returns in the
+   *cmdlineP structure are actually in the supplied argv array.  And
+   sometimes, one of these strings is actually just a suffix of an entry
+   in argv!
+-----------------------------------------------------------------------------*/
+    optStruct3 opt;
+    optEntry *option_def;
+        /* Instructions to OptParseOptions on how to parse our options.
+         */
+    unsigned int option_def_index;
+    unsigned int legalonly, illegalonly, correctedonly;
+
+    MALLOCARRAY(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3('v', "verbose",        OPT_FLAG, NULL,  &cmdlineP->verbose,  0);
+    OPTENT3('V', "debug",          OPT_FLAG, NULL,  &cmdlineP->debug,    0);
+    OPTENT3('p', "pal",            OPT_FLAG, NULL,  &cmdlineP->pal,      0);
+    OPTENT3('l', "legalonly",      OPT_FLAG, NULL,  &legalonly,           0);
+    OPTENT3('i', "illegalonly",    OPT_FLAG, NULL,  &illegalonly,         0);
+    OPTENT3('c', "correctedonly",  OPT_FLAG, NULL,  &correctedonly,       0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = true;
+    opt.allowNegNum = false;
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+
+    if (argc - 1 == 0)
+        cmdlineP->inputFilename = "-";  /* he wants stdin */
+    else if (argc - 1 == 1)
+        cmdlineP->inputFilename = argv[1];
+    else 
+        pm_error("Too many arguments.  The only arguments accepted "
+                 "are the mask color and optional input file specification");
+
+    if (legalonly + illegalonly + correctedonly > 1)
+        pm_error("--legalonly, --illegalonly, and --correctedonly are "
+                 "conflicting options.  Specify at most one of these.");
+        
+    if (legalonly) 
+        cmdlineP->output = LEGAL_ONLY;
+    else if (illegalonly) 
+        cmdlineP->output = ILLEGAL_ONLY;
+    else if (correctedonly) 
+        cmdlineP->output = CORRECTED_ONLY;
+    else 
+        cmdlineP->output = ALL;
+}
+
+
 
 static void 
 rgbtoyiq(const int r, const int g, const int b, 
@@ -118,39 +170,39 @@ yuvtorgb(const double y, const double u, const double v,
 
 
 static void
-make_legal_yiq(const double y, const double i, const double q, 
-               double * const y_new_p, 
-               double * const i_new_p, 
-               double * const q_new_p,
-               enum legalize * const action_p
-    ) {
+makeLegalYiq(double          const y,
+             double          const i,
+             double          const q, 
+             double *        const yNewP, 
+             double *        const iNewP, 
+             double *        const qNewP,
+             enum legalize * const actionP) {
     
-    double sat_old, sat_new;
+    double satOld, satNew;
     /*
      * I and Q are legs of a right triangle.  Saturation is the hypotenuse.
      */
-    sat_old = sqrt(i*i + q*q);
-    if (y+sat_old > 1.0) {
-        const double diff = 0.5*((y+sat_old) - 1.0);
-        *y_new_p = y - diff;
-        sat_new = 1.0 - *y_new_p;
-        *i_new_p = i*(sat_new/sat_old);
-        *q_new_p = q*(sat_new/sat_old);
-        *action_p = LOWER_SAT;
-    } else if (y-sat_old <= -0.251) {
-        const double diff = 0.5*((sat_old-y) - 0.251);
-        *y_new_p = y + diff;
-        sat_new = 0.250 + *y_new_p;
-        *i_new_p = i*(sat_new/sat_old);
-        *q_new_p = q*(sat_new/sat_old);
-        *action_p = RAISE_SAT;
+    satOld = sqrt(SQR(i) + SQR(q));
+    if (y+satOld > 1.0) {
+        const double diff = 0.5*((y + satOld) - 1.0);
+        *yNewP = y - diff;
+        satNew = 1.0 - *yNewP;
+        *iNewP = i * (satNew/satOld);
+        *qNewP = q * (satNew/satOld);
+        *actionP = LOWER_SAT;
+    } else if (y - satOld <= -0.251) {
+        const double diff = 0.5*((satOld - y) - 0.251);
+        *yNewP = y + diff;
+        satNew = 0.250 + *yNewP;
+        *iNewP = i * (satNew/satOld);
+        *qNewP = q * (satNew/satOld);
+        *actionP = RAISE_SAT;
     } else {
-        *y_new_p = y;
-        *i_new_p = i;
-        *q_new_p = q;
-        *action_p = ALREADY_LEGAL;
+        *yNewP = y;
+        *iNewP = i;
+        *qNewP = q;
+        *actionP = ALREADY_LEGAL;
     }
-    return;
 }
 
 
@@ -206,7 +258,7 @@ make_legal_yiq_i(const int r_in, const int g_in, const int b_in,
      * Convert to YIQ and compute the new saturation.
      */
     rgbtoyiq(r_in, g_in, b_in, &y, &i, &q);
-    make_legal_yiq(y, i, q, &y_new, &i_new, &q_new, action_p);
+    makeLegalYiq(y, i, q, &y_new, &i_new, &q_new, action_p);
     if (*action_p != ALREADY_LEGAL)
         /*
          * Given the new I and Q, compute new RGB values.
@@ -295,204 +347,155 @@ make_legal_yuv_b(const pixel input,
 
 
 static void 
-report_mapping(const pixel old_pixel, const pixel new_pixel) {
+reportMapping(pixel const oldPixel,
+              pixel const newPixel) {
 /*----------------------------------------------------------------------------
-  Assuming old_pixel and new_pixel are input and output pixels,
+  Assuming oldPixel and newPixel are input and output pixels,
   tell the user that we changed a pixel to make it legal, if in fact we
   did and it isn't the same change that we just reported.
 -----------------------------------------------------------------------------*/
-    static pixel last_changed_pixel;
-    static int first_time = TRUE;
-
-    if (!PPM_EQUAL(old_pixel, new_pixel) && 
-        (first_time || PPM_EQUAL(old_pixel, last_changed_pixel))) {
-        pm_message("Mapping %d %d %d -> %d %d %d\n",
-                   PPM_GETR(old_pixel),
-                   PPM_GETG(old_pixel),
-                   PPM_GETB(old_pixel),
-                   PPM_GETR(new_pixel),
-                   PPM_GETG(new_pixel),
-                   PPM_GETB(new_pixel)
+    static pixel lastChangedPixel;
+    static bool firstTime = true;
+
+    if (!PPM_EQUAL(oldPixel, newPixel) && 
+        (firstTime || PPM_EQUAL(oldPixel, lastChangedPixel))) {
+        pm_message("Mapping %u %u %u -> %u %u %u\n",
+                   PPM_GETR(oldPixel),
+                   PPM_GETG(oldPixel),
+                   PPM_GETB(oldPixel),
+                   PPM_GETR(newPixel),
+                   PPM_GETG(newPixel),
+                   PPM_GETB(newPixel)
             );
 
-        last_changed_pixel = old_pixel;
-        first_time = FALSE;
+        lastChangedPixel = oldPixel;
+        firstTime = false;
     }    
 }
 
 
 
 static void
-convert_one_image(FILE * const ifp, struct cmdlineInfo const cmdline, 
-                  bool * const eofP, 
-                  int * const hicountP, int * const locountP) {
+convertOneImage(FILE *             const ifP,
+                struct cmdlineInfo const cmdline, 
+                unsigned int *     const hiCountP,
+                unsigned int *     const loCountP) {
 
     /* Parameters of input image: */
     int rows, cols;
     pixval maxval;
     int format;
 
-    ppm_readppminit(ifp, &cols, &rows, &maxval, &format);
-    ppm_writeppminit(stdout, cols, rows, maxval, FALSE);
+    ppm_readppminit(ifP, &cols, &rows, &maxval, &format);
+    ppm_writeppminit(stdout, cols, rows, maxval, 0);
     {
-        pixel* const input_row = ppm_allocrow(cols);
-        pixel* const output_row = ppm_allocrow(cols);
-        pixel last_illegal_pixel;
-        /* Value of the illegal pixel we most recently processed */
+        pixel * const inputRow = ppm_allocrow(cols);
+        pixel * const outputRow = ppm_allocrow(cols);
+
+        pixel lastIllegalPixel;
+            /* Value of the illegal pixel we most recently processed */
         pixel black;
-        /* A constant - black pixel */
+            /* A constant - black pixel */
 
         PPM_ASSIGN(black, 0, 0, 0);
 
-        PPM_ASSIGN(last_illegal_pixel, 0, 0, 0);  /* initial value */
+        PPM_ASSIGN(lastIllegalPixel, 0, 0, 0);  /* initial value */
         {
-            int row;
+            unsigned int row;
 
-            *hicountP = 0; *locountP = 0;  /* initial values */
+            *hiCountP = 0; *loCountP = 0;  /* initial values */
 
             for (row = 0; row < rows; ++row) {
-                int col;
-                ppm_readppmrow(ifp, input_row, cols, maxval, format);
+                unsigned int col;
+                ppm_readppmrow(ifP, inputRow, cols, maxval, format);
                 for (col = 0; col < cols; ++col) {
                     pixel corrected;
-                    /* Corrected or would-be corrected value for pixel */
+                        /* Corrected or would-be corrected value for pixel */
                     enum legalize action;
-                    /* What action was used to make pixel legal */
+                        /* What action was used to make pixel legal */
                     if (cmdline.pal)
-                        make_legal_yuv_b(input_row[col],
+                        make_legal_yuv_b(inputRow[col],
                                          &corrected,
                                          &action);
                     else
-                        make_legal_yiq_b(input_row[col],
+                        make_legal_yiq_b(inputRow[col],
                                          &corrected,
                                          &action);
                         
                     if (action == LOWER_SAT) 
-                        (*hicountP)++;
+                        ++*hiCountP;
                     if (action == RAISE_SAT)
-                        (*locountP)++;
-                    if (cmdline.debug) report_mapping(input_row[col],
-                                                      corrected);
+                        ++*loCountP;
+                    if (cmdline.debug)
+                        reportMapping(inputRow[col], corrected);
                     switch (cmdline.output) {
                     case ALL:
-                        output_row[col] = corrected;
+                        outputRow[col] = corrected;
                         break;
                     case LEGAL_ONLY:
-                        output_row[col] = (action == ALREADY_LEGAL) ?
-                            input_row[col] : black;
+                        outputRow[col] = (action == ALREADY_LEGAL) ?
+                            inputRow[col] : black;
                         break;
                     case ILLEGAL_ONLY:
-                        output_row[col] = (action != ALREADY_LEGAL) ?
-                            input_row[col] : black;
+                        outputRow[col] = (action != ALREADY_LEGAL) ?
+                            inputRow[col] : black;
                         break;
                     case CORRECTED_ONLY:
-                        output_row[col] = (action != ALREADY_LEGAL) ?
+                        outputRow[col] = (action != ALREADY_LEGAL) ?
                             corrected : black;
                         break;
                     }
                 }
-                ppm_writeppmrow(stdout, output_row, cols, maxval, FALSE);
+                ppm_writeppmrow(stdout, outputRow, cols, maxval, 0);
             }
         }
-        ppm_freerow(output_row);
-        ppm_freerow(input_row);
+        ppm_freerow(outputRow);
+        ppm_freerow(inputRow);
     }
 }
 
 
-static void
-parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
-/*----------------------------------------------------------------------------
-   Note that many of the strings that this function returns in the
-   *cmdlineP structure are actually in the supplied argv array.  And
-   sometimes, one of these strings is actually just a suffix of an entry
-   in argv!
------------------------------------------------------------------------------*/
-    optStruct3 opt;
-    optEntry *option_def;
-        /* Instructions to OptParseOptions on how to parse our options.
-         */
-    unsigned int option_def_index;
-    unsigned int legalonly, illegalonly, correctedonly;
-
-    MALLOCARRAY(option_def, 100);
-
-    option_def_index = 0;   /* incremented by OPTENTRY */
-    OPTENT3('v', "verbose",        OPT_FLAG, NULL,  &cmdlineP->verbose,  0);
-    OPTENT3('V', "debug",          OPT_FLAG, NULL,  &cmdlineP->debug,    0);
-    OPTENT3('p', "pal",            OPT_FLAG, NULL,  &cmdlineP->pal,      0);
-    OPTENT3('l', "legalonly",      OPT_FLAG, NULL,  &legalonly,           0);
-    OPTENT3('i', "illegalonly",    OPT_FLAG, NULL,  &illegalonly,         0);
-    OPTENT3('c', "correctedonly",  OPT_FLAG, NULL,  &correctedonly,       0);
-
-    opt.opt_table = option_def;
-    opt.short_allowed = TRUE;
-    opt.allowNegNum = FALSE;
-
-    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
-
-    if (argc - 1 == 0)
-        cmdlineP->inputFilename = "-";  /* he wants stdin */
-    else if (argc - 1 == 1)
-        cmdlineP->inputFilename = argv[1];
-    else 
-        pm_error("Too many arguments.  The only arguments accepted "
-                 "are the mask color and optional input file specification");
-
-    if (legalonly + illegalonly + correctedonly > 1)
-        pm_error("--legalonly, --illegalonly, and --correctedonly are "
-                 "conflicting options.  Specify at most one of these.");
-        
-    if (legalonly) 
-        cmdlineP->output = LEGAL_ONLY;
-    else if (illegalonly) 
-        cmdlineP->output = ILLEGAL_ONLY;
-    else if (correctedonly) 
-        cmdlineP->output = CORRECTED_ONLY;
-    else 
-        cmdlineP->output = ALL;
-}
-
-
 
 int
-main(int argc, char **argv) {
+main(int argc, const char **argv) {
     
     struct cmdlineInfo cmdline;
     FILE * ifP;
-    int total_hicount, total_locount;
-    int image_count;
+    unsigned int totalHiCount, totalLoCount;
+    unsigned int imageCount;
 
-    bool eof;
+    int eof;
 
-    ppm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
     ifP = pm_openr(cmdline.inputFilename);
+    
+    imageCount = 0;    /* initial value */
+    totalHiCount = 0;  /* initial value */
+    totalLoCount = 0;  /* initial value */
 
-    image_count = 0;    /* initial value */
-    total_hicount = 0;  /* initial value */
-    total_locount = 0;  /* initial value */
-
-    eof = FALSE;
+    eof = false;
     while (!eof) {
-        int hicount, locount;
-        convert_one_image(ifP, cmdline, &eof, &hicount, &locount);
-        image_count++;
-        total_hicount += hicount;
-        total_locount += locount;
+        unsigned int hiCount, loCount;
+
+        convertOneImage(ifP, cmdline, &hiCount, &loCount);
+
+        ++imageCount;
+        totalHiCount += hiCount;
+        totalLoCount += loCount;
+
         ppm_nextimage(ifP, &eof);
     }
 
 
 	if (cmdline.verbose) {
-        pm_message("%d images processed.", image_count);
-        pm_message("%d pixels were above the saturation limit.", 
-                   total_hicount);
-        pm_message("%d pixels were below the saturation limit.", 
-                   total_locount);
+        pm_message("%u images processed.", imageCount);
+        pm_message("%u pixels were above the saturation limit.", 
+                   totalHiCount);
+        pm_message("%u pixels were below the saturation limit.", 
+                   totalLoCount);
     }
     
     pm_close(ifP);
diff --git a/generator/pamgauss.c b/generator/pamgauss.c
index b6afdb7e..0e1661e6 100644
--- a/generator/pamgauss.c
+++ b/generator/pamgauss.c
@@ -9,8 +9,6 @@
 #include "mallocvar.h"
 #include "pam.h"
 
-#define true (1)
-#define false (0)
 
 
 struct cmdlineInfo {
diff --git a/generator/pamgradient.c b/generator/pamgradient.c
index 6546e334..57e78288 100644
--- a/generator/pamgradient.c
+++ b/generator/pamgradient.c
@@ -18,7 +18,7 @@ struct cmdlineInfo {
 };
 
 static void
-parseCommandLine(int argc, char **argv,
+parseCommandLine(int argc, const char **argv,
                  struct cmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
   Convert program invocation arguments (argc,argv) into a format the 
@@ -45,7 +45,7 @@ parseCommandLine(int argc, char **argv,
     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, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (!maxvalSpec)
@@ -153,7 +153,7 @@ createEdge(const struct pam * const pamP,
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char *argv[]) {
 
     struct cmdlineInfo cmdline;
     struct pam pam;
@@ -162,7 +162,7 @@ main(int argc, char *argv[]) {
     tuple * rightEdge;
     unsigned int row;
     
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
diff --git a/generator/pamseq.c b/generator/pamseq.c
index b1ed0c79..1af5252a 100644
--- a/generator/pamseq.c
+++ b/generator/pamseq.c
@@ -7,8 +7,6 @@
 #include "pam.h"
 #include "shhopt.h"
 
-#define true (1)
-#define false (0)
 
 
 struct cmdlineInfo {
diff --git a/generator/pgmnoise.c b/generator/pgmnoise.c
index bf73ea48..442edc59 100644
--- a/generator/pgmnoise.c
+++ b/generator/pgmnoise.c
@@ -7,6 +7,8 @@
 #include "mallocvar.h"
 #include "shhopt.h"
 #include "pgm.h"
+#include <assert.h>
+
 
 
 struct cmdlineInfo {
@@ -15,13 +17,13 @@ struct cmdlineInfo {
     */
     unsigned int width;
     unsigned int height;
+    unsigned int maxval;
     unsigned int randomseed;
     unsigned int randomseedSpec;
 };
 
 
 
-
 static void
 parseCommandLine(int argc, const char ** const argv,
                  struct cmdlineInfo * const cmdlineP) {
@@ -34,12 +36,15 @@ parseCommandLine(int argc, const char ** const argv,
          */
     optStruct3 opt;
     unsigned int option_def_index;
+    unsigned int maxvalSpec;
 
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
     OPTENT3(0,   "randomseed",   OPT_UINT,    &cmdlineP->randomseed,
             &cmdlineP->randomseedSpec,      0);
+    OPTENT3(0,   "maxval",       OPT_UINT,    &cmdlineP->maxval,
+            &maxvalSpec,                    0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
@@ -47,6 +52,16 @@ parseCommandLine(int argc, const char ** const argv,
 
     pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+    free(option_def);
+
+    if (maxvalSpec) {
+        if (cmdlineP->maxval > PGM_OVERALLMAXVAL)
+            pm_error("Maxval too large: %u.  Maximu is %u", 
+                     cmdlineP->maxval, PGM_OVERALLMAXVAL);
+        else if (cmdlineP->maxval == 0)
+            pm_error("Maxval must not be zero");
+    } else
+        cmdlineP->maxval = PGM_MAXMAXVAL;
 
     if (argc-1 != 2)
         pm_error("Wrong number of arguments: %u.  "
@@ -66,30 +81,95 @@ parseCommandLine(int argc, const char ** const argv,
         else
             cmdlineP->height = height;
     }
-    free(option_def);
 }
 
 
 
+static unsigned int
+randPool(unsigned int const digits) {
+/*----------------------------------------------------------------------------
+  Draw 'digits' bits from pool of random bits.  If the number of random bits
+  in pool is insufficient, call rand() and add 31 bits to it.
+  
+  'digits' must be at most 16.
+
+  We assume that each call to rand() generates 31 bits, or RAND_MAX ==
+  2147483647.
+  
+  The underlying logic is flexible and endian-free.  The above conditions
+  can be relaxed.
+-----------------------------------------------------------------------------*/
+    static unsigned long int hold=0;  /* entropy pool */
+    static unsigned int len=0;        /* number of valid bits in pool */
+
+    unsigned int const mask = (1 << digits) - 1;
+
+    unsigned int retval;
+
+    assert(RAND_MAX == 2147483647 && digits <= 16);
+
+    retval = hold;  /* initial value */
+
+    if (len > digits) { /* Enough bits in hold to satisfy request */
+        hold >>= digits;
+        len   -= digits;
+    } else {              /* Load another 31 bits into hold */
+        hold    = rand(); 
+        retval |= (hold << len);
+        hold >>=  (digits - len);
+        len = 31 - digits + len;
+    }
+    return (retval & mask);
+}
+
+
 
 static void
-pgmnoise(FILE * const ofP,
+pgmnoise(FILE *       const ofP,
          unsigned int const cols,
          unsigned int const rows,
          gray         const maxval) {
 
+    bool const usingPool = !(RAND_MAX==2147483647 && (maxval & (maxval+1)));
+    unsigned int const bitLen = pm_maxvaltobits(maxval);
+
     unsigned int row;
     gray * destrow;
 
+    /* If maxval is 2^n-1, we draw exactly n bits from the pool.
+       Otherwise call rand() and determine gray value by modulo.
+
+       In the latter case, there is a miniscule skew toward 0 (=black)
+       because smaller numbers are produced more frequently by modulo.
+       Thus we employ the pool method only when it is certain that no
+       skew will ensue.
+
+       To illustrate the point, consider converting the outcome of one
+       roll of a fair, six-sided die to 5 values (0 to 4) by N % 5.  The
+       probability for values 1, 2, 3, 4 are 1/6, but 0 alone is 2/6.
+       Average is 10/6 or 1.6667, compared to 2.0 from an ideal
+       generator which produces exactly 5 values.  With two dice
+       average improves to 70/36 or 1.9444.
+
+       The more (distinct) dice we roll, or the more binary digits we
+       draw, the smaller the skew.
+    */
+
     destrow = pgm_allocrow(cols);
 
     pgm_writepgminit(ofP, cols, rows, maxval, 0);
 
     for (row = 0; row < rows; ++row) {
-        unsigned int col;
-        for (col = 0; col < cols; ++col)
-            destrow[col] = rand() % (maxval + 1);
-
+        if (usingPool) {
+            unsigned int col;
+            for (col = 0; col < cols; ++col)
+                destrow[col] = randPool(bitLen);
+        } 
+        else { 
+            unsigned int col;
+            for (col = 0; col < cols; ++col)
+                destrow[col] = rand() % (maxval + 1); 
+        }
         pgm_writepgmrow(ofP, destrow, cols, maxval, 0);
     }
 
@@ -110,8 +190,7 @@ main(int          argc,
 
     srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed());
 
-    pgmnoise(stdout, cmdline.width, cmdline.height, PGM_MAXMAXVAL);
+    pgmnoise(stdout, cmdline.width, cmdline.height, cmdline.maxval);
 
     return 0;
 }
-
diff --git a/generator/ppmcie.c b/generator/ppmcie.c
index 69af5732..717ed13b 100644
--- a/generator/ppmcie.c
+++ b/generator/ppmcie.c
@@ -35,10 +35,8 @@
 #include "nstring.h"
 
 #define CLAMP(v, l, h)  ((v) < (l) ? (l) : (v) > (h) ? (h) : (v))
-#define TRUE    1
-#define FALSE   0
 
-#define Maxval  255                   /* Maxval to use in generated pixmaps */
+pixval const cieMaxval = 255;  /* Maxval to use in generated pixmaps */
 
 /* A  color  system is defined by the CIE x and y  coordinates of its
    three primary illuminants and the x and y coordinates of the  white
@@ -522,12 +520,12 @@ makeAllBlack(pixel **     const pixels,
 
 static void
 drawTongueOutline(pixel ** const pixels,
-                  int    const pixcols,
-                  int    const pixrows,
-                  pixval const maxval,
-                  bool   const upvp,
-                  int    const xBias,
-                  int    const yBias) {
+                  int      const pixcols,
+                  int      const pixrows,
+                  pixval   const maxval,
+                  bool     const upvp,
+                  int      const xBias,
+                  int      const yBias) {
 
     int const pxcols = pixcols - xBias;
     int const pxrows = pixrows - yBias;
@@ -546,7 +544,7 @@ drawTongueOutline(pixel ** const pixels,
                                        &icx, &icy);
         
         if (wavelength > 380)
-            ppmd_line(pixels, pixcols, pixrows, Maxval,
+            ppmd_line(pixels, pixcols, pixrows, maxval,
                       B(lx, ly), B(icx, icy),
                       PPMD_NULLDRAWPROC, (char *) &rgbcolor);
         else {
@@ -585,12 +583,12 @@ findTongue(pixel ** const pixels,
          ++i);
 
     if (i >= pxcols)
-        *presentP = FALSE;
+        *presentP = false;
     else {
         int j;
         int const leftEdge = i;
 
-        *presentP = TRUE;
+        *presentP = true;
         
         for (j = pxcols - 1;
              j >= leftEdge && PPM_GETR(Bixels(row, j)) == 0;
@@ -652,16 +650,16 @@ fillInTongue(pixel **                   const pixels,
 
                 xyz_to_rgb(cs, cx, cy, cz, &jr, &jg, &jb);
 
-                mx = Maxval;
+                mx = maxval;
         
                 /* Check whether the requested color  is  within  the
                    gamut  achievable with the given color system.  If
                    not, draw it in a reduced  intensity,  interpolated
                    by desaturation to the closest within-gamut color. */
         
-                if (constrain_rgb(&jr, &jg, &jb)) {
-                    mx = highlightGamut ? Maxval : ((Maxval + 1) * 3) / 4;
-                }
+                if (constrain_rgb(&jr, &jg, &jb))
+                    mx = highlightGamut ? maxval : ((maxval + 1) * 3) / 4;
+
                 /* Scale to max(rgb) = 1. */
                 jmax = MAX(jr, MAX(jg, jb));
                 if (jmax > 0) {
@@ -959,14 +957,14 @@ plotBlackBodyCurve(pixel **                   const pixels,
         }
 
         if (t > 1000) {
-            ppmd_line(pixels, pixcols, pixrows, Maxval,
+            ppmd_line(pixels, pixcols, pixrows, maxval,
                       B(lx, ly), B(xb, yb), PPMD_NULLDRAWPROC,
                       (char *) &rgbcolor);
 
             /* Draw tick mark every 1000 kelvins */
 
             if ((((int) t) % 1000) == 0) {
-                ppmd_line(pixels, pixcols, pixrows, Maxval,
+                ppmd_line(pixels, pixcols, pixrows, maxval,
                           B(lx, ly - Sz(2)), B(lx, ly + Sz(2)),
                           PPMD_NULLDRAWPROC, (char *) &rgbcolor);
 
@@ -978,7 +976,7 @@ plotBlackBodyCurve(pixel **                   const pixels,
                     char bb[20];
 
                     sprintf(bb, "%g", t);
-                    ppmd_text(pixels, pixcols, pixrows, Maxval,
+                    ppmd_text(pixels, pixcols, pixrows, maxval,
                               B(lx - Sz(12), ly - Sz(4)), Sz(6), 0, bb,
                               PPMD_NULLDRAWPROC, (char *) &rgbcolor);
                 }
@@ -1057,7 +1055,7 @@ plotMonochromeWavelengths(
             PPM_ASSIGN(rgbcolor, maxval, maxval, maxval);
             tx = icx + ((x < 520) ? Sz(-2) : ((x >= 535) ? Sz(2) : 0));
             ty = icy + ((x < 520) ? 0 : ((x >= 535) ? Sz(-1) : Sz(-2))); 
-            ppmd_line(pixels, pixcols, pixrows, Maxval,
+            ppmd_line(pixels, pixcols, pixrows, maxval,
                       B(icx, icy), B(tx, ty),
                       PPMD_NULLDRAWPROC, (char *) &rgbcolor);
 
@@ -1089,13 +1087,13 @@ plotMonochromeWavelengths(
             }
             /* gamma correct from linear rgb to nonlinear rgb. */
             gamma_correct_rgb(cs, &jr, &jg, &jb);
-            r = Maxval * jr;
-            g = Maxval * jg;
-            b = Maxval * jb;
+            r = maxval * jr;
+            g = maxval * jg;
+            b = maxval * jb;
             PPM_ASSIGN(rgbcolor, (pixval) r, (pixval) g, (pixval) b);
 
             sprintf(wl, "%d", x);
-            ppmd_text(pixels, pixcols, pixrows, Maxval,
+            ppmd_text(pixels, pixcols, pixrows, maxval,
                       B(icx + bx, icy + by), Sz(6), 0, wl,
                       PPMD_NULLDRAWPROC, (char *) &rgbcolor);
         }
@@ -1127,7 +1125,7 @@ writeLabel(pixel **                   const pixels,
                 cs->xBlue, cs->yBlue, cs->xWhite, cs->yWhite);
     sysdesc[sizeof(sysdesc)-1] = '\0';  /* for robustness */
 
-    ppmd_text(pixels, pixcols, pixrows, Maxval,
+    ppmd_text(pixels, pixcols, pixrows, maxval,
               pixcols / 3, Sz(24), Sz(12), 0, sysdesc,
               PPMD_NULLDRAWPROC, (char *) &rgbcolor);
 }
@@ -1135,8 +1133,8 @@ writeLabel(pixel **                   const pixels,
 
 
 int
-main(int argc,
-     char * argv[]) {
+main(int          argc,
+     const char * argv[]) {
 
     int argn;
     const char * const usage = "[-[no]black] [-[no]wpoint] [-[no]label] [-no[axes]] [-full]\n\
@@ -1146,24 +1144,24 @@ main(int argc,
 [-size <s>] [-xsize|-width <x>] [-ysize|-height <y>]";
     const struct colorSystem *cs;
 
-    int widspec = FALSE, hgtspec = FALSE;
+    bool widspec = false, hgtspec = false;
     unsigned int xBias, yBias;
-    int upvp = FALSE;             /* xy or u'v' color coordinates? */
-    int showWhite = TRUE;             /* Show white point ? */
-    int showBlack = TRUE;             /* Show black body curve ? */
-    int fullChart = FALSE;            /* Fill entire tongue ? */
-    int showLabel = TRUE;             /* Show labels ? */
-    int showAxes = TRUE;              /* Plot axes ? */
-
-    ppm_init(&argc, argv);
+    bool upvp = false;             /* xy or u'v' color coordinates? */
+    bool showWhite = true;         /* Show white point ? */
+    bool showBlack = true;         /* Show black body curve ? */
+    bool fullChart = false;        /* Fill entire tongue ? */
+    bool showLabel = true;         /* Show labels ? */
+    bool showAxes = true;          /* Plot axes ? */
+
+    pm_proginit(&argc, argv);
     argn = 1;
 
     cs = &Rec709system;  /* default */
     while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
         if (pm_keymatch(argv[argn], "-xy", 2)) {
-            upvp = FALSE;
+            upvp = false;
         } else if (pm_keymatch(argv[argn], "-upvp", 1)) {
-            upvp = TRUE;
+            upvp = true;
         } else if (pm_keymatch(argv[argn], "-xsize", 1) ||
                    pm_keymatch(argv[argn], "-width", 2)) {
             if (widspec) {
@@ -1172,7 +1170,7 @@ main(int argc,
             argn++;
             if ((argn == argc) || (sscanf(argv[argn], "%d", &sxsize) != 1))
                 pm_usage(usage);
-            widspec = TRUE;
+            widspec = true;
         } else if (pm_keymatch(argv[argn], "-ysize", 1) ||
                    pm_keymatch(argv[argn], "-height", 2)) {
             if (hgtspec) {
@@ -1181,7 +1179,7 @@ main(int argc,
             argn++;
             if ((argn == argc) || (sscanf(argv[argn], "%d", &sysize) != 1))
                 pm_usage(usage);
-            hgtspec = TRUE;
+            hgtspec = true;
         } else if (pm_keymatch(argv[argn], "-size", 2)) {
             if (hgtspec || widspec) {
                 pm_error("already specified a size/height/ysize");
@@ -1190,7 +1188,7 @@ main(int argc,
             if ((argn == argc) || (sscanf(argv[argn], "%d", &sysize) != 1))
                 pm_usage(usage);
             sxsize = sysize;
-            hgtspec = widspec = TRUE;
+            hgtspec = widspec = true;
         } else if (pm_keymatch(argv[argn], "-rec709", 1)) {
             cs = &Rec709system;
         } else if (pm_keymatch(argv[argn], "-ntsc", 1)) {
@@ -1204,23 +1202,23 @@ main(int argc,
         } else if (pm_keymatch(argv[argn], "-cie", 1)) {
             cs = &CIEsystem;                 
         } else if (pm_keymatch(argv[argn], "-black", 3)) {
-            showBlack = TRUE;         /* Show black body curve */
+            showBlack = true;         /* Show black body curve */
         } else if (pm_keymatch(argv[argn], "-wpoint", 2)) {
-            showWhite = TRUE;         /* Show white point of color system */
+            showWhite = true;         /* Show white point of color system */
         } else if (pm_keymatch(argv[argn], "-noblack", 3)) {
-            showBlack = FALSE;        /* Don't show black body curve */
+            showBlack = false;        /* Don't show black body curve */
         } else if (pm_keymatch(argv[argn], "-nowpoint", 3)) {
-            showWhite = FALSE;        /* Don't show white point of system */
+            showWhite = false;        /* Don't show white point of system */
         } else if (pm_keymatch(argv[argn], "-label", 1)) {
-            showLabel = TRUE;         /* Show labels. */
+            showLabel = true;         /* Show labels. */
         } else if (pm_keymatch(argv[argn], "-nolabel", 3)) {
-            showLabel = FALSE;        /* Don't show labels */
+            showLabel = false;        /* Don't show labels */
         } else if (pm_keymatch(argv[argn], "-axes", 1)) {
-            showAxes = TRUE;          /* Show axes. */
+            showAxes = true;          /* Show axes. */
         } else if (pm_keymatch(argv[argn], "-noaxes", 3)) {
-            showAxes = FALSE;         /* Don't show axes */
+            showAxes = false;         /* Don't show axes */
         } else if (pm_keymatch(argv[argn], "-full", 1)) {
-            fullChart = TRUE;         /* Fill whole tongue full-intensity */
+            fullChart = true;         /* Fill whole tongue full-intensity */
         } else if (pm_keymatch(argv[argn], "-gamma", 2)) {
             cs = &Customsystem;
             argn++;
@@ -1289,32 +1287,32 @@ main(int argc,
 
     makeAllBlack(pixels, pixcols, pixrows);
 
-    drawTongueOutline(pixels, pixcols, pixrows, Maxval, upvp, xBias, yBias);
+    drawTongueOutline(pixels, pixcols, pixrows, cieMaxval, upvp, xBias, yBias);
 
-    fillInTongue(pixels, pixcols, pixrows, Maxval, cs, upvp, xBias, yBias,
+    fillInTongue(pixels, pixcols, pixrows, cieMaxval, cs, upvp, xBias, yBias,
                  fullChart);
 
     if (showAxes)
-        drawAxes(pixels, pixcols, pixrows, Maxval, upvp, xBias, yBias);
+        drawAxes(pixels, pixcols, pixrows, cieMaxval, upvp, xBias, yBias);
 
     if (showWhite)
-        plotWhitePoint(pixels, pixcols, pixrows, Maxval,
+        plotWhitePoint(pixels, pixcols, pixrows, cieMaxval,
                        cs, upvp, xBias, yBias);
 
     if (showBlack)
-        plotBlackBodyCurve(pixels, pixcols, pixrows, Maxval,
+        plotBlackBodyCurve(pixels, pixcols, pixrows, cieMaxval,
                            upvp, xBias, yBias);
 
     /* Plot wavelengths around periphery of the tongue. */
 
     if (showAxes)
-        plotMonochromeWavelengths(pixels, pixcols, pixrows, Maxval,
+        plotMonochromeWavelengths(pixels, pixcols, pixrows, cieMaxval,
                                   cs, upvp, xBias, yBias);
 
     if (showLabel)
-        writeLabel(pixels, pixcols, pixrows, Maxval, cs);
+        writeLabel(pixels, pixcols, pixrows, cieMaxval, cs);
 
-    ppm_writeppm(stdout, pixels, pixcols, pixrows, Maxval, FALSE);
+    ppm_writeppm(stdout, pixels, pixcols, pixrows, cieMaxval, 0);
 
     return 0;
 }
diff --git a/generator/ppmforge.c b/generator/ppmforge.c
index 189e930c..8ea86429 100644
--- a/generator/ppmforge.c
+++ b/generator/ppmforge.c
@@ -39,6 +39,7 @@
 #include "pm_c_util.h"
 #include "ppm.h"
 #include "mallocvar.h"
+#include "shhopt.h"
 
 static double const hugeVal = 1e50;
 
@@ -74,12 +75,6 @@ static double arand, gaussadd, gaussfac; /* Gaussian random parameters */
 static double fracdim;            /* Fractal dimension */
 static double powscale;           /* Power law scaling exponent */
 static int meshsize = 256;        /* FFT mesh size */
-static unsigned int seedarg;        /* Seed specified by user */
-static bool seedspec = FALSE;      /* Did the user specify a seed ? */
-static bool clouds = FALSE;        /* Just generate clouds */
-static bool stars = FALSE;         /* Just generate stars */
-static int screenxsize = 256;         /* Screen X size */
-static int screenysize = 256;         /* Screen Y size */
 static double inclangle, hourangle;   /* Star position relative to planet */
 static bool inclspec = FALSE;      /* No inclination specified yet */
 static bool hourspec = FALSE;      /* No hour specified yet */
@@ -88,6 +83,166 @@ static double glaciers;           /* Glacier level */
 static int starfraction;          /* Star fraction */
 static int starcolor;            /* Star color saturation */
 
+
+struct CmdlineInfo {
+    unsigned int clouds;
+    unsigned int night;
+    float        dimension;
+    float        hourAngle;
+    unsigned int hourSpec;
+    float        inclAngle;
+    unsigned int inclinationSpec;
+    unsigned int meshSize;
+    unsigned int meshSpec;
+    float        power;
+    float        glaciers;
+    float        ice;
+    int          saturation;
+    unsigned int seed;
+    int          stars;
+    unsigned int starsSpec;
+    unsigned int width;
+    unsigned int height;
+};
+
+
+
+static void
+parseCommandLine(int argc, const char **argv,
+                 struct CmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+  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 
+  argv[] points to.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;
+        /* Instructions to OptParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    unsigned int dimensionSpec, seedSpec,
+        meshSpec, powerSpec, glaciersSpec, iceSpec, saturationSpec,
+        starsSpec, widthSpec, heightSpec;
+    float hour;
+    float inclination;
+    unsigned int mesh;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;
+    OPTENT3(0, "clouds",      OPT_FLAG, NULL, &cmdlineP->clouds, 0);
+    OPTENT3(0, "night",       OPT_FLAG, NULL, &cmdlineP->night, 0);
+    OPTENT3(0, "dimension",   OPT_FLOAT, &cmdlineP->dimension,
+            &dimensionSpec, 0);
+    OPTENT3(0, "hour",        OPT_FLOAT, &hour,
+            &cmdlineP->hourSpec, 0);
+    OPTENT3(0, "inclination", OPT_FLOAT, &inclination,
+            &cmdlineP->inclinationSpec, 0);
+    OPTENT3(0, "tilt",        OPT_FLOAT, &inclination,
+            &cmdlineP->inclinationSpec, 0);
+    OPTENT3(0, "mesh",        OPT_UINT, &mesh,
+            &meshSpec, 0);
+    OPTENT3(0, "power",       OPT_FLOAT, &cmdlineP->power,
+            &powerSpec, 0);
+    OPTENT3(0, "glaciers",    OPT_FLOAT, &cmdlineP->glaciers,
+            &glaciersSpec, 0);
+    OPTENT3(0, "ice",         OPT_FLOAT, &cmdlineP->ice,
+            &iceSpec, 0);
+    OPTENT3(0, "saturation",  OPT_INT,   &cmdlineP->saturation,
+            &saturationSpec, 0);
+    OPTENT3(0, "seed",        OPT_UINT,  &cmdlineP->seed,
+            &seedSpec, 0);
+    OPTENT3(0, "stars",       OPT_INT,   &cmdlineP->stars,
+            &starsSpec, 0);
+    OPTENT3(0, "width",       OPT_UINT,  &cmdlineP->width,
+            &widthSpec, 0);
+    OPTENT3(0, "xsize",       OPT_UINT,  &cmdlineP->width,
+            &widthSpec, 0);
+    OPTENT3(0, "height",      OPT_UINT,  &cmdlineP->height,
+            &heightSpec, 0);
+    OPTENT3(0, "ysize",       OPT_UINT,  &cmdlineP->height,
+            &heightSpec, 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 (dimensionSpec) {
+        if (cmdlineP->dimension <= 0.0)
+            pm_error("-dimension must be greater than zero.  "
+                     "You specified %f", cmdlineP->dimension);
+    } else
+        cmdlineP->dimension = cmdlineP->clouds ? 2.15 : 2.4;
+
+    if (cmdlineP->hourSpec)
+        cmdlineP->hourAngle = (M_PI / 12.0) * (hour + 12.0);
+
+    if (cmdlineP->inclinationSpec)
+        cmdlineP->inclAngle = (M_PI / 180.0) * inclination;
+
+    if (meshSpec) {
+        unsigned int i;
+        if (mesh < 2)
+            pm_error("-mesh value must be at least 2.  "
+                     "You specified %u", mesh);
+        /* Force FFT mesh to the next larger power of 2. */
+        for (i = 2; i < mesh; i <<= 1);
+        cmdlineP->meshSize = i;
+    } else
+        cmdlineP->meshSize = 256;
+
+    if (powerSpec) {
+        if (cmdlineP->power <= 0.0)
+            pm_error("-power must be greater than zero.  "
+                     "You specified %f", cmdlineP->power);
+    } else
+        cmdlineP->power = cmdlineP->clouds ? 0.75 : 1.2;
+
+    if (iceSpec) {
+        if (cmdlineP->ice <= 0.0)
+            pm_error("-ice must be greater than zero.  "
+                     "You specified %f", cmdlineP->ice);
+    } else
+        cmdlineP->ice = 0.4;
+
+    if (glaciersSpec) {
+        if (cmdlineP->glaciers <= 0.0)
+            pm_error("-glaciers must be greater than 0.  "
+                     "You specified %f", cmdlineP->glaciers);
+    } else
+        cmdlineP->glaciers = 0.75;
+
+    if (!starsSpec)
+        cmdlineP->stars = 100;
+
+    if (!saturationSpec)
+        cmdlineP->saturation = 125;
+
+    if (!seedSpec)
+        cmdlineP->seed = pm_randseed();
+
+    if (!widthSpec)
+        cmdlineP->width = 256;
+
+    if (!heightSpec)
+        cmdlineP->height = 256;
+
+    if (argc-1 > 0)
+        pm_error("There are no non-option arguments.  "
+                 "You specified %u", argc-1);
+
+    free(option_def);
+}
+
+
 /*  FOURN  --  Multi-dimensional fast Fourier transform
 
     Called with arguments:
@@ -274,19 +429,6 @@ static void spectralsynth(x, n, h)
 }
 
 
-static unsigned int
-initseed(void) {
-    /*  Generate initial random seed.  */
-
-    unsigned int i;
-
-    srand(pm_randseed());
-    for (i = 0; i < 7; ++i)
-        rand();
-    return rand();
-}
-
-
 
 /*  TEMPRGB  --  Calculate the relative R, G, and B components  for  a
          black  body  emitting  light  at a given temperature.
@@ -417,7 +559,8 @@ makeCp(float *      const a,
 
 
 static void
-createPlanetStuff(float *          const a,
+createPlanetStuff(bool             const clouds,
+                  float *          const a,
                   unsigned int     const n,
                   double **        const uP,
                   double **        const u1P,
@@ -456,7 +599,9 @@ createPlanetStuff(float *          const a,
             "        -inclination %.0f -hour %d -ice %.2f -glaciers %.2f",
             (siang * (180.0 / M_PI)),
             (int) (((shang * (12.0 / M_PI)) + 12 +
-                    (flipped ? 12 : 0)) + 0.5) % 24, icelevel, glaciers);
+                    (flipped ? 12 : 0)) + 0.5) % 24,
+            icelevel,
+            glaciers);
         pm_message("        -stars %d -saturation %d.",
                    starfraction, starcolor);
     }
@@ -531,9 +676,9 @@ generateCloudRow(pixel *         const pixels,
 
     /* Render the FFT output as clouds. */
 
-    unsigned int j;
+    unsigned int col;
 
-    for (j = 0; j < cols; j++) {
+    for (col = 0; col < cols; ++col) {
         double r;
         pixval w;
         
@@ -542,15 +687,15 @@ generateCloudRow(pixel *         const pixels,
            referenced below does not exist.
         */
         if (t1 > 0.0)
-            r += t1 * u1[j] * cp[byf + bxf[j]] +
-                t1 * u[j]  * cp[byf + bxc[j]];
+            r += t1 * u1[col] * cp[byf + bxf[col]] +
+                t1 * u[col]  * cp[byf + bxc[col]];
         if (t > 0.0)
-            r += t * u1[j] * cp[byc + bxf[j]] +
-                t * u[j]  * cp[byc + bxc[j]];
+            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 + j), w, w, maxval);
+        PPM_ASSIGN(pixels[col], w, w, maxval);
     }
 }
 
@@ -819,7 +964,7 @@ genplanet(bool         const stars,
         pm_message("%s: -seed %d -dimension %.2f -power %.2f -mesh %d",
                    clouds ? "clouds" : "planet",
                    rseed, fracdim, powscale, meshsize);
-        createPlanetStuff(a, n, &u, &u1, &bxf, &bxc, &cp, &sunvec, 
+        createPlanetStuff(clouds, a, n, &u, &u1, &bxf, &bxc, &cp, &sunvec, 
                           cols, maxval);
     }
 
@@ -940,19 +1085,14 @@ static bool
 planet(unsigned int const cols,
        unsigned int const rows,
        bool         const stars,
-       bool         const clouds) {
+       bool         const clouds,
+       unsigned int const rseed) {
 /*----------------------------------------------------------------------------
    Make a planet.
 -----------------------------------------------------------------------------*/
     float * a;
     bool error;
-    unsigned int rseed;        /* Current random seed */
-    
-    if (seedspec)
-        rseed = seedarg;
-    else 
-        rseed = initseed();
-    
+
     initgauss(rseed);
     
     if (stars) {
@@ -981,200 +1121,39 @@ planet(unsigned int const cols,
 
 
 
-
 int 
-main(int argc, char ** argv) {
+main(int argc, const char ** argv) {
 
+    struct CmdlineInfo cmdline;
     bool success;
-    int i;
-    const char * const usage = "\n\
-[-width|-xsize <x>] [-height|-ysize <y>] [-mesh <n>]\n\
-[-clouds] [-dimension <f>] [-power <f>] [-seed <n>]\n\
-[-hour <f>] [-inclination|-tilt <f>] [-ice <f>] [-glaciers <f>]\n\
-[-night] [-stars <n>] [-saturation <n>]";
-    bool dimspec = FALSE, meshspec = FALSE, powerspec = FALSE,
-        widspec = FALSE, hgtspec = FALSE, icespec = FALSE,
-        glacspec = FALSE, starspec = FALSE, starcspec = FALSE;
-
-    int cols, rows;     /* Dimensions of our output image */
-
-    ppm_init(&argc, argv);
-    i = 1;
-    
-    while ((i < argc) && (argv[i][0] == '-') && (argv[i][1] != '\0')) {
-
-        if (pm_keymatch(argv[i], "-clouds", 2)) {
-            clouds = TRUE;
-        } else if (pm_keymatch(argv[i], "-night", 2)) {
-            stars = TRUE;
-        } else if (pm_keymatch(argv[i], "-dimension", 2)) {
-            if (dimspec) {
-                pm_error("already specified a dimension");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%lf", &fracdim)  != 1))
-                pm_usage(usage);
-            if (fracdim <= 0.0) {
-                pm_error("fractal dimension must be greater than 0");
-            }
-            dimspec = TRUE;
-        } else if (pm_keymatch(argv[i], "-hour", 3)) {
-            if (hourspec) {
-                pm_error("already specified an hour");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%lf", &hourangle) != 1))
-                pm_usage(usage);
-            hourangle = (M_PI / 12.0) * (hourangle + 12.0);
-            hourspec = TRUE;
-        } else if (pm_keymatch(argv[i], "-inclination", 3) ||
-                   pm_keymatch(argv[i], "-tilt", 2)) {
-            if (inclspec) {
-                pm_error("already specified an inclination/tilt");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%lf", &inclangle) != 1))
-                pm_usage(usage);
-            inclangle = (M_PI / 180.0) * inclangle;
-            inclspec = TRUE;
-        } else if (pm_keymatch(argv[i], "-mesh", 2)) {
-            unsigned int j;
 
-            if (meshspec) {
-                pm_error("already specified a mesh size");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%d", &meshsize) != 1))
-                pm_usage(usage);
+    unsigned int cols, rows;     /* Dimensions of our output image */
 
-            if (meshsize < 2)
-                pm_error("mesh must be at least 2");
+    pm_proginit(&argc, argv);
 
-            /* Force FFT mesh to the next larger power of 2. */
+    parseCommandLine(argc, argv, &cmdline);
 
-            for (j = meshsize; (j & 1) == 0; j >>= 1) ;
-
-            if (j != 1) {
-                for (j = 2; j < meshsize; j <<= 1) ;
-                meshsize = j;
-            }
-            meshspec = TRUE;
-        } else if (pm_keymatch(argv[i], "-power", 2)) {
-            if (powerspec) {
-                pm_error("already specified a power factor");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%lf", &powscale) != 1))
-                pm_usage(usage);
-            if (powscale <= 0.0) {
-                pm_error("power factor must be greater than 0");
-            }
-            powerspec = TRUE;
-        } else if (pm_keymatch(argv[i], "-ice", 3)) {
-            if (icespec) {
-                pm_error("already specified ice cap level");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%lf", &icelevel) != 1))
-                pm_usage(usage);
-            if (icelevel <= 0.0) {
-                pm_error("ice cap level must be greater than 0");
-            }
-            icespec = TRUE;
-        } else if (pm_keymatch(argv[i], "-glaciers", 2)) {
-            if (glacspec) {
-                pm_error("already specified glacier level");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%lf", &glaciers) != 1))
-                pm_usage(usage);
-            if (glaciers <= 0.0) {
-                pm_error("glacier level must be greater than 0");
-            }
-            glacspec = TRUE;
-        } else if (pm_keymatch(argv[i], "-stars", 3)) {
-            if (starspec) {
-                pm_error("already specified a star fraction");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%d", &starfraction) != 1))
-                pm_usage(usage);
-            starspec = TRUE;
-        } else if (pm_keymatch(argv[i], "-saturation", 3)) {
-            if (starcspec) {
-                pm_error("already specified a star color saturation");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%d", &starcolor) != 1))
-                pm_usage(usage);
-            starcspec = TRUE;
-        } else if (pm_keymatch(argv[i], "-seed", 3)) {
-            if (seedspec) {
-                pm_error("already specified a random seed");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%u", &seedarg) != 1))
-                pm_usage(usage);
-            seedspec = TRUE;
-        } else if (pm_keymatch(argv[i], "-xsize", 2) ||
-                   pm_keymatch(argv[i], "-width", 2)) {
-            if (widspec) {
-                pm_error("already specified a width/xsize");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%d", &screenxsize) != 1))
-                pm_usage(usage);
-            widspec = TRUE;
-        } else if (pm_keymatch(argv[i], "-ysize", 2) ||
-                   pm_keymatch(argv[i], "-height", 3)) {
-            if (hgtspec) {
-                pm_error("already specified a height/ysize");
-            }
-            i++;
-            if ((i == argc) || (sscanf(argv[i], "%d", &screenysize) != 1))
-                pm_usage(usage);
-            hgtspec = TRUE;
-        } else {
-            pm_usage(usage);
-        }
-        i++;
-    }
-
-
-    /* Set defaults when explicit specifications were not given.
-
-       The  default  fractal  dimension  and  power  scale depend upon
-       whether we are generating a planet or clouds. 
-    */
-    
-    if (!dimspec) {
-        fracdim = clouds ? 2.15 : 2.4;
-    }
-    if (!powerspec) {
-        powscale = clouds ? 0.75 : 1.2;
-    }
-    if (!icespec) {
-        icelevel = 0.4;
-    }
-    if (!glacspec) {
-        glaciers = 0.75;
-    }
-    if (!starspec) {
-        starfraction = 100;
-    }
-    if (!starcspec) {
-        starcolor = 125;
-    }
+    fracdim      = cmdline.dimension;
+    hourspec     = cmdline.hourSpec;
+    hourangle    = cmdline.hourAngle;
+    inclspec     = cmdline.inclinationSpec;
+    inclangle    = cmdline.inclAngle;
+    meshsize     = cmdline.meshSize;
+    powscale     = cmdline.power;
+    icelevel     = cmdline.ice;
+    glaciers     = cmdline.glaciers;
+    starfraction = cmdline.stars;
+    starcolor    = cmdline.saturation;
 
     /* 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.  
     */
 
-    cols = (MAX(screenysize, screenxsize) + 1) & (~1);
-    rows = screenysize;
+    cols = (MAX(cmdline.height, cmdline.width) + 1) & (~1);
+    rows = cmdline.height;
 
-    success = planet(cols, rows, stars, clouds);
+    success = planet(cols, rows, cmdline.night, cmdline.clouds, cmdline.seed);
 
     exit(success ? 0 : 1);
 }
diff --git a/generator/ppmrainbow b/generator/ppmrainbow
index 96e304ac..c0568d9b 100755
--- a/generator/ppmrainbow
+++ b/generator/ppmrainbow
@@ -1,4 +1,28 @@
-#!/usr/bin/perl -wl
+#!/bin/sh
+
+##############################################################################
+# This is essentially a Perl program.  We exec the Perl interpreter specifying
+# this same file as the Perl program and use the -x option to cause the Perl
+# interpreter to skip down to the Perl code.  The reason we do this instead of
+# just making /usr/bin/perl the script interpreter (instead of /bin/sh) is
+# that the user may have multiple Perl interpreters and the one he wants to
+# use is properly located in the PATH.  The user's choice of Perl interpreter
+# may be crucial, such as when the user also has a PERL5LIB environment
+# variable and it selects modules that work with only a certain main
+# interpreter program.
+#
+# An alternative some people use is to have /usr/bin/env as the script
+# interpreter.  We don't do that because we think the existence and
+# compatibility of /bin/sh is more reliable.
+#
+# Note that we aren't concerned about efficiency because the user who needs
+# high efficiency can use directly the programs that this program invokes.
+#
+##############################################################################
+
+exec perl -w -x -S -- "$0" "$@"
+
+#!/usr/bin/perl
 use strict;
 use Getopt::Long;
 
diff --git a/lib/libpam.c b/lib/libpam.c
index 549f4c55..f188f7d6 100644
--- a/lib/libpam.c
+++ b/lib/libpam.c
@@ -1046,9 +1046,7 @@ pnm_writepaminit(struct pam * const pamP) {
     
     switch (PAM_FORMAT_TYPE(pamP->format)) {
     case PAM_TYPE:
-        if (pm_plain_output)
-            pm_error("There is no plain version of PAM.  -plain option "
-                     "is not allowed");
+        /* See explanation below of why we ignore 'pm_plain_output' here. */
         fprintf(pamP->file, "P7\n");
         writeComments(pamP);
         fprintf(pamP->file, "WIDTH %u\n",   (unsigned)pamP->width);
@@ -1108,6 +1106,23 @@ pnm_writepaminit(struct pam * const pamP) {
 
 
 
+/* EFFECT OF -plain WHEN WRITING PAM FORMAT:
+
+   Before Netpbm 10.63 (June 2013), pnm_writepaminit() did a pm_error() here
+   if 'pm_plain_output' was set (i.e. the user said -plain).  But this isn't
+   really logical, because -plain is a global option for the program and here
+   we are just writing one image.  As a global option, -plain must be defined
+   to have effect where it makes sense and have no effect where it doesn't.
+   Note that a program that generates GIF just ignores -plain.  Note also that
+   a program could conceivably generate both a PPM image and a PAM image.
+
+   Note also how we handle the other a user can request plain format: the
+   'plainformat' member of the PAM struct.  In the case of PAM, we ignore that
+   member.
+*/
+
+
+
 void
 pnm_checkpam(const struct pam *   const pamP, 
              enum pm_check_type   const checkType, 
@@ -1291,7 +1306,7 @@ pnm_addopacityrow(const struct pam * const pamP,
 
 void
 pnm_getopacity(const struct pam * const pamP,
-               bool *             const haveOpacityP,
+               int *              const haveOpacityP,
                unsigned int *     const opacityPlaneP) {
 
     /* Usage note: this is obsolete since we added 'have_opacity', etc.
diff --git a/lib/libpammap.c b/lib/libpammap.c
index 66aa6fc0..ef373e81 100644
--- a/lib/libpammap.c
+++ b/lib/libpammap.c
@@ -574,7 +574,7 @@ pnm_computetupletablehash(struct pam * const pamP,
 -----------------------------------------------------------------------------*/
     tuplehash tupletablehash;
     unsigned int i;
-    bool fits;
+    int fits;
     
     tupletablehash = pnm_createtuplehash();
 
diff --git a/lib/libpamn.c b/lib/libpamn.c
index bd3fab21..b30bde53 100644
--- a/lib/libpamn.c
+++ b/lib/libpamn.c
@@ -498,7 +498,7 @@ gammaCommon(struct pam *  const pamP,
 
     unsigned int plane;
     unsigned int opacityPlane;
-    bool haveOpacity;
+    int haveOpacity;
     
     pnm_getopacity(pamP, &haveOpacity, &opacityPlane);
 
@@ -548,7 +548,7 @@ applyopacityCommon(enum applyUnapply const applyUnapply,
    if the foreground values had already been so multiplied.
 -----------------------------------------------------------------------------*/
     unsigned int opacityPlane;
-    bool haveOpacity;
+    int haveOpacity;
     
     pnm_getopacity(pamP, &haveOpacity, &opacityPlane);
 
@@ -645,7 +645,7 @@ createUngammaMapOffset(const struct pam * const pamP,
         MALLOCARRAY(ungammaTransformMap, pamP->maxval+1);
 
         if (ungammaTransformMap != NULL) {
-            bool haveOpacity;
+            int haveOpacity;
             unsigned int opacityPlane;
             unsigned int plane;
 
diff --git a/lib/libpamwrite.c b/lib/libpamwrite.c
index 73e5e78a..9f86e359 100644
--- a/lib/libpamwrite.c
+++ b/lib/libpamwrite.c
@@ -22,6 +22,7 @@
 #include <math.h>
 
 #include "pm_config.h"
+#include "pm_c_util.h"
 #include "pam.h"
 
 
@@ -354,7 +355,9 @@ pnm_writepamrow(const struct pam * const pamP,
        pnm_writepaminit().
     */
     
-    if (pm_plain_output || pamP->plainformat) {
+    if (pamP->format == PAM_FORMAT || !(pm_plain_output || pamP->plainformat))
+        writePamRawRow(pamP, tuplerow, 1);
+    else {
         switch (PAM_FORMAT_TYPE(pamP->format)) {
         case PBM_TYPE:
             writePamPlainPbmRow(pamP, tuplerow);
@@ -364,18 +367,13 @@ pnm_writepamrow(const struct pam * const pamP,
             writePamPlainRow(pamP, tuplerow);
             break;
         case PAM_TYPE:
-            /* pm_plain_output is impossible here due to assumption stated
-               above about pnm_writepaminit() having checked it.  The
-               pamP->plainformat is meaningless for PAM.
-            */
-            writePamRawRow(pamP, tuplerow, 1);
+            assert(false);
             break;
         default:
             pm_error("Invalid 'format' value %u in pam structure", 
                      pamP->format);
         }
-    } else
-        writePamRawRow(pamP, tuplerow, 1);
+    }
 }
 
 
diff --git a/lib/libpbm1.c b/lib/libpbm1.c
index 25498bc7..c96779ed 100644
--- a/lib/libpbm1.c
+++ b/lib/libpbm1.c
@@ -57,27 +57,28 @@ pbm_nextimage(FILE *file, int * const eofP) {
 
 
 void
-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) {
+pbm_check(FILE *               const fileP,
+          enum pm_check_type   const checkType, 
+          int                  const format,
+          int                  const cols,
+          int                  const rows,
+          enum pm_check_code * const retvalP) {
 
     if (rows < 0)
         pm_error("Invalid number of rows passed to pbm_check(): %d", rows);
     if (cols < 0)
         pm_error("Invalid number of columns passed to pbm_check(): %d", cols);
     
-    if (check_type != PM_CHECK_BASIC) {
-        if (retval_p) *retval_p = PM_CHECK_UNKNOWN_TYPE;
+    if (checkType != PM_CHECK_BASIC) {
+        if (retvalP)
+            *retvalP = PM_CHECK_UNKNOWN_TYPE;
     } else if (format != RPBM_FORMAT) {
-        if (retval_p) *retval_p = PM_CHECK_UNCHECKABLE;
+        if (retvalP)
+            *retvalP = PM_CHECK_UNCHECKABLE;
     } else {        
-        pm_filepos const bytes_per_row = (cols+7)/8;
-        pm_filepos const need_raster_size = rows * bytes_per_row;
-#ifdef LARGEFILEDEBUG
-        pm_message("pm_filepos passed to pm_check() is %u bytes",
-                   sizeof(pm_filepos));
-#endif
-        pm_check(file, check_type, need_raster_size, retval_p);
+        pm_filepos const bytesPerRow    = (cols+7)/8;
+        pm_filepos const needRasterSize = rows * bytesPerRow;
+        pm_check(fileP, checkType, needRasterSize, retvalP);
     }
 }
 
diff --git a/lib/libpgm1.c b/lib/libpgm1.c
index 5a533f49..987ee04e 100644
--- a/lib/libpgm1.c
+++ b/lib/libpgm1.c
@@ -338,28 +338,30 @@ pgm_readpgm(FILE * const fileP,
 
 void
 pgm_check(FILE *               const file, 
-          enum pm_check_type   const check_type, 
+          enum pm_check_type   const checkType, 
           int                  const format, 
           int                  const cols, 
           int                  const rows, 
           gray                 const maxval,
-          enum pm_check_code * const retval_p) {
+          enum pm_check_code * const retvalP) {
 
     if (rows < 0)
         pm_error("Invalid number of rows passed to pgm_check(): %d", rows);
     if (cols < 0)
         pm_error("Invalid number of columns passed to pgm_check(): %d", cols);
     
-    if (check_type != PM_CHECK_BASIC) {
-        if (retval_p) *retval_p = PM_CHECK_UNKNOWN_TYPE;
+    if (checkType != PM_CHECK_BASIC) {
+        if (retvalP)
+            *retvalP = PM_CHECK_UNKNOWN_TYPE;
     } else if (PGM_FORMAT_TYPE(format) == PBM_TYPE) {
-        pbm_check(file, check_type, format, cols, rows, retval_p);
+        pbm_check(file, checkType, format, cols, rows, retvalP);
     } else if (format != RPGM_FORMAT) {
-        if (retval_p) *retval_p = PM_CHECK_UNCHECKABLE;
+        if (retvalP)
+            *retvalP = PM_CHECK_UNCHECKABLE;
     } else {        
-        pm_filepos const bytes_per_row = cols * (maxval > 255 ? 2 : 1);
-        pm_filepos const need_raster_size = rows * bytes_per_row;
+        pm_filepos const bytesPerRow    = cols * (maxval > 255 ? 2 : 1);
+        pm_filepos const needRasterSize = rows * bytesPerRow;
         
-        pm_check(file, check_type, need_raster_size, retval_p);
+        pm_check(file, checkType, needRasterSize, retvalP);
     }
 }
diff --git a/lib/libppm1.c b/lib/libppm1.c
index 1b417613..195aec70 100644
--- a/lib/libppm1.c
+++ b/lib/libppm1.c
@@ -422,30 +422,32 @@ ppm_readppm(FILE *   const fileP,
 
 void
 ppm_check(FILE *               const fileP, 
-          enum pm_check_type   const check_type, 
+          enum pm_check_type   const checkType, 
           int                  const format, 
           int                  const cols, 
           int                  const rows, 
           pixval               const maxval,
-          enum pm_check_code * const retval_p) {
+          enum pm_check_code * const retvalP) {
 
     if (rows < 0)
         pm_error("Invalid number of rows passed to ppm_check(): %d", rows);
     if (cols < 0)
         pm_error("Invalid number of columns passed to ppm_check(): %d", cols);
     
-    if (check_type != PM_CHECK_BASIC) {
-        if (retval_p) *retval_p = PM_CHECK_UNKNOWN_TYPE;
+    if (checkType != PM_CHECK_BASIC) {
+        if (retvalP)
+            *retvalP = PM_CHECK_UNKNOWN_TYPE;
     } else if (PPM_FORMAT_TYPE(format) == PBM_TYPE) {
-        pbm_check(fileP, check_type, format, cols, rows, retval_p);
+        pbm_check(fileP, checkType, format, cols, rows, retvalP);
     } else if (PPM_FORMAT_TYPE(format) == PGM_TYPE) {
-        pgm_check(fileP, check_type, format, cols, rows, maxval, retval_p);
+        pgm_check(fileP, checkType, format, cols, rows, maxval, retvalP);
     } else if (format != RPPM_FORMAT) {
-        if (retval_p) *retval_p = PM_CHECK_UNCHECKABLE;
+        if (retvalP)
+            *retvalP = PM_CHECK_UNCHECKABLE;
     } else {        
-        pm_filepos const bytes_per_row = cols * 3 * (maxval > 255 ? 2 : 1);
-        pm_filepos const need_raster_size = rows * bytes_per_row;
+        pm_filepos const bytesPerRow    = cols * 3 * (maxval > 255 ? 2 : 1);
+        pm_filepos const needRasterSize = rows * bytesPerRow;
         
-        pm_check(fileP, check_type, need_raster_size, retval_p);
+        pm_check(fileP, checkType, needRasterSize, retvalP);
     }
 }
diff --git a/lib/libppmcolor.c b/lib/libppmcolor.c
index 70e8499d..347bab29 100644
--- a/lib/libppmcolor.c
+++ b/lib/libppmcolor.c
@@ -451,6 +451,43 @@ ppm_colorname(const pixel * const colorP,
 
 #define MAXCOLORNAMES 1000u
 
+static const char **
+allocColorNames() {
+
+    const char ** colornames;
+
+    MALLOCARRAY(colornames, MAXCOLORNAMES);
+
+    if (colornames) {
+        unsigned int i;
+        for (i = 0; i < MAXCOLORNAMES; ++i)
+            colornames[i] = NULL;
+    }
+    return colornames;
+}
+
+
+
+static colorhash_table
+allocColorHash(void) {
+
+    colorhash_table cht;
+    jmp_buf jmpbuf;
+    jmp_buf * origJmpbufP;
+
+    if (setjmp(jmpbuf) != 0)
+        cht = NULL;
+    else {
+        pm_setjmpbufsave(&jmpbuf, &origJmpbufP);
+        cht = ppm_alloccolorhash();
+    }
+    pm_setjmpbuf(origJmpbufP);
+
+    return cht;
+}
+
+
+
 static void
 processColorfileEntry(struct colorfile_entry const ce,
                       colorhash_table        const cht,
@@ -525,6 +562,9 @@ readOpenColorFile(FILE *          const colorFileP,
    Read the color dictionary file *colorFileP and add the colors in it
    to colornames[], colors[], and 'cht'.
 
+   colornames[] and colors[] must be allocated with MAXCOLORNAMES entries
+   at entry.
+
    We may add colors to 'cht' even if we fail.
 -----------------------------------------------------------------------------*/
     unsigned int nColorsDone;
@@ -543,12 +583,7 @@ readOpenColorFile(FILE *          const colorFileP,
             processColorfileEntry(ce, cht, colornames, colors,
                                   &nColorsDone, errorP);
     }
-    if (!*errorP) {
-        *nColorsP = nColorsDone;
-        
-        while (nColorsDone < MAXCOLORNAMES)
-            colornames[nColorsDone++] = NULL;
-    }
+    *nColorsP = nColorsDone;
     
     if (*errorP) {
         unsigned int colorIndex;
@@ -560,26 +595,6 @@ readOpenColorFile(FILE *          const colorFileP,
 
 
 
-static colorhash_table
-allocColorHash(void) {
-
-    colorhash_table cht;
-    jmp_buf jmpbuf;
-    jmp_buf * origJmpbufP;
-
-    if (setjmp(jmpbuf) != 0)
-        cht = NULL;
-    else {
-        pm_setjmpbufsave(&jmpbuf, &origJmpbufP);
-        cht = ppm_alloccolorhash();
-    }
-    pm_setjmpbuf(origJmpbufP);
-
-    return cht;
-}
-
-
-
 static void
 readColorFile(const char *    const fileName,
               bool            const mustOpen,
@@ -588,7 +603,20 @@ readColorFile(const char *    const fileName,
               pixel *         const colors,
               colorhash_table const cht,
               const char **   const errorP) {
+/*----------------------------------------------------------------------------
+   Read the color dictionary file named 'fileName' and add the colors in it
+   to colornames[], colors[], and 'cht'.  Return as *nColorsP the number
+   of colors in it.
 
+   If the file is not openable (e.g. not file by that name exists), abort the
+   program if 'mustOpen' is true; otherwise, return values indicating a
+   dictionary with no colors.
+
+   colornames[] and colors[] must be allocated with MAXCOLORNAMES entries
+   at entry.
+
+   We may add colors to 'cht' even if we fail.
+-----------------------------------------------------------------------------*/
     FILE * colorFileP;
 
     openColornameFile(fileName, mustOpen, &colorFileP, errorP);
@@ -598,11 +626,6 @@ readColorFile(const char *    const fileName,
                empty file
             */
             *nColorsP = 0;
-            {
-                unsigned int i;
-                for (i = 0; i < MAXCOLORNAMES; ++i)
-                    colornames[i] = NULL;
-            }
             *errorP = NULL;
         } else {
             readOpenColorFile(colorFileP, nColorsP, colornames, colors, cht,
@@ -626,7 +649,7 @@ readcolordict(const char *      const fileName,
 
     const char ** colornames;
 
-    MALLOCARRAY(colornames, MAXCOLORNAMES);
+    colornames = allocColorNames();
 
     if (colornames == NULL)
         pm_asprintf(errorP, "Unable to allocate space for colorname table.");
@@ -675,7 +698,28 @@ ppm_readcolordict(const char *      const fileName,
                   const char ***    const colornamesP,
                   pixel **          const colorsP,
                   colorhash_table * const chtP) {
+/*----------------------------------------------------------------------------
+   Read the color dictionary from the file named 'fileName'.  If we can't open
+   the file (e.g. because it does not exist), and 'mustOpen' is false, return
+   an empty dictionary (it contains no colors).  But if 'mustOpen' is true,
+   abort the program instead of returning an empty dictionary.
+
+   Return as *nColorsP the number of colors in the dictionary.
 
+   Return as *colornamesP the names of those colors.  *colornamesP is a
+   malloced array that Caller must free with ppm_freecolornames().
+   The first *nColorsP entries are valid; *chtP contains indices into this
+   array.
+
+   Return as *colorsP the colors.  *colorsP is a malloced array of size
+   MAXCOLORS with the first elements filled in and the rest undefined.
+
+   Return as *chtP a color hash table mapping each color in the dictionary
+   to the index into *colornamesP for the name of the color.
+
+   Each of 'nColorsP, 'colornamesP', and 'colorsP' may be null, in which case
+   we do not return the corresponding information (or allocate memory for it).
+-----------------------------------------------------------------------------*/
     colorhash_table cht;
     const char ** colornames;
     pixel * colors;
diff --git a/lib/libsystem.c b/lib/libsystem.c
index 259f18e4..b8c3ea50 100644
--- a/lib/libsystem.c
+++ b/lib/libsystem.c
@@ -501,20 +501,20 @@ pm_feed_from_memory(int    const pipeToFeedFd,
 
     struct bufferDesc * const inputBufferP = feederParm;
     
-    FILE * const outfile = fdopen(pipeToFeedFd, "w");
+    FILE * const outFileP = fdopen(pipeToFeedFd, "w");
     
-    int bytesTransferred;
+    size_t bytesTransferred;
 
     /* The following signals (and normally kills) the process with
        SIGPIPE if the pipe does not take all 'size' bytes.
     */
     bytesTransferred = 
-        fwrite(inputBufferP->buffer, 1, inputBufferP->size, outfile);
+        fwrite(inputBufferP->buffer, 1, inputBufferP->size, outFileP);
 
     if (inputBufferP->bytesTransferredP)
         *(inputBufferP->bytesTransferredP) = bytesTransferred;
 
-    fclose(outfile);
+    fclose(outFileP);
 }
 
 
@@ -525,14 +525,14 @@ pm_accept_to_memory(int             const pipetosuckFd,
 
     struct bufferDesc * const outputBufferP = accepterParm;
     
-    FILE * const infile = fdopen(pipetosuckFd, "r");
+    FILE * const inFileP = fdopen(pipetosuckFd, "r");
 
-    int bytesTransferred;
+    size_t bytesTransferred;
 
     bytesTransferred =
-        fread(outputBufferP->buffer, 1, outputBufferP->size, infile);
+        fread(outputBufferP->buffer, 1, outputBufferP->size, inFileP);
 
-    fclose(infile);
+    fclose(inFileP);
 
     if (outputBufferP->bytesTransferredP)
         *(outputBufferP->bytesTransferredP) = bytesTransferred;
diff --git a/lib/pam.h b/lib/pam.h
index 6213dab3..2726092b 100644
--- a/lib/pam.h
+++ b/lib/pam.h
@@ -52,9 +52,13 @@ struct pam {
         */
     FILE * file;
     int format;
-        /* The format code of the raw image.  This is PAM_FORMAT
+        /* The format code of the image.  This is PAM_FORMAT
            unless the PAM image is really a view of a PBM, PGM, or PPM
-           image.  Then it's PBM_FORMAT, RPBM_FORMAT, etc.
+           image.  Then it's PBM_FORMAT, RPBM_FORMAT, etc.  For output,
+           only the format _type_ is significant, e.g. PBM_FORMAT
+           and RPBM_FORMAT have identical effect.  This is because on
+           output, 'plainformat' determines whether the output is the
+           raw or plain format of the type given by 'format'.
            */
     unsigned int plainformat;
         /* Logical: On output, use plain version of the format type
@@ -67,6 +71,9 @@ struct pam {
            Before Netpbm 10.32, this was rather different.  It simply
            described for convenience the plainness of the format indicated
            by 'format'.
+
+           This is meaningless when 'format' is PAM_FORMAT, as PAM does not
+           have plain and raw variations.
         */
     int height;  /* Height of image in rows */
     int width;   
@@ -514,6 +521,8 @@ pnm_backgroundtuple(struct pam *  const pamP,
 /*----------------------------------------------------------------------------
    These are meant for passing to pm_system() as Standard Input feeder
    and Standard Output accepter.
+
+   The 'feederParm' or 'accepterParm' is a pointer to a struct pamtuples.
 -----------------------------------------------------------------------------*/
 
 void
diff --git a/lib/pmfileio.c b/lib/pmfileio.c
index 82b44cdb..1263261a 100644
--- a/lib/pmfileio.c
+++ b/lib/pmfileio.c
@@ -919,10 +919,6 @@ pm_check(FILE *               const file,
     pm_filepos curpos;  /* Current position of file; -1 if none */
     int rc;
 
-#ifdef LARGEFILEDEBUG
-    pm_message("pm_filepos received by pm_check() is %u bytes.",
-               sizeof(pm_filepos));
-#endif
     /* Note: FTELLO() is either ftello() or ftell(), depending on the
        capabilities of the underlying C library.  It is defined in
        pm_config.h.  ftello(), in turn, may be either ftell() or
diff --git a/lib/util/mallocvar.h b/lib/util/mallocvar.h
index 31ad38bc..e92e3fe4 100644
--- a/lib/util/mallocvar.h
+++ b/lib/util/mallocvar.h
@@ -87,7 +87,7 @@ reallocProduct(void **      const blockP,
     void * array; \
     array = arrayName; \
     reallocProduct(&array, nElements, sizeof(arrayName[0])); \
-    if (!array) \
+    if (!array && arrayName) \
         free(arrayName); \
     arrayName = array; \
 } while (0)
diff --git a/lib/util/pm_c_util.h b/lib/util/pm_c_util.h
index f17d1e03..79897cf0 100644
--- a/lib/util/pm_c_util.h
+++ b/lib/util/pm_c_util.h
@@ -41,35 +41,49 @@
    use "int".
 */
 
-/* We used to assume that if TRUE was defined, then bool was too.
-   However, we had a report on 2001.09.21 of a Tru64 system that had
-   TRUE but not bool and on 2002.03.21 of an AIX 4.3 system that was
-   likewise.  So now we define bool all the time, unless the macro
-   HAVE_BOOL is defined.  If someone is using the Netpbm libraries and
-   also another library that defines bool, he can either make the
-   other library define/respect HAVE_BOOL or just define HAVE_BOOL in
-   the file that includes pm_config.h or with a compiler option.  Note
-   that C++ always has bool.  
+/* We will probably never again see a system that does not have
+   <stdbool.h>, but just in case, we have our own alternative here.
 
-   A preferred way of getting booleans is <stdbool.h>.  But it's not
-   available on all platforms, and it's easy to reproduce what it does
-   here.
+   Evidence shows that the compiler actually produces better code with
+   <stdbool.h> than with bool simply typedefed to int.
 */
+
+#ifdef __cplusplus
+  /* C++ has a bool type and false and true constants built in. */
+#else
+  /* The test for __STDC__ is paranoid.  It is there just in case some
+     nonstandard compiler defines __STDC_VERSION__ in an arbitrary manner.
+  */
+  #if ( defined(__GNUC__) && (__GNUC__ >= 3) ) || \
+      ( defined(__STDC__) && (__STDC__ ==1) && \
+        defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) ) 
+    #include <stdbool.h>
+  #else
+    /* We used to assume that if TRUE was defined, then bool was too.
+       However, we had a report on 2001.09.21 of a Tru64 system that had
+       TRUE but not bool and on 2002.03.21 of an AIX 4.3 system that was
+       likewise.  So now we define bool all the time, unless the macro
+       HAVE_BOOL is defined.  If someone is using the Netpbm libraries and
+       also another library that defines bool, he can either make the
+       other library define/respect HAVE_BOOL or just define HAVE_BOOL in
+       the file that includes pm_config.h or with a compiler option.  Note
+       that C++ always has bool.  
+    */
+    #ifndef HAVE_BOOL
+      #define HAVE_BOOL 1
+      typedef int bool;
+    #endif
+    #ifndef true
+      enum boolvalue {false=0, true=1};
+    #endif
+  #endif
+#endif
+
 #ifndef TRUE
-  #define TRUE 1
+  #define TRUE true
   #endif
 #ifndef FALSE
-  #define FALSE 0
-  #endif
-/* C++ has a bool type and false and true constants built in. */
-#ifndef __cplusplus
-  #ifndef HAVE_BOOL
-    #define HAVE_BOOL 1
-    typedef int bool;
-    #endif
-  #ifndef true
-    enum boolvalue {false=0, true=1};
-    #endif
+#define FALSE false
   #endif
 
 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
diff --git a/other/pamchannel.c b/other/pamchannel.c
index 48a2b2d7..3adb0e66 100644
--- a/other/pamchannel.c
+++ b/other/pamchannel.c
@@ -36,7 +36,7 @@ struct cmdlineInfo {
 
 
 static void
-parseCommandLine(int argc, char ** argv,
+parseCommandLine(int argc, const char ** argv,
                  struct cmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the file spec array we return is stored in the storage that
@@ -63,7 +63,7 @@ parseCommandLine(int argc, char ** argv,
     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, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (!infileSpec)
@@ -174,13 +174,13 @@ doOneImage(FILE *       const ifP,
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char *argv[]) {
 
     struct cmdlineInfo cmdline;
     FILE * ifP;
-    bool eof;
+    int eof;
 
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
     
diff --git a/other/pamdepth.c b/other/pamdepth.c
index 7b5de8b3..71dae9d8 100644
--- a/other/pamdepth.c
+++ b/other/pamdepth.c
@@ -28,7 +28,7 @@ struct cmdlineInfo {
 
 
 static void
-parseCommandLine(int argc, char ** argv,
+parseCommandLine(int argc, const char ** argv,
                  struct cmdlineInfo *cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the file spec strings we return are stored in the storage that
@@ -51,7 +51,7 @@ parseCommandLine(int argc, char ** argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We may have parms that are negative numbers */
 
-    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (argc-1 < 1)
@@ -133,16 +133,15 @@ transformRaster(struct pam * const inpamP,
 
 
 int
-main(int    argc,
-     char * argv[]) {
+main(int argc, const char * argv[]) {
 
     struct cmdlineInfo cmdline;
     FILE * ifP;
     struct pam inpam;
     struct pam outpam;
-    bool eof;
+    int eof;
 
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
diff --git a/other/pamexec.c b/other/pamexec.c
index 5961319b..d14d8752 100644
--- a/other/pamexec.c
+++ b/other/pamexec.c
@@ -159,7 +159,7 @@ main(int argc, const char *argv[]) {
     struct cmdlineInfo cmdline;
 
     FILE *       ifP;         /* Input file pointer */
-    bool         eof;         /* No more images in input */
+    int          eof;         /* No more images in input */
     unsigned int imageSeq;
         /* Sequence number of current image in input file.  First = 0.
            (Useful for tracking down problems).
diff --git a/other/pampick.c b/other/pampick.c
index 5229502d..61941f06 100644
--- a/other/pampick.c
+++ b/other/pampick.c
@@ -92,7 +92,7 @@ struct cmdlineInfo {
 
 
 static void
-parseCommandLine(int argc, char ** argv,
+parseCommandLine(int argc, const char ** argv,
                  struct cmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the pointers we place into *cmdlineP are sometimes to storage
@@ -119,7 +119,7 @@ parseCommandLine(int argc, char ** argv,
     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, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     initUintSet(&cmdlineP->imageSeqList, argc-1);
@@ -217,15 +217,15 @@ failIfUnpickedImages(const struct uintSet * const uintSetP,
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char *argv[]) {
 
     struct cmdlineInfo cmdline;
 
-    bool eof;  /* No more images in input */
+    int eof;  /* No more images in input */
     unsigned int imageSeq;  
         /* Sequence of current image in input file.  First = 0 */
 
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
     
diff --git a/other/pamsplit.c b/other/pamsplit.c
index 2c029d04..26eb0d59 100644
--- a/other/pamsplit.c
+++ b/other/pamsplit.c
@@ -155,7 +155,7 @@ main(int argc, const char *argv[]) {
     struct cmdlineInfo cmdline;
 
     FILE * ifP;
-    bool eof;  /* No more images in input */
+    int eof;  /* No more images in input */
     unsigned int imageSeq;  
         /* Sequence of current image in input file.  First = 0 */
 
diff --git a/other/pamstack.c b/other/pamstack.c
index e151d99b..308852c8 100644
--- a/other/pamstack.c
+++ b/other/pamstack.c
@@ -216,10 +216,10 @@ nextImageAllStreams(unsigned int const nInput,
     unsigned int inputSeq;
 
     for (inputSeq = 0; inputSeq < nInput; ++inputSeq) {
-        bool eof;
+        int eof;
         pnm_nextimage(ifP[inputSeq], &eof);
         if (eof)
-            *eofP = eof;
+            *eofP = true;
     }
 }
 
diff --git a/other/pnmcolormap.c b/other/pnmcolormap.c
index fca4a213..57db4329 100644
--- a/other/pnmcolormap.c
+++ b/other/pnmcolormap.c
@@ -655,7 +655,7 @@ addImageColorsToHash(struct pam *   const pamP,
         pnm_readpamrow(pamP, tuplerow);
 
         for (col = 0; col < pamP->width; ++col) {
-            bool firstOccurrence;
+            int firstOccurrence;
 
             pnm_addtuplefreqoccurrence(pamP, tuplerow[col], tuplehash,
                                        &firstOccurrence);
@@ -688,7 +688,7 @@ computeHistogram(FILE *         const ifP,
     struct pam firstPam;
     tuplehash tuplehash;
     unsigned int colorCount;
-    bool eof;
+    int eof;
     
     pm_message("making histogram...");
 
diff --git a/test/Execute-Tests b/test/Execute-Tests
index bec1cd56..39fab58c 100755
--- a/test/Execute-Tests
+++ b/test/Execute-Tests
@@ -53,6 +53,9 @@ fi
 
 srcdir=$(dirname $0)
 
+# Provision to run programs under valgrind.
+# export PBM_TESTPREFIX="valgrind --log-fd=4 "${PBM_TESTPREFIX}
+
 # Set tmpdir, which is used in some of the test scripts.  By default
 # this is created by mktemp.  The user can override and specify tmpdir,
 # but in this case it must be an existing directory and must not be
@@ -60,7 +63,7 @@ srcdir=$(dirname $0)
 
 if [ -z $tmpdir ]
   then
-  tmpdir_created=$(mktemp -d TestPBM-XXXXXXX) || exit 1;
+    tmpdir_created=$(mktemp -d) || exit 1;
   export tmpdir=${tmpdir_created}
   else
   tmpdir_created="";
@@ -90,7 +93,13 @@ declare -a status=("SUCCESS" "FAILURE" "UNEXPECTED SUCCESS"
 
 # Copy test files to the current work directory
 
-cp -n -t . ${srcdir}/testgrid.pbm ${srcdir}/testimg.ppm 
+if [ ! -f ./testgrid.pbm ]
+  then cp -v ${srcdir}/testgrid.pbm ./testgrid.pbm
+fi
+
+if [ ! -f ./testimg.ppm ]
+  then cp -v ${srcdir}/testimg.ppm  ./testimg.ppm 
+fi
 
 # Execute the tests, as described in the "Test-Order" file.
 #
@@ -103,31 +112,31 @@ cp -n -t . ${srcdir}/testgrid.pbm ${srcdir}/testimg.ppm
 #
 # All tests are self-contained.
 #
-# By defeault the tests are executed in the order described in the
-# file Test-Order.  Normally the Test-Order in the source directory
-# will be used, but the user can override this with a file named
-# Test-Order placed in the work directory.  (This feature comes useful
-# when you want to pare down the list.)
-
-if [ ! -f ./Test-Order ]
-then cp ${srcdir}/Test-Order ./Test-Order
-fi
+# By default the tests are executed in the order described in the
+# file Test-Order.  Copy this file from the source directory
+# to the work directory.
+# 
+# The --no-clobber version comes useful when the user wants a modified
+# (pared-down) version of Test-Order.
+
+cp ${srcdir}/Test-Order ./Test-Order
+#cp --no-clobber ${srcdir}/Test-Order ./Test-Order
 
 for t in `grep -v "^#" ./Test-Order | fgrep ".test"`
 do
 echo == $t ==
 ${srcdir}/$t >  ${t%.test}.out ; let result=$?
 case $result in
-0)   cmp --quiet ${t%.test}.out ${srcdir}/${t%.test}.ok ;
+0)   cmp -s ${t%.test}.out ${srcdir}/${t%.test}.ok ;
      if [ $? -eq 0 ]
         then let result=0;  rm  ${t%.test}.out ;
         else let result=1;
      fi
      let supported=1 ;;
-*) let result=1 ; let supported=1;;
+80) let result=4 ; let supported=0;;
+*)  let result=1 ; let supported=1;;
 esac
 
-
 # Report whether a single test succeeded or failed.
 # Increment counters.
 
@@ -168,7 +177,7 @@ for s in 0 1 2 3 4 5
 
 echo ==================
 echo "All tests done."
-date --rfc-3339=seconds
+date -R -u
 
 
 # Exit with status 0 if all supported tests succeeded, 1 otherwise.
diff --git a/test/Test-Order b/test/Test-Order
index a23bdd92..698552b9 100644
--- a/test/Test-Order
+++ b/test/Test-Order
@@ -16,7 +16,14 @@ pgmramp.test
 ppmgauss.test
 ppmcie.test
 ppmwheel.test
+
+# Generators with random components
+
+pgmnoise.test
 ppmpat.test
+pgmcrater.test
+ppmforge.test
+ppmrough.test
 
 # Analyzer tests
 
@@ -46,6 +53,7 @@ pnmcat.test
 pamflip.test
 pamenlarge.test
 pnminvert.test
+pamchannel.test
 
 pbmpscale.test
 pnmremap1.test
@@ -93,6 +101,7 @@ fits-roundtrip.test
 g3-roundtrip.test
 gem-roundtrip.test
 gif-roundtrip.test
+gif-quant-roundtrip.test
 hdiff-roundtrip.test
 leaf-roundtrip.test
 mgr-roundtrip.test
@@ -105,6 +114,7 @@ targa-roundtrip.test
 tiff-roundtrip.test
 utahrle-roundtrip.test
 wbmp-roundtrip.test
+winicon-roundtrip.test
 xbm-roundtrip.test
 xpm-roundtrip.test
 xwd-roundtrip.test
diff --git a/test/all-in-place.ok b/test/all-in-place.ok
index 75e1e01a..1510f2e7 100644
--- a/test/all-in-place.ok
+++ b/test/all-in-place.ok
@@ -102,6 +102,7 @@ pamtosvg: ok
 pamtotga: ok
 pamtotiff: ok
 pamtouil: ok
+pamtowinicon: ok
 pamtoxvmini: ok
 pamundice: ok
 pamwipeout: ok
@@ -329,6 +330,7 @@ ximtoppm: ok
 xpmtoppm: ok
 xvminitoppm: ok
 xwdtopnm: ok
+winicontopam: ok
 ybmtopbm: ok
 yuvsplittoppm: ok
 yuvtoppm: ok
@@ -348,3 +350,5 @@ ppmquant: ok
 ppmquantall: ok
 ppmrainbow: ok
 ppmfade: ok
+pamstretch-gen: ok
+pcdovtoppm: ok
diff --git a/test/all-in-place.test b/test/all-in-place.test
index ae67e809..87ddfad8 100755
--- a/test/all-in-place.test
+++ b/test/all-in-place.test
@@ -16,11 +16,15 @@ function testExitStatus () {
 
     case $3 in
       $2)  echo $1": ok" ;;
-      126) if [ ! -z ${PBM_TESTPREFIX} ] && [ ! -x ${PBM_TESTPREFIX}/$1 ]
+      126) if [ ! -z "${PBM_TESTPREFIX}" ] && \
+              [   -d "${PBM_TESTPREFIX}" ] && \
+              [ ! -x "${PBM_TESTPREFIX}/$1" ]
              then echo $1": NOT EXECUTABLE";
              else echo $1": ERROR: "$3;    echo $1": error: "$3 1>&2 ;
            fi ;;
-      127) if [ ! -z ${PBM_TESTPREFIX} ] && [ ! -f ${PBM_TESTPREFIX}/$1 ]
+      127) if [ ! -z "${PBM_TESTPREFIX}" ] && \
+              [   -d "${PBM_TESTPREFIX}" ] && \
+              [ ! -f "${PBM_TESTPREFIX}/$1" ]
              then echo $1": NO SUCH FILE";
              else echo $1": ERROR: "$3;    echo $1": error: "$3 1>&2 ;
            fi ;;
@@ -29,70 +33,350 @@ function testExitStatus () {
 }
 
 
-# Test programs which support the --version flag.
+# Test programs which have the --version flag.
 # See showVersion() in lib/libpm.c for the standard version announcement.
 
-for i in \
-  411toppm asciitopgm atktopbm avstopam bioradtopgm \
-  bmptopnm bmptoppm brushtopbm cameratopam cistopbm \
-  cmuwmtopbm ddbugtopbm escp2topbm eyuvtoppm fitstopnm \
-  fstopgm g3topbm gemtopbm gemtopnm giftopnm gouldtoppm \
-  hdifftopam hipstopgm icontopbm ilbmtoppm imgtoppm infotopam \
-  jbigtopnm jpeg2ktopam jpegtopnm leaftoppm lispmtopgm \
-  macptopbm mdatopbm mgrtopbm mrftopbm mtvtoppm neotoppm \
-  palmtopnm pamaddnoise pamarith pambackground pambayer \
-  pamchannel pamcomp pamcut pamdeinterlace pamdepth \
-  pamdice pamditherbw pamedge pamendian pamenlarge \
-  pamexec pamfile pamfixtrunc pamflip pamfunc pamgauss \
-  pamgradient pamlookup pammasksharpen pammixinterlace \
-  pammosaicknit pamoil pampaintspill pamperspective pampick \
-  pampop9 pamrecolor pamrgbatopng pamrubber pamscale pamseq \
-  pamsharpmap pamsharpness pamsistoaglyph pamslice pamsplit \
-  pamstack pamstereogram pamstretch pamsumm pamsummcol \
-  pamthreshold pamtilt pamtoavs pamtodjvurle pamtofits \
-  pamtogif pamtohdiff pamtohtmltbl pamtojpeg2k pamtompfont \
-  pamtooctaveimg pamtopam pamtopdbimg pamtopfm pamtopnm \
-  pamtosrf pamtosvg pamtotga pamtotiff pamtouil pamtoxvmini \
-  pamundice pamwipeout pamx pbmclean pbmlife pbmmake pbmmask \
-  pbmminkowski pbmpage pbmpscale pbmreduce pbmtext pbmtextps \
-  pbmto10x pbmto4425 pbmtoascii pbmtoatk pbmtobbnbg pbmtocis \
-  pbmtocmuwm pbmtodjvurle pbmtoepsi pbmtoepson pbmtoescp2 \
-  pbmtog3 pbmtogem pbmtogo pbmtoibm23xx pbmtoicon pbmtolj \
-  pbmtoln03 pbmtolps pbmtomacp pbmtomatrixorbital pbmtomda \
-  pbmtomgr pbmtomrf pbmtonokia pbmtopgm pbmtopi3 pbmtopk \
-  pbmtoplot pbmtoppa pbmtopsg3 pbmtoptx pbmtosunicon \
-  pbmtowbmp pbmtoxbm pbmtoybm pbmtozinc pbmupc pc1toppm \
-  pcxtoppm pdbimgtopam pfmtopam pgmabel pgmbentley pgmcrater \
-  pgmdeshadow pgmedge pgmenhance pgmhist pgmkernel pgmmake \
-  pgmmedian pgmminkowski pgmmorphconv pgmnoise pgmnorm \
-  pgmoil pgmramp pgmslice pgmtexture pgmtofs pgmtolispm \
-  pgmtopbm pgmtopgm pgmtoppm pi1toppm pi3topbm picttoppm \
-  pjtoppm pktopbm pngtopam pngtopnm pnmalias pnmarith pnmcat \
-  pnmcolormap pnmcomp pnmconvol pnmcrop pnmcut pnmdepth \
-  pnmenlarge pnmfile pnmflip pnmgamma pnmhisteq pnmhistmap \
-  pnmindex pnminterp pnminvert pnmmercator pnmmontage \
-  pnmnlfilt pnmnorm pnmpad pnmpaste pnmpsnr pnmremap \
-  pnmrotate pnmscale pnmscalefixed pnmshear pnmsmooth \
-  pnmsplit pnmstitch pnmtile pnmtoddif pnmtofiasco pnmtofits \
-  pnmtojbig pnmtojpeg pnmtopalm pnmtopclxl pnmtopng pnmtopnm \
-  pnmtops pnmtorast pnmtorle pnmtosgi pnmtosir pnmtotiff \
-  pnmtotiffcmyk pnmtoxwd ppm3d ppmbrighten ppmchange \
-  ppmcie ppmcolormask ppmcolors ppmdcfont ppmddumpfont \
-  ppmdim ppmdist ppmdither ppmdmkfont ppmdraw ppmflash \
-  ppmforge ppmglobe ppmhist ppmlabel ppmmake ppmmix ppmnorm \
-  ppmntsc ppmpat ppmrelief ppmrough ppmshift \
-  ppmspread ppmtoacad ppmtoapplevol ppmtoarbtxt ppmtoascii \
-  ppmtobmp ppmtoeyuv ppmtogif ppmtoicr ppmtoilbm ppmtojpeg \
-  ppmtoleaf ppmtolj ppmtomitsu ppmtompeg ppmtoneo ppmtopcx \
-  ppmtopgm ppmtopi1 ppmtopict ppmtopj ppmtopjxl ppmtoppm \
-  ppmtopuzz ppmtorgb3 ppmtosixel ppmtospu ppmtoterm ppmtouil \
-  ppmtowinicon ppmtoxpm ppmtoyuv ppmtoyuvsplit ppmtv ppmwheel \
-  psidtopgm pstopnm qrttoppm rasttopnm rawtopgm rawtoppm \
-  rgb3toppm rlatopam rletopnm sbigtopgm sgitopnm sirtopnm \
-  sldtoppm spctoppm spottopgm sputoppm srftopam sunicontopnm \
-  svgtopam tgatoppm thinkjettopbm tifftopnm wbmptopbm \
-  winicontoppm xbmtopbm ximtoppm xpmtoppm xvminitoppm \
-  xwdtopnm ybmtopbm yuvsplittoppm yuvtoppm zeisstopnm
+ordinary_testprogs="\
+  411toppm \
+  asciitopgm \
+  atktopbm \
+  avstopam \
+  bioradtopgm \
+  bmptopnm \
+  bmptoppm \
+  brushtopbm \
+  cameratopam \
+  cistopbm \
+  cmuwmtopbm \
+  ddbugtopbm \
+  escp2topbm \
+  eyuvtoppm \
+  fitstopnm \
+  fstopgm \
+  g3topbm \
+  gemtopbm \
+  gemtopnm \
+  giftopnm \
+  gouldtoppm \
+  hdifftopam \
+  hipstopgm \
+  icontopbm \
+  ilbmtoppm \
+  imgtoppm \
+  infotopam \
+  jbigtopnm \
+  jpeg2ktopam \
+  jpegtopnm \
+  leaftoppm \
+  lispmtopgm \
+  macptopbm \
+  mdatopbm \
+  mgrtopbm \
+  mrftopbm \
+  mtvtoppm \
+  neotoppm \
+  palmtopnm \
+  pamaddnoise \
+  pamarith \
+  pambackground \
+  pambayer \
+  pamchannel \
+  pamcomp \
+  pamcut \
+  pamdeinterlace \
+  pamdepth \
+  pamdice \
+  pamditherbw \
+  pamedge \
+  pamendian \
+  pamenlarge \
+  pamexec \
+  pamfile \
+  pamfixtrunc \
+  pamflip \
+  pamfunc \
+  pamgauss \
+  pamgradient \
+  pamlookup \
+  pammasksharpen \
+  pammixinterlace \
+  pammosaicknit \
+  pamoil \
+  pampaintspill \
+  pamperspective \
+  pampick \
+  pampop9 \
+  pamrecolor \
+  pamrgbatopng \
+  pamrubber \
+  pamscale \
+  pamseq \
+  pamsharpmap \
+  pamsharpness \
+  pamsistoaglyph \
+  pamslice \
+  pamsplit \
+  pamstack \
+  pamstereogram \
+  pamstretch \
+  pamsumm \
+  pamsummcol \
+  pamthreshold \
+  pamtilt \
+  pamtoavs \
+  pamtodjvurle \
+  pamtofits \
+  pamtogif \
+  pamtohdiff \
+  pamtohtmltbl \
+  pamtojpeg2k \
+  pamtompfont \
+  pamtooctaveimg \
+  pamtopam \
+  pamtopdbimg \
+  pamtopfm \
+  pamtopnm \
+  pamtosrf \
+  pamtosvg \
+  pamtotga \
+  pamtotiff \
+  pamtouil \
+  pamtowinicon \
+  pamtoxvmini \
+  pamundice \
+  pamwipeout \
+  pamx \
+  pbmclean \
+  pbmlife \
+  pbmmake \
+  pbmmask \
+  pbmminkowski \
+  pbmpage \
+  pbmpscale \
+  pbmreduce \
+  pbmtext \
+  pbmtextps \
+  pbmto10x \
+  pbmto4425 \
+  pbmtoascii \
+  pbmtoatk \
+  pbmtobbnbg \
+  pbmtocis \
+  pbmtocmuwm \
+  pbmtodjvurle \
+  pbmtoepsi \
+  pbmtoepson \
+  pbmtoescp2 \
+  pbmtog3 \
+  pbmtogem \
+  pbmtogo \
+  pbmtoibm23xx \
+  pbmtoicon \
+  pbmtolj \
+  pbmtoln03 \
+  pbmtolps \
+  pbmtomacp \
+  pbmtomatrixorbital \
+  pbmtomda \
+  pbmtomgr \
+  pbmtomrf \
+  pbmtonokia \
+  pbmtopgm \
+  pbmtopi3 \
+  pbmtopk \
+  pbmtoplot \
+  pbmtoppa \
+  pbmtopsg3 \
+  pbmtoptx \
+  pbmtosunicon \
+  pbmtowbmp \
+  pbmtoxbm \
+  pbmtoybm \
+  pbmtozinc \
+  pbmupc \
+  pc1toppm \
+  pcxtoppm \
+  pdbimgtopam \
+  pfmtopam \
+  pgmabel \
+  pgmbentley \
+  pgmcrater \
+  pgmdeshadow \
+  pgmedge \
+  pgmenhance \
+  pgmhist \
+  pgmkernel \
+  pgmmake \
+  pgmmedian \
+  pgmminkowski \
+  pgmmorphconv \
+  pgmnoise \
+  pgmnorm \
+  pgmoil \
+  pgmramp \
+  pgmslice \
+  pgmtexture \
+  pgmtofs \
+  pgmtolispm \
+  pgmtopbm \
+  pgmtopgm \
+  pgmtoppm \
+  pi1toppm \
+  pi3topbm \
+  picttoppm \
+  pjtoppm \
+  pktopbm \
+  pngtopam \
+  pngtopnm \
+  pnmalias \
+  pnmarith \
+  pnmcat \
+  pnmcolormap \
+  pnmcomp \
+  pnmconvol \
+  pnmcrop \
+  pnmcut \
+  pnmdepth \
+  pnmenlarge \
+  pnmfile \
+  pnmflip \
+  pnmgamma \
+  pnmhisteq \
+  pnmhistmap \
+  pnmindex \
+  pnminterp \
+  pnminvert \
+  pnmmercator \
+  pnmmontage \
+  pnmnlfilt \
+  pnmnorm \
+  pnmpad \
+  pnmpaste \
+  pnmpsnr \
+  pnmremap \
+  pnmrotate \
+  pnmscale \
+  pnmscalefixed \
+  pnmshear \
+  pnmsmooth \
+  pnmsplit \
+  pnmstitch \
+  pnmtile \
+  pnmtoddif \
+  pnmtofiasco \
+  pnmtofits \
+  pnmtojbig \
+  pnmtojpeg \
+  pnmtopalm \
+  pnmtopclxl \
+  pnmtopng \
+  pnmtopnm \
+  pnmtops \
+  pnmtorast \
+  pnmtorle \
+  pnmtosgi \
+  pnmtosir \
+  pnmtotiff \
+  pnmtotiffcmyk \
+  pnmtoxwd \
+  ppm3d \
+  ppmbrighten \
+  ppmchange \
+  ppmcie \
+  ppmcolormask \
+  ppmcolors \
+  ppmdcfont \
+  ppmddumpfont \
+  ppmdim \
+  ppmdist \
+  ppmdither \
+  ppmdmkfont \
+  ppmdraw \
+  ppmflash \
+  ppmforge \
+  ppmglobe \
+  ppmhist \
+  ppmlabel \
+  ppmmake \
+  ppmmix \
+  ppmnorm \
+  ppmntsc \
+  ppmpat \
+  ppmrelief \
+  ppmrough \
+  ppmshift \
+  ppmspread \
+  ppmtoacad \
+  ppmtoapplevol \
+  ppmtoarbtxt \
+  ppmtoascii \
+  ppmtobmp \
+  ppmtoeyuv \
+  ppmtogif \
+  ppmtoicr \
+  ppmtoilbm \
+  ppmtojpeg \
+  ppmtoleaf \
+  ppmtolj \
+  ppmtomitsu \
+  ppmtompeg \
+  ppmtoneo \
+  ppmtopcx \
+  ppmtopgm \
+  ppmtopi1 \
+  ppmtopict \
+  ppmtopj \
+  ppmtopjxl \
+  ppmtoppm \
+  ppmtopuzz \
+  ppmtorgb3 \
+  ppmtosixel \
+  ppmtospu \
+  ppmtoterm \
+  ppmtouil \
+  ppmtowinicon \
+  ppmtoxpm \
+  ppmtoyuv \
+  ppmtoyuvsplit \
+  ppmtv \
+  ppmwheel \
+  psidtopgm \
+  pstopnm \
+  qrttoppm \
+  rasttopnm \
+  rawtopgm \
+  rawtoppm \
+  rgb3toppm \
+  rlatopam \
+  rletopnm \
+  sbigtopgm \
+  sgitopnm \
+  sirtopnm \
+  sldtoppm \
+  spctoppm \
+  spottopgm \
+  sputoppm \
+  srftopam \
+  sunicontopnm \
+  svgtopam \
+  tgatoppm \
+  thinkjettopbm \
+  tifftopnm \
+  wbmptopbm \
+  winicontopam \
+  winicontoppm \
+  xbmtopbm \
+  ximtoppm \
+  xpmtoppm \
+  xvminitoppm \
+  xwdtopnm \
+  ybmtopbm \
+  yuvsplittoppm \
+  yuvtoppm \
+  zeisstopnm \
+"
+
+for i in $ordinary_testprogs
   do
     ${PBM_TESTPREFIX}$i --version  2>&1 | \
     egrep -v \
@@ -110,7 +394,7 @@ ${PBM_TESTPREFIX}fiascotopnm -v 2> /dev/null
 
 
 
-# Test manweb and pnmmargin, which support --help.
+# Test manweb and pnmmargin, which have --help.
 
 ${PBM_TESTPREFIX}manweb --help > /dev/null
     testExitStatus manweb 0 $?
@@ -159,6 +443,18 @@ ${PBM_TESTPREFIX}ppmfade -f /dev/zero -base /dev/null > /dev/null 2> /dev/null
 
 
 
+# Test pamstretch-gen and pcdovtoppm with no input.
+# These two programs write a usage message on standout in this case.
+# Exit status should be 1.
+
+for i in pamstretch-gen pcdovtoppm
+  do
+  ${PBM_TESTPREFIX}$i > /dev/zero
+     testExitStatus $i 1 $?
+  done
+
+
+
 # We do not test hpcdtoppm.
 # This is a stand-in which announces the absence of the real hpcdtoppm.
 # TODO: Provide for the case in which the real hpcdtoppm is encountered.
diff --git a/test/g3-roundtrip.test b/test/g3-roundtrip.test
index c5c21fa0..e00997f6 100755
--- a/test/g3-roundtrip.test
+++ b/test/g3-roundtrip.test
@@ -3,11 +3,13 @@
 # Also requires: pnmcrop
 
 ${PBM_TESTPREFIX}pbmtog3 -nofixedwidth testgrid.pbm | \
-${PBM_TESTPREFIX}g3topbm -width=14 | diff - testgrid.pbm ; echo $?
+${PBM_TESTPREFIX}g3topbm -width=14 | cmp -s - testgrid.pbm
+echo $?
 
 ${PBM_TESTPREFIX}pbmtog3 -nofixedwidth -reversebits testgrid.pbm | \
-${PBM_TESTPREFIX}g3topbm -width=14 -reversebits | diff - testgrid.pbm ; echo $?
+${PBM_TESTPREFIX}g3topbm -width=14 -reversebits | cmp -s - testgrid.pbm
+echo $?
 
 ${PBM_TESTPREFIX}pbmtog3 testgrid.pbm | \
 ${PBM_TESTPREFIX}g3topbm  | ${PBM_BINPREFIX}pnmcrop -white -right -bottom | \
- diff - testgrid.pbm ; echo $?
+ cmp -s - testgrid.pbm ; echo $?
diff --git a/test/gem-roundtrip.test b/test/gem-roundtrip.test
index 9548637a..05f1d28c 100755
--- a/test/gem-roundtrip.test
+++ b/test/gem-roundtrip.test
@@ -1,6 +1,6 @@
 #! /bin/bash
 # This script tests: pbmtogem gemtopbm
-# Also requires: 
+# Also requires: gemtopnm
 
 # Should print 2425386270 41, cksum of testgrid.pbm
 ${PBM_TESTPREFIX}pbmtogem testgrid.pbm | ${PBM_TESTPREFIX}gemtopbm | cksum
diff --git a/test/gif-quant-roundtrip.ok b/test/gif-quant-roundtrip.ok
new file mode 100644
index 00000000..573541ac
--- /dev/null
+++ b/test/gif-quant-roundtrip.ok
@@ -0,0 +1 @@
+0
diff --git a/test/gif-quant-roundtrip.test b/test/gif-quant-roundtrip.test
new file mode 100644
index 00000000..5e093b29
--- /dev/null
+++ b/test/gif-quant-roundtrip.test
@@ -0,0 +1,15 @@
+#! /bin/bash
+# This script tests: giftopnm pamtogif pnmquant
+# Also requires: pnmcolormap pnmremap
+
+# Should print 0
+
+colors=15      # any value between 2 - 256 works
+
+${PBM_TESTPREFIX}pnmquant $colors testimg.ppm > ${tmpdir}/quant.ppm &&
+${PBM_TESTPREFIX}pamtogif ${tmpdir}/quant.ppm | ${PBM_TESTPREFIX}giftopnm | \
+   cmp -s - ${tmpdir}/quant.ppm > /dev/null
+echo $?
+
+rm ${tmpdir}/quant.ppm
+
diff --git a/test/gif-roundtrip.ok b/test/gif-roundtrip.ok
index 011ebd3a..cf95bb37 100644
--- a/test/gif-roundtrip.ok
+++ b/test/gif-roundtrip.ok
@@ -1,3 +1,4 @@
 2871603838 33838
 1926073387 101484
 2425386270 41
+P1 4 1 0101 
\ No newline at end of file
diff --git a/test/gif-roundtrip.test b/test/gif-roundtrip.test
index 73246705..a32d574a 100755
--- a/test/gif-roundtrip.test
+++ b/test/gif-roundtrip.test
@@ -1,6 +1,6 @@
 #! /bin/bash
 # This script tests: giftopnm pamtogif
-# Also requires: ppmtopgm ppmtorgb3 rgb3toppm
+# Also requires: ppmtopgm ppmtorgb3 rgb3toppm pbmmake
 
 # Test 1. Should produce 2871603838 33838
 # which is the result of ppmtopgm testimg.ppm | cksum
@@ -28,3 +28,12 @@ rm ${tmpdir}/testimg.{ppm,red,grn,blu} ${tmpdir}/out.{red,grn}
 
 # Test 3. Should produce 2425386270 41
 ${PBM_TESTPREFIX}pamtogif testgrid.pbm | ${PBM_TESTPREFIX}giftopnm | cksum
+
+# Test 4.
+# In this gif file the code length changes after the last image data.
+# Image data: 3 bits, end code 4 bits.
+# Should produce P1 4 1 0 1 0 1
+
+${PBM_BINPREFIX}pbmmake -g 4 1 | \
+  ${PBM_TESTPREFIX}pamtogif | ${PBM_TESTPREFIX}giftopnm -plain | \
+  tr '\n' ' '
diff --git a/test/pad-crop-roundtrip.test b/test/pad-crop-roundtrip.test
index 532b6cbd..2b3c777b 100755
--- a/test/pad-crop-roundtrip.test
+++ b/test/pad-crop-roundtrip.test
@@ -1,6 +1,6 @@
 #! /bin/bash
 # This script tests: pnmcrop pnmmargin
-# Also requires: 
+# Also requires: pnmpad
 
 ${PBM_TESTPREFIX}pnmmargin -white 10 testimg.ppm | \
   ${PBM_TESTPREFIX}pnmcrop | cksum
diff --git a/test/pamchannel.ok b/test/pamchannel.ok
new file mode 100644
index 00000000..79317f03
--- /dev/null
+++ b/test/pamchannel.ok
@@ -0,0 +1,3 @@
+1571496937 33838
+394856971 33838
+3164158573 33838
diff --git a/test/pamchannel.test b/test/pamchannel.test
new file mode 100644
index 00000000..f83dd3b6
--- /dev/null
+++ b/test/pamchannel.test
@@ -0,0 +1,32 @@
+#! /bin/bash
+# This script tests: pamchannel
+# Also requires: pamtopnm
+
+
+# Extract planes one by one.
+# Convert output to pgm to make it identical to ppmtorgb3 output.
+
+# $ ppmtorgb3 testimg.ppm ; cksum testimg.{red,grn,blu}
+#
+# 1571496937 33838 testimg.red
+# 394856971 33838 testimg.grn
+# 3164158573 33838 testimg.blu
+
+
+# Test 1. red channel
+# Should produce 1571496937 33838
+
+${PBM_TESTPREFIX}pamchannel -infile testimg.ppm 0 | \
+  ${PBM_BINPREFIX}pamtopnm --assume | cksum
+
+# Test 2. green channel
+# Should produce  394856971 33838
+
+${PBM_TESTPREFIX}pamchannel -infile testimg.ppm 1 | \
+  ${PBM_BINPREFIX}pamtopnm --assume | cksum
+
+# Test 3. blue channel
+# Should produce 3164158573 33838
+
+${PBM_TESTPREFIX}pamchannel -infile testimg.ppm 2 | \
+  ${PBM_BINPREFIX}pamtopnm --assume | cksum
diff --git a/test/pamslice-roundtrip.test b/test/pamslice-roundtrip.test
index fd125500..d7ca657d 100755
--- a/test/pamslice-roundtrip.test
+++ b/test/pamslice-roundtrip.test
@@ -1,6 +1,6 @@
 #! /bin/bash
 # This script tests: pamslice
-# Also requires: pnmtopnm
+# Also requires: pnmtopnm pamtopnm
 
 # Slice rows, one by one, out of testgrid.pbm.
 # Add header and reconstruct pbm image.
diff --git a/test/pbmclean.test b/test/pbmclean.test
index 05fe9338..69081ff9 100755
--- a/test/pbmclean.test
+++ b/test/pbmclean.test
@@ -1,6 +1,6 @@
 #! /bin/bash
 # This script tests: pbmclean
-# Also requires: pbmmake pbmpage pnmmargin
+# Also requires: pbmmake pbmpage pnmmargin pnmpad
 
 ${PBM_BINPREFIX}pbmmake -g 3 3 | ${PBM_BINPREFIX}pnmmargin -black 2 \
  >${tmpdir}/test.pbm
diff --git a/test/pbmminkowski.test b/test/pbmminkowski.test
index d0376e9e..ccb882b1 100755
--- a/test/pbmminkowski.test
+++ b/test/pbmminkowski.test
@@ -1,6 +1,6 @@
 #! /bin/bash
 # This script tests: pbmminkowski
-# Also requires: pbmmake pnmmargin
+# Also requires: pbmmake pnmmargin pnmpad
 
 ${PBM_BINPREFIX}pbmmake -w 1 1 | ${PBM_BINPREFIX}pnmmargin -b 1 | \
   ${PBM_TESTPREFIX}pbmminkowski
diff --git a/test/pgmcrater.ok b/test/pgmcrater.ok
new file mode 100644
index 00000000..aa2592c9
--- /dev/null
+++ b/test/pgmcrater.ok
@@ -0,0 +1 @@
+3828822912 65551
diff --git a/test/pgmcrater.test b/test/pgmcrater.test
new file mode 100644
index 00000000..e8df9a23
--- /dev/null
+++ b/test/pgmcrater.test
@@ -0,0 +1,29 @@
+#! /bin/bash
+# This script tests: pgmcrater
+# Also requires: pgmnoise
+
+# This test is sensitive to differences in floating point math.
+# With GCC slight results start to appear with -number 75 in
+# the following test.  Compiler type (GCC, Clang, etc.),
+# SSE math (by default off with x86 32 bit on with x86 64 bit)
+# and --ffast-math are factors.
+
+# We hope that by keeping the number of craters small the
+# difference will not show up.
+#
+# The slight differences in the image file are not discernable by
+# the naked eye.
+
+${PBM_BINPREFIX}pgmnoise --testrandom --quiet
+case $? in
+   81)
+      # Should print: 3828822912 65551
+      ${PBM_TESTPREFIX}pgmcrater -quiet -number 25 -randomseed 1 | cksum
+      ;;
+
+   8[02-9] | 90)
+       echo "Skipping: random number generator is not glibc." 1>&2
+       exit 80;;
+
+   *)  exit 1;;  # pgmnoise --testrandom failed
+esac
diff --git a/test/pgmnoise.ok b/test/pgmnoise.ok
new file mode 100644
index 00000000..138218c2
--- /dev/null
+++ b/test/pgmnoise.ok
@@ -0,0 +1 @@
+2005134911 10015
diff --git a/test/pgmnoise.test b/test/pgmnoise.test
new file mode 100644
index 00000000..8ee2fccc
--- /dev/null
+++ b/test/pgmnoise.test
@@ -0,0 +1,22 @@
+#! /bin/bash
+# This script tests: pgmnoise
+# Also requires: 
+
+# We first check whether random number generator is glibc rand().
+# If not, this test is skipped.
+
+${PBM_TESTPREFIX}pgmnoise --testrandom
+
+case $? in
+   81)
+        # Should print: 1663614689 10015
+        ${PBM_TESTPREFIX}pgmnoise --randomseed=0 100 100 | cksum ;;
+
+        # Any additional tests go here.
+
+   8[02-9] | 90)
+        echo "Skipping: random number generator is not glibc." 1>&2
+        exit 80;;
+
+   *)   exit 1;;  # pgmnoise --testrandom failed
+esac
diff --git a/test/pnm-plain-roundtrip.test b/test/pnm-plain-roundtrip.test
index eab0b0d7..86dbb2fb 100755
--- a/test/pnm-plain-roundtrip.test
+++ b/test/pnm-plain-roundtrip.test
@@ -1,6 +1,6 @@
 #! /bin/bash
 # This script tests: pnmtopnm
-# Also requires: 
+# Also requires: pamtopnm
 
 ${PBM_TESTPREFIX}pnmtopnm -plain testimg.ppm | \
   ${PBM_TESTPREFIX}pnmtopnm | cksum
diff --git a/test/pnmremap1.ok b/test/pnmremap1.ok
index a6cfc2bd..07954684 100644
--- a/test/pnmremap1.ok
+++ b/test/pnmremap1.ok
@@ -1 +1 @@
-2667816854 101482
+3602410851 101482
diff --git a/test/pnmtile.test b/test/pnmtile.test
index b0c14ca6..0f9d91df 100755
--- a/test/pnmtile.test
+++ b/test/pnmtile.test
@@ -7,6 +7,7 @@ ${PBM_TESTPREFIX}pnmtile 40 50 testgrid.pbm | cksum
 ${PBM_TESTPREFIX}pnmtile 454 298 testimg.ppm > ${tmpdir}/testimg4.ppm &&
 ${PBM_BINPREFIX}pnmcat -lr testimg.ppm testimg.ppm > ${tmpdir}/testimg2.ppm &&
 ${PBM_BINPREFIX}pnmcat -tb ${tmpdir}/testimg2.ppm ${tmpdir}/testimg2.ppm | \
-diff - ${tmpdir}/testimg4.ppm && echo $?
+cmp -s - ${tmpdir}/testimg4.ppm
+echo $?
 
 rm ${tmpdir}/testimg{2,4}.ppm
diff --git a/test/pnmtopnm-plain.test b/test/pnmtopnm-plain.test
index 3cbd5752..ff211e40 100755
--- a/test/pnmtopnm-plain.test
+++ b/test/pnmtopnm-plain.test
@@ -1,6 +1,6 @@
 #! /bin/bash
 # This script tests: pnmtopnm
-# Also requires: pgmtopgm ppmtoppm
+# Also requires: pgmtopgm ppmtoppm pamtopnm
 
 ${PBM_TESTPREFIX}pnmtopnm -plain testgrid.pbm
 
diff --git a/test/ppmcie.out-64 b/test/ppmcie.out-64
deleted file mode 100644
index 3d8ca13a..00000000
--- a/test/ppmcie.out-64
+++ /dev/null
@@ -1 +0,0 @@
-2583941766 786447
diff --git a/test/ppmdfont.test b/test/ppmdfont.test
index e973297b..027b8f2c 100755
--- a/test/ppmdfont.test
+++ b/test/ppmdfont.test
@@ -7,3 +7,13 @@ ${PBM_TESTPREFIX}ppmdmkfont | ${PBM_TESTPREFIX}ppmddumpfont 2>&1 | cksum
 
 # Test 2. Should produce: 2845495212 75033
 ${PBM_TESTPREFIX}ppmdmkfont | ${PBM_TESTPREFIX}ppmdcfont | cksum
+
+# There is a strange glitch in output when ppmdcfont is compiled by clang:
+# 3171,3173c3171,3173
+# <     0x01,
+# <     95,
+# <     32
+# ---
+# >     0x00,
+# >     0,
+# >     0
diff --git a/test/ppmdim.test b/test/ppmdim.test
index b8158d63..e2a1b0df 100755
--- a/test/ppmdim.test
+++ b/test/ppmdim.test
@@ -1,6 +1,6 @@
 #! /bin/bash
 # This script tests: ppmdim
-# Also requires: pamfunc pnmarith pamsumm
+# Also requires: pamfunc pnmarith pamarith pamsumm
 
 # Compare ppmdim and pamfunc with various dim factors
 # Due to the difference in rounding methods, pamfunc produces slightly
diff --git a/test/ppmforge.ok b/test/ppmforge.ok
new file mode 100644
index 00000000..e4a4c9e2
--- /dev/null
+++ b/test/ppmforge.ok
@@ -0,0 +1 @@
+3634219838 196623
diff --git a/test/ppmforge.test b/test/ppmforge.test
new file mode 100644
index 00000000..014dc543
--- /dev/null
+++ b/test/ppmforge.test
@@ -0,0 +1,20 @@
+#! /bin/bash
+# This script tests: ppmforge
+# Also requires: pgmnoise
+
+# Use small x y values to avoid floating point issues.
+
+
+${PBM_BINPREFIX}pgmnoise --testrandom --quiet
+case $? in
+   81)
+      # Test 1: Should print: 3634219838 196623
+      ${PBM_TESTPREFIX}ppmforge -night -seed 1 | cksum
+      ;;
+
+   8[02-9] | 90)
+       echo "Skipping: random number generator is not glibc." 1>&2
+       exit 80;;
+
+   *)  exit 1;;  # pgmnoise --testrandom failed
+esac
diff --git a/test/ppmhist.test b/test/ppmhist.test
index b849e72d..55cbeac9 100755
--- a/test/ppmhist.test
+++ b/test/ppmhist.test
@@ -1,6 +1,6 @@
 #! /bin/bash
 # This script tests: ppmhist
-# Also requires: pgmhist pgmramp
+# Also requires: pgmramp
 
 ${PBM_BINPREFIX}pgmramp -maxval=8 -lr 8 2 | ${PBM_TESTPREFIX}ppmhist
 ${PBM_TESTPREFIX}ppmhist -map -sort=rgb testimg.ppm | cksum
diff --git a/test/ppmmake.test b/test/ppmmake.test
index 02e747ab..da23095c 100755
--- a/test/ppmmake.test
+++ b/test/ppmmake.test
@@ -2,8 +2,6 @@
 # This script tests: ppmmake
 # Also requires: 
 
-#export RGBDEF=/usr/share/emacs/23.2/etc/rgb.txt
-
 ${PBM_TESTPREFIX}ppmmake rgb:ff/80/80 50 100 -maxval=5 | cksum
 ${PBM_TESTPREFIX}ppmmake red 50 50  | cksum
 
diff --git a/test/ppmmix.test b/test/ppmmix.test
index 0f9deedc..451aa8be 100755
--- a/test/ppmmix.test
+++ b/test/ppmmix.test
@@ -25,5 +25,4 @@ ${PBM_BINPREFIX}pnminvert testimg.ppm | ${PBM_TESTPREFIX}ppmmix .5 \
     testimg.ppm - | tee ${tmpdir}/a3.ppm | \
   ${PBM_BINPREFIX}pamsumm -brief -max &&
   ${PBM_BINPREFIX}pamsumm -brief -min ${tmpdir}/a3.ppm &&
-
 rm ${tmpdir}/a3.ppm
diff --git a/test/ppmpat.test b/test/ppmpat.test
index 0fe9f25a..669cf17c 100755
--- a/test/ppmpat.test
+++ b/test/ppmpat.test
@@ -1,28 +1,35 @@
 #! /bin/bash
 # This script tests: ppmpat
-# Also requires:
+# Also requires: pgmnoise
 
-# TODO 1: Write tests for squig and poles.  It appears that they are
+# TODO: Write tests for squig and poles.  It appears that they are
 # sensitive to differences in floating point math.
 
-# TODO 2: Skip this test if the pseudo-random number generator is
-# not glibc's rand().
+${PBM_BINPREFIX}pgmnoise --testrandom --quiet
+case $? in
+   81)
+       # Test 1. Should print: 4008533639 781
+       ${PBM_TESTPREFIX}ppmpat --randomseed=0 -g2 16 16 | cksum
 
+       # Test 2. Should print: 2448908863 9613
+       ${PBM_TESTPREFIX}ppmpat --randomseed=0 -g2 64 50 | cksum
 
-# Test 1. Should print: 4008533639 781
-${PBM_TESTPREFIX}ppmpat --randomseed=0 -g2 16 16 | cksum
+       # Test 3. Should print: 2698433077 1549
+       ${PBM_TESTPREFIX}ppmpat --randomseed=0 -madras 32 16 | cksum
 
-# Test 2. Should print: 2448908863 9613
-${PBM_TESTPREFIX}ppmpat --randomseed=0 -g2 64 50 | cksum
+       # Test 4. Should print: 3705929501 781
+       ${PBM_TESTPREFIX}ppmpat --randomseed=0 -tartan 16 16 | cksum
 
-# Test 3. Should print: 2698433077 1549
-${PBM_TESTPREFIX}ppmpat --randomseed=0 -madras 32 16 | cksum
+       # Test 5. Should print: 2219119109 36015
+       ${PBM_TESTPREFIX}ppmpat --randomseed=0 -camo 100 120 | cksum
 
-# Test 4. Should print: 3705929501 781
-${PBM_TESTPREFIX}ppmpat --randomseed=0 -tartan 16 16 | cksum
+       # Test 6. Should print: 3436846137 16813
+       ${PBM_TESTPREFIX}ppmpat --randomseed=0 -anticamo 80 70 | cksum
+       ;;
 
-# Test 5. Should print: 2219119109 36015
-${PBM_TESTPREFIX}ppmpat --randomseed=0 -camo 100 120 | cksum
+   8[02-9] | 90)
+       echo "Skipping: random number generator is not glibc." 1>&2
+       exit 80;;
 
-# Test 6. Should print: 3436846137 16813
-${PBM_TESTPREFIX}ppmpat --randomseed=0 -anticamo 80 70 | cksum
+   *)  exit 1;;  # pgmnoise --testrandom failed
+esac
diff --git a/test/ppmrough.ok b/test/ppmrough.ok
new file mode 100644
index 00000000..83643849
--- /dev/null
+++ b/test/ppmrough.ok
@@ -0,0 +1 @@
+378403602 30015
diff --git a/test/ppmrough.test b/test/ppmrough.test
new file mode 100644
index 00000000..1de8dd1b
--- /dev/null
+++ b/test/ppmrough.test
@@ -0,0 +1,18 @@
+#! /bin/bash
+# This script tests: ppmrough
+# Also requires: pgmnoise
+
+
+${PBM_BINPREFIX}pgmnoise --testrandom --quiet
+case $? in
+   81)
+      # Should print: 378403602 30015
+      ${PBM_TESTPREFIX}ppmrough  -randomseed 1 | cksum
+      ;;
+
+   8[02-9] | 90)
+       echo "Skipping: random number generator is not glibc." 1>&2
+       exit 80;;
+
+   *)  exit 1;;  # pgmnoise --testrandom failed
+esac
diff --git a/test/ps-roundtrip.ok b/test/ps-roundtrip.ok
index 67f7a1fe..a267f7eb 100644
--- a/test/ps-roundtrip.ok
+++ b/test/ps-roundtrip.ok
@@ -1,2 +1,3 @@
 1926073387 101484
 2425386270 41
+1386192571 507420
diff --git a/test/ps-roundtrip.test b/test/ps-roundtrip.test
index 6d6935af..60ecf60a 100755
--- a/test/ps-roundtrip.test
+++ b/test/ps-roundtrip.test
@@ -1,21 +1,38 @@
 #! /bin/bash
 # This script tests: pnmtops pstopnm
-# Also requires: pnmtopnm
+# Also requires: pnmtopnm pamtopnm gs
 
+# Test 1.  Should print: 1926073387 101484
 ${PBM_TESTPREFIX}pnmtops -nocenter -equalpixels -dpi 72 -noturn testimg.ppm \
   > ${tmpdir}/testimg.ps
-xysize=`awk  '/BoundingBox/ {print "-xsize="$4,"-ysize="$5}' \
+xysize1=`awk  '/BoundingBox/ {print "-xsize="$4,"-ysize="$5}' \
   ${tmpdir}/testimg.ps` 
-${PBM_TESTPREFIX}pstopnm -xborder=0 -yborder=0 $xysize -stdout \
+${PBM_TESTPREFIX}pstopnm -xborder=0 -yborder=0 $xysize1 -stdout \
   -quiet ${tmpdir}/testimg.ps | \
   ${PBM_BINPREFIX}pnmtopnm | cksum
 
-${PBM_TESTPREFIX}pnmtops -nocenter -equalpixels -dpi 72 -noturn testgrid.pbm \
-  > ${tmpdir}/testgrid.ps
-xysize=`awk  '/BoundingBox/ {print "-xsize="$4,"-ysize="$5}' \
+
+# Test 2.  Should print: 2425386270 41
+${PBM_TESTPREFIX}pnmtops -nocenter -equalpixels -dpi 72 -noturn \
+  testgrid.pbm  > ${tmpdir}/testgrid.ps &&
+xysize2=`awk  '/BoundingBox/ {print "-xsize="$4,"-ysize="$5}' \
   ${tmpdir}/testgrid.ps`
-${PBM_TESTPREFIX}pstopnm -xborder=0 -yborder=0 $xysize -stdout \
+${PBM_TESTPREFIX}pstopnm -xborder=0 -yborder=0 $xysize2 -stdout \
   -quiet ${tmpdir}/testgrid.ps -pbm | \
   ${PBM_BINPREFIX}pnmtopnm | cksum
 
-rm  ${tmpdir}/testgrid.ps  ${tmpdir}/testimg.ps
+
+#Test 3. Should print: 1386192571 507420
+cat testimg.ppm testimg.ppm testimg.ppm testgrid.pbm testgrid.pbm | \
+${PBM_TESTPREFIX}pnmtops -nocenter -equalpixels -dpi 72 -noturn -setpage \
+  > ${tmpdir}/testimg5.ps
+xysize3=`awk  '/BoundingBox/ {print "-xsize="$4,"-ysize="$5 ; exit}' \
+  ${tmpdir}/testimg5.ps`
+${PBM_TESTPREFIX}pstopnm -xborder=0 -yborder=0 $xysize3 \
+    -stdout  ${tmpdir}/testimg5.ps | \
+  ${PBM_BINPREFIX}pnmtopnm | cksum
+
+
+#rm  ${tmpdir}/testgrid.ps  ${tmpdir}/testimg.ps  ${tmpdir}/testimg5.ps
+rm   ${tmpdir}/testimg.ps  ${tmpdir}/testimg5.ps
+mv ${tmpdir}/testgrid.ps /tmp
diff --git a/test/rgb3-roundtrip.ok b/test/rgb3-roundtrip.ok
index 745a7c5f..64da849d 100644
--- a/test/rgb3-roundtrip.ok
+++ b/test/rgb3-roundtrip.ok
@@ -1,4 +1,5 @@
 1926073387 101484
+3744829044 101514
 2425386270 41
 0
 0
diff --git a/test/rgb3-roundtrip.test b/test/rgb3-roundtrip.test
index 9cc45499..d3575b95 100755
--- a/test/rgb3-roundtrip.test
+++ b/test/rgb3-roundtrip.test
@@ -11,6 +11,9 @@ ${PBM_TESTPREFIX}ppmtorgb3 ${tmpdir}/testimg.ppm &&
 ${PBM_TESTPREFIX}rgb3toppm ${tmpdir}/testimg.red ${tmpdir}/testimg.grn \
   ${tmpdir}/testimg.blu | cksum
 
+cat ${tmpdir}/testimg.red ${tmpdir}/testimg.grn ${tmpdir}/testimg.blu | \
+  cksum
+
 rm ${tmpdir}/testimg.{ppm,red,grn,blu}
 
 cp testgrid.pbm ${tmpdir} &&
@@ -23,9 +26,9 @@ ${PBM_TESTPREFIX}rgb3toppm ${tmpdir}/testgrid.red ${tmpdir}/testgrid.grn \
 # With PGM or PBM input, the three monochrome planes should be
 # identical.  Test for this.
 
-diff ${tmpdir}/testgrid.red ${tmpdir}/testgrid.grn ; echo $?
-diff ${tmpdir}/testgrid.grn ${tmpdir}/testgrid.blu ; echo $?
-${PBM_BINPREFIX}pgmtopgm < testgrid.pbm | diff - ${tmpdir}/testgrid.red;
+cmp -s ${tmpdir}/testgrid.red ${tmpdir}/testgrid.grn ; echo $?
+cmp -s ${tmpdir}/testgrid.grn ${tmpdir}/testgrid.blu ; echo $?
+${PBM_BINPREFIX}pgmtopgm < testgrid.pbm | cmp -s - ${tmpdir}/testgrid.red
   echo $?
 
 rm ${tmpdir}/testgrid.{pbm,red,grn,blu}
diff --git a/test/winicon-roundtrip.ok b/test/winicon-roundtrip.ok
new file mode 100644
index 00000000..8334ff4e
--- /dev/null
+++ b/test/winicon-roundtrip.ok
@@ -0,0 +1,2 @@
+71846281 6925
+326197919 137
diff --git a/test/winicon-roundtrip.test b/test/winicon-roundtrip.test
new file mode 100644
index 00000000..f5f2926e
--- /dev/null
+++ b/test/winicon-roundtrip.test
@@ -0,0 +1,13 @@
+#! /bin/bash
+# This script tests: pamtowinicon winicontopam
+# Also requires: pnmcut pnmtile pamtopnm ppmtopgm pgmtopbm
+
+${PBM_BINPREFIX}pnmcut --left=30 --width=48 --height=48 testimg.ppm | \
+${PBM_TESTPREFIX}pamtowinicon | ${PBM_TESTPREFIX}winicontopam | \
+  ${PBM_BINPREFIX}pamtopnm | cksum
+
+${PBM_BINPREFIX}pnmtile 32 32 testgrid.pbm | \
+${PBM_TESTPREFIX}pamtowinicon | ${PBM_TESTPREFIX}winicontopam | \
+  ${PBM_BINPREFIX}pamtopnm | ${PBM_BINPREFIX}ppmtopgm | \
+  ${PBM_BINPREFIX}pgmtopbm  -th -val=0.5 | cksum
+
diff --git a/test/yuv-roundtrip.test b/test/yuv-roundtrip.test
index c160c480..697d86aa 100755
--- a/test/yuv-roundtrip.test
+++ b/test/yuv-roundtrip.test
@@ -4,5 +4,6 @@
 
 # Should produce 1904478375 253455
 
-${PBM_BINPREFIX}pamgradient cyan yellow red green 352 240 | \
+${PBM_BINPREFIX}pamgradient rgb:00/ff/ff rgb:ff/ff/00 \
+                            rgb:ff/00/00 rgb:00/ff/00 352 240 | \
     ${PBM_TESTPREFIX}ppmtoyuv | ${PBM_TESTPREFIX}yuvtoppm 352 240 | cksum
diff --git a/version.mk b/version.mk
index 397cdccb..70979cfd 100644
--- a/version.mk
+++ b/version.mk
@@ -1,4 +1,4 @@
 NETPBM_MAJOR_RELEASE = 10
-NETPBM_MINOR_RELEASE = 62
-NETPBM_POINT_RELEASE = 9
+NETPBM_MINOR_RELEASE = 63
+NETPBM_POINT_RELEASE = 0