about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile48
-rw-r--r--analyzer/Makefile9
-rw-r--r--common.mk23
-rw-r--r--converter/other/Makefile26
-rw-r--r--converter/other/bmptopnm.c572
-rw-r--r--converter/other/gemtopnm.c200
-rw-r--r--converter/other/jbig/jbigtopnm.c394
-rw-r--r--converter/other/jbig/libjbig/jbig.c196
-rw-r--r--converter/other/jpeg2000/jpeg2ktopam.c107
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_util.c26
-rw-r--r--converter/other/jpeg2000/pamtojpeg2k.c82
-rw-r--r--converter/other/pamtotga.c349
-rw-r--r--converter/other/pamtotiff.c62
-rw-r--r--converter/pbm/Makefile8
-rw-r--r--converter/pbm/pbmtoln03.c211
-rw-r--r--converter/pbm/pbmtomacp.c6
-rw-r--r--converter/pbm/pbmtoppa/pbm.c273
-rw-r--r--converter/ppm/hpcdtoppm/Makefile4
-rw-r--r--converter/ppm/picttoppm.c360
-rw-r--r--converter/ppm/pjtoppm.c215
-rw-r--r--converter/ppm/ppmtobmp.c175
-rw-r--r--converter/ppm/ppmtomitsu.c16
-rw-r--r--converter/ppm/tgatoppm.c291
-rw-r--r--converter/ppm/xpmtoppm.c112
-rw-r--r--converter/ppm/xvminitoppm.c64
-rw-r--r--converter/tga.h13
-rw-r--r--doc/HISTORY84
-rw-r--r--editor/Makefile18
-rw-r--r--editor/pamcomp.c10
-rw-r--r--editor/pamcut.c480
-rw-r--r--editor/pammixmulti.c543
-rw-r--r--editor/pnmconvol.c2
-rw-r--r--editor/pnmhisteq.c32
-rw-r--r--editor/pnmpaste.c32
-rw-r--r--editor/specialty/Makefile8
-rw-r--r--generator/pamtris/boundaries.c200
-rw-r--r--generator/pamtris/boundaries.h1
-rw-r--r--generator/pamtris/fract.h54
-rw-r--r--generator/pamtris/framebuffer.c49
-rw-r--r--generator/pamtris/framebuffer.h10
-rw-r--r--generator/pamtris/input.c803
-rw-r--r--generator/pamtris/input.h22
-rw-r--r--generator/pamtris/limits_pamtris.h8
-rw-r--r--generator/pamtris/pamtris.c67
-rw-r--r--generator/pamtris/triangle.c274
-rw-r--r--generator/pamtris/triangle.h2
-rw-r--r--generator/pamtris/utils.c218
-rw-r--r--generator/pamtris/utils.h59
-rw-r--r--generator/pamtris/varying.h12
-rw-r--r--generator/pbmtext.c9
-rw-r--r--lib/colorname.c7
-rw-r--r--lib/libpamcolor.c8
-rw-r--r--lib/libpbmfont0.c4
-rw-r--r--lib/libpbmfont1.c4
-rw-r--r--lib/libpbmfont2.c50
-rw-r--r--lib/libpm.c4
-rw-r--r--lib/libppmcolor.c8
-rw-r--r--lib/pbmfont.h4
-rw-r--r--lib/pm.h64
-rw-r--r--lib/pmfileio.c104
-rw-r--r--lib/util/runlength.c38
-rw-r--r--netpbm.c46
-rw-r--r--other/Makefile10
-rw-r--r--other/pamfix.c12
-rw-r--r--other/pnmcolormap.c173
-rw-r--r--pm_config.in.h12
-rw-r--r--test/Test-Order6
-rw-r--r--test/bmp-quant-roundtrip.ok6
-rwxr-xr-xtest/bmp-quant-roundtrip.test36
-rw-r--r--test/bmp-roundtrip.ok20
-rwxr-xr-xtest/bmp-roundtrip.test41
-rw-r--r--test/cut-cat-roundtrip.ok92
-rwxr-xr-xtest/cut-cat-roundtrip.test128
-rw-r--r--test/g3-roundtrip.ok20
-rwxr-xr-xtest/g3-roundtrip.test20
-rw-r--r--test/gif-quant-roundtrip.ok2
-rwxr-xr-xtest/gif-quant-roundtrip.test2
-rw-r--r--test/gif-roundtrip.ok20
-rwxr-xr-xtest/gif-roundtrip.test8
-rw-r--r--test/palm-roundtrip.ok10
-rwxr-xr-xtest/palm-roundtrip.test8
-rw-r--r--test/pamcut.ok15
-rwxr-xr-xtest/pamcut.test35
-rw-r--r--test/pammixmulti-identity.ok22
-rwxr-xr-xtest/pammixmulti-identity.test77
-rw-r--r--test/pbmtext-utf8.ok4
-rwxr-xr-xtest/pbmtext-utf8.test4
-rw-r--r--test/pdb-roundtrip.ok22
-rwxr-xr-xtest/pdb-roundtrip.test6
-rw-r--r--test/pnmpaste-pbm.ok22
-rwxr-xr-xtest/pnmpaste-pbm.test47
-rw-r--r--test/pnmtile.ok2
-rwxr-xr-xtest/pnmtile.test2
-rw-r--r--test/rgb3-roundtrip.ok2
-rwxr-xr-xtest/rgb3-roundtrip.test2
-rw-r--r--test/targa-roundtrip.ok40
-rwxr-xr-xtest/targa-roundtrip.test82
-rw-r--r--version.mk4
98 files changed, 4895 insertions, 3299 deletions
diff --git a/GNUmakefile b/GNUmakefile
index 3bf3623d..1beebb4c 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -11,6 +11,7 @@
 #   deb:          Make a .deb file in the current dir.
 #
 #   check-tree:     Conduct tests on Netpbm files in the source dir. 
+#                   with "target=pamtotga" tests only pamtotga.
 #   check-package:  Conduct tests on packaged Netpbm files.
 #   check-install:  Conduct tests on installed Netpbm files.
 #   check:          Default check.  Synonym for check-package.
@@ -101,18 +102,27 @@ all: nonmerge
 .PHONY: nonmerge
 nonmerge: $(PRODUCT_SUBDIRS:%=%/all)
 
-# Parallel make (make --jobs) is not smart enough to coordinate builds
-# between submakes, so a naive parallel make would cause certain
-# targets to get built multiple times simultaneously.  That is usually
-# unacceptable.  So we introduce extra dependencies here just to make
-# sure such targets are already up to date before the submake starts,
-# for the benefit of parallel make.  Note that we ensure that parallel
-# make works for 'make all' in the top directory, but it may still fail
-# for the aforementioned reason for other invocations.
+# Completely parallel make (make --jobs) does not work because there are
+# multiple targets somewhere in the Netpbm build that depend upon pm_config.h
+# and similar targets, and the threads building those multiple targets might
+# simultaneously find that pm_config.h needs to be built and proceed to build
+# it.  After one thread has built pm_config.h, it will proceed to use
+# pm_config.h, but the other thread is still building pm_config.h, which is
+# not valid while it is in the middle of being built.
+#
+# But many submakes don't have any such shared dependencies, so build their
+# targets in parallel just fine.  So we declare this make file ineligible for
+# parallel make and have special dependencies to get pm_config.h and like
+# targets built before any submakes begin.  The submakes will thus never find
+# that pm_config.h needs to be built, so we leave them eligible for parallel
+# make.
+
+.NOTPARALLEL:
 
 $(SUBDIRS:%=%/all) lib/util/all: pm_config.h inttypes_netpbm.h version.h
 $(PROG_SUBDIRS:%=%/all): lib/all $(SUPPORT_SUBDIRS:%=%/all)
 lib/all: lib/util/all
+netpbm: lib/all
 
 .PHONY: lib/util/all
 lib/util/all:
@@ -139,7 +149,7 @@ $(TYPEGEN) $(ENDIANGEN): $(BUILDDIR)/buildtools
 	$(MAKE) -C $(dir $@) -f $(SRCDIR)/buildtools/Makefile \
 	    SRCDIR=$(SRCDIR) BUILDDIR=$(BUILDDIR) $(notdir $@) 
 
-inttypes_netpbm.h: $(TYPEGEN)
+$(BUILDDIR)/inttypes_netpbm.h: $(TYPEGEN)
 	$(TYPEGEN) >$@
 
 
@@ -155,7 +165,7 @@ $(TESTRANDOM): $(BUILDDIR)/test
 # that or to override the results, because it doesn't work if he's
 # cross compiling.
 
-pm_config.h: \
+$(BUILDDIR)/pm_config.h: \
   $(SRCDIR)/pm_config.in.h config.mk inttypes_netpbm.h \
   $(ENDIANGEN)
 # Note that this rule depends on the effect of the .DELETE_ON_ERROR
@@ -197,7 +207,7 @@ endif
 MAJOR := $(NETPBM_MAJOR_RELEASE)
 MINOR := $(NETPBM_MINOR_RELEASE)
 POINT := $(NETPBM_POINT_RELEASE)
-version.h: $(SRCDIR)/version.mk
+$(BUILDDIR)/version.h: $(SRCDIR)/version.mk
 	@rm -f $@
 	@echo "/* Generated by make file rule */" >>$@
 	@echo "#define NETPBM_VERSION" \
@@ -373,18 +383,6 @@ netpbm:%:%.o $(OBJECT_DEP) $(NETPBMLIB) $(URTLIBDEP) $(LIBOPT)
 
 netpbm.o: mergetrylist
 
-install.merge: local.install.merge
-.PHONY: local.install.merge
-local.install.merge:
-	cd $(PKGDIR)/bin; $(SYMLINKEXE) netpbm pnmnoraw
-	cd $(PKGDIR)/bin; $(SYMLINKEXE) netpbm gemtopbm
-	cd $(PKGDIR)/bin; $(SYMLINKEXE) netpbm pnminterp
-	cd $(PKGDIR)/bin; $(SYMLINKEXE) netpbm pgmoil
-	cd $(PKGDIR)/bin; $(SYMLINKEXE) netpbm ppmtojpeg
-	cd $(PKGDIR)/bin; $(SYMLINKEXE) netpbm bmptoppm
-	cd $(PKGDIR)/bin; $(SYMLINKEXE) netpbm pgmnorm
-	cd $(PKGDIR)/bin; $(SYMLINKEXE) netpbm pnmfile
-
 ifneq ($(NETPBMLIBTYPE),unixstatic)
 install.lib: lib/install.lib
 else
@@ -519,9 +517,9 @@ check-tree : PALMMAPDIR ?= $(SRCDIR)/converter/other/pnmtopalm
 
 
 # Create RESULTDIR.
-# If it already exists, rename and covert to an archive directory.
+# If it already exists, rename and convert to an archive directory.
 # Use numbered backup.
-# TODO: Renaming fails with old versions of mv which do not support -T.  
+# Note: Renaming fails with old versions of mv which do not have -T.  
 
 resultdir-backup: FORCE
 	if [ -d $(RESULTDIR) ]; \
diff --git a/analyzer/Makefile b/analyzer/Makefile
index abd87d7c..dc7a0cb2 100644
--- a/analyzer/Makefile
+++ b/analyzer/Makefile
@@ -46,12 +46,14 @@ OBJECTS = $(BINARIES:%=%.o)
 MERGEBINARIES = $(BINARIES)
 MERGE_OBJECTS = $(MERGEBINARIES:%=%.o2)
 
+HAVE_MERGE_COMPAT=YES
+
 .PHONY: all
 all: $(BINARIES)
 
 include $(SRCDIR)/common.mk
 
-install.bin: install.bin.local
+install.bin install.merge: install.bin.local
 .PHONY: install.bin.local
 install.bin.local: $(PKGDIR)/bin
 # Remember that $(SYMLINK) might just be a copy command.
@@ -60,5 +62,10 @@ install.bin.local: $(PKGDIR)/bin
 	cd $(PKGDIR)/bin ; \
 	$(SYMLINK) pamfile$(EXE) pnmfile$(EXE)
 
+mergecomptrylist:
+	cat /dev/null >$@
+	echo "TRY(\"pgmslice\", main_pamslice);" >>$@
+	echo "TRY(\"pnmfile\",  main_pamfile);"  >>$@
+
 FORCE:
 
diff --git a/common.mk b/common.mk
index 97810cd4..4bfdb6a1 100644
--- a/common.mk
+++ b/common.mk
@@ -400,14 +400,29 @@ $(PORTBINARIES) $(MATHBINARIES): %: %.o \
 	  "-Dmain=main_$*" \
           $(CFLAGS_MERGE) $(CFLAGS_PERSONAL) $(CADD) -o $@ $<
 
-# The "merge try list" is a file full of TRY macro invocations, one for
-# each Netpbm program in this directory or any subdirectory that can be
-# invoked via the merged Netpbm program.  You will find it #included in
-# netpbm.c.
+# The "merge try list" is a file full of TRY macro invocations, one for each
+# Netpbm program in this directory or any subdirectory that can be invoked via
+# the merged Netpbm program.  There are additional TRYs for backward
+# compatility program names (e.g. 'pnmcomp' for 'pamcomp').  You will find the
+# merge try list #included in netpbm.c.
+
+# The file 'mergecomptrylist' contains the backward compatibility TRYs for the
+# current directory.  Just the current directory itself - not subdirectories.
+# Only directories that contain programs with backward compatibility names
+# have a 'mergecomptrylist'.  The make file for a directory that has
+# 'mergecomptrylist' sets make variable HAVE_MERGE_COMPAT to "YES".
+
+ifeq ($(HAVE_MERGE_COMPAT),YES)
+mergetrylist: mergecomptrylist
+endif
 
 mergetrylist: $(SUBDIRS:%=%/mergetrylist) 
 	cat /dev/null $(SUBDIRS:%=%/mergetrylist) >$@
 	$(SRCDIR)/buildtools/make_merge.sh $(MERGEBINARIES) >>$@
+ifeq ($(HAVE_MERGE_COMPAT),YES)
+	echo "/* Backward compatibility names from mergecomptrylist: */" >>$@
+	cat mergecomptrylist >>$@
+endif
 
 # The "merge list" is a list of all the object files from this directory and
 # any subdirectories that have to be linked into the merged Netpbm program.
diff --git a/converter/other/Makefile b/converter/other/Makefile
index b01f66ae..2be88781 100644
--- a/converter/other/Makefile
+++ b/converter/other/Makefile
@@ -166,6 +166,8 @@ endif
 OBJECTS = $(BINARIES:%=%.o) $(EXTRA_OBJECTS)
 MERGE_OBJECTS = $(MERGEBINARIES:%=%.o2) $(EXTRA_OBJECTS)
 
+HAVE_MERGE_COMPAT=YES
+
 pnmtops.o pnmtops.o2: CFLAGS_TARGET=$(PNMTOPS_NOFLATE_OPT)
 
 SCRIPTS = anytopnm pnmtoplainpnm
@@ -248,7 +250,7 @@ bmptopnm.o bmptopnm.o2: bmp.h
 
 pamtotga.o pamtotga.o2: tga.h
 
-install.bin: install.bin.local
+install.bin install.merge: install.bin.local
 .PHONY: install.bin.local
 install.bin.local: $(PKGDIR)/bin
 # Remember that $(SYMLINK) might just be a copy command.
@@ -296,3 +298,25 @@ ifeq ($(HAVE_PNGLIB),Y)
 	cd $(PKGDIR)/bin ; \
 	$(SYMLINK) pamtopng$(EXE) pamrgbatopng$(EXE)
 endif
+
+mergecomptrylist:
+	cat /dev/null >$@
+	echo "TRY(\"bmptoppm\",     main_bmptopnm);"     >>$@
+	echo "TRY(\"gemtopbm\",     main_gemtopnm);"     >>$@
+ifneq ($(JPEGLIB),NONE)
+	echo "TRY(\"ppmtojpeg\",    main_pnmtojpeg);"    >>$@
+endif
+	echo "TRY(\"ppmtouil\",     main_pamtouil);"     >>$@
+	echo "TRY(\"ppmtotga\",     main_pamtotga);"     >>$@
+	echo "TRY(\"pnmtopnm\",     main_pamtopnm);"     >>$@
+	echo "TRY(\"pnmtofits\",    main_pamtofits);"    >>$@
+ifneq ($(TIFF_PREREQ_MISSING),Y)
+	echo "TRY(\"pnmtotiff\",    main_pamtotiff);"    >>$@
+endif
+ifeq ($(HAVE_PNGLIB),Y)
+	echo "TRY(\"pngtopnm\",     main_pngtopam);"     >>$@
+endif
+	echo "TRY(\"icontopbm\",    main_sunicontopnm);" >>$@
+ifeq ($(HAVE_PNGLIB),Y)
+	echo "TRY(\"pamrgbatopng\", main_pamtopng);"     >>$@
+endif
diff --git a/converter/other/bmptopnm.c b/converter/other/bmptopnm.c
index 787b9020..3f66634b 100644
--- a/converter/other/bmptopnm.c
+++ b/converter/other/bmptopnm.c
@@ -1,7 +1,7 @@
 /*****************************************************************************
                                     bmptopnm.c
 ******************************************************************************
- 
+
  Bmptopnm - Converts from a Microsoft Windows or OS/2 .BMP file to a
  PBM, PGM, or PPM file.
 
@@ -9,7 +9,7 @@
  The name was changed in March 2002.
 
  Copyright (C) 1992 by David W. Sanderson.
- 
+
  Permission to use, copy, modify, and distribute this software and its
  documentation for any purpose and without fee is hereby granted,
  provided that the above copyright notice appear in all copies and
@@ -62,14 +62,14 @@ struct bitPosition {
 };
 
 struct pixelformat {
-    /* The format of a pixel representation from the raster.  i.e. which 
-       bits apply to red, green, blue, and transparency 
+    /* The format of a pixel representation from the raster.  i.e. which
+       bits apply to red, green, blue, and transparency
     */
     struct bitPosition red;
     struct bitPosition blu;
     struct bitPosition grn;
     struct bitPosition trn;
-    
+
     bool conventionalBgr;
         /* This means that the above bit positions are just the conventional
            BGR format -- one byte Blue, one byte Green, one byte Red,
@@ -83,7 +83,7 @@ struct pixelformat {
 typedef struct {
     /* These are all encodings of floating point */
     unsigned long x;
-    unsigned long y; 
+    unsigned long y;
     unsigned long z;
 } cieXyz;
 
@@ -105,14 +105,14 @@ struct bmpInfoHeader {
            described by the "mask" values in the header, rather than
            fixed formats.
         */
-    unsigned int cmapsize;
+    unsigned int cmapSize;
         /* Size in bytes of the colormap (palette) in the BMP file.
 
            Zero means there is no colormap.
         */
     unsigned int imageSize;
-        /* Size in bytes of the image data.  We only reference this 
-           when the image is compressed. */    
+        /* Size in bytes of the image data.  We only reference this
+           when the image is compressed. */
     unsigned short cPlanes;
     BMPCompType compression;
     struct pixelformat pixelformat;
@@ -151,7 +151,7 @@ parseCommandLine(int argc, const char ** argv,
 
     option_def_index = 0;   /* incremented by OPTENT3 */
     OPTENT3(0,   "verbose",     OPT_FLAG,   NULL, &cmdlineP->verbose,   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 */
@@ -159,7 +159,7 @@ parseCommandLine(int argc, const char ** argv,
     pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
-    if (argc-1 == 0) 
+    if (argc-1 == 0)
         cmdlineP->inputFileName = "-";
     else if (argc-1 != 1)
         pm_error("Program takes zero or one argument (filename).  You "
@@ -251,7 +251,45 @@ GetCieXyzTriple(FILE *         const ifP) {
 
 
 static struct pixelformat
-defaultPixelformat(unsigned int const bitCount);
+defaultPixelformat(unsigned int const bitCount) {
+
+    struct pixelformat retval;
+
+    switch (bitCount) {
+    case 16:
+        /* This layout is sometimes called "RGB555".  A document from
+           Microsoft says this is the default (when the "compression"
+           field of the header says COMP_BITFIELDS).
+        */
+        retval.conventionalBgr = FALSE;
+        retval.red.shift = 10;
+        retval.grn.shift = 5;
+        retval.blu.shift = 0;
+        retval.trn.shift = 0;
+        retval.red.mask = 0x1f;  /* 5 bits */
+        retval.grn.mask = 0x1f;  /* 5 bits */
+        retval.blu.mask = 0x1f;  /* 5 bits */
+        retval.trn.mask = 0;
+        break;
+    case 24:
+    case 32:
+        retval.conventionalBgr = TRUE;
+        retval.red.shift = 16;
+        retval.grn.shift = 8;
+        retval.blu.shift = 0;
+        retval.trn.shift = 0;
+        retval.red.mask = 0xff;  /* 8 bits */
+        retval.grn.mask = 0xff;  /* 8 bits */
+        retval.blu.mask = 0xff;  /* 8 bits */
+        retval.trn.mask = 0;
+        break;
+    default:
+        /* colormapped - masks are undefined */
+        break;
+    }
+
+    return retval;
+}
 
 
 
@@ -261,7 +299,7 @@ readOffBytes(FILE * const fp, unsigned int const nbytes) {
    Read 'nbytes' from file 'fp'.  Abort program if read error.
 -----------------------------------------------------------------------------*/
     int i;
-    
+
     for(i = 0; i < nbytes; ++i) {
         int rc;
         rc = getc(fp);
@@ -273,8 +311,8 @@ readOffBytes(FILE * const fp, unsigned int const nbytes) {
 
 
 static void
-bmpReadfileheader(FILE *         const ifP, 
-                  unsigned int * const bytesReadP, 
+bmpReadfileheader(FILE *         const ifP,
+                  unsigned int * const bytesReadP,
                   unsigned int * const offBitsP) {
 
     unsigned long     offBits;
@@ -304,7 +342,21 @@ bmpReadfileheader(FILE *         const ifP,
 static void
 readOs2InfoHeaderRest(FILE *                 const ifP,
                       struct bmpInfoHeader * const headerP) {
+/*----------------------------------------------------------------------------
+   Read the rest of the info header, after its size field, of an OS2 BMP from
+   *ifP.
+
+   Add the information from it to *headerP, in particular these members:
 
+     cols
+     rows
+     rowOrder
+     cPlanes
+     cBitCount
+     cmapSize
+     pixelformat
+     compression
+-----------------------------------------------------------------------------*/
     unsigned short colsField, rowsField;
     unsigned short planesField, bitCountField;
 
@@ -313,7 +365,7 @@ readOs2InfoHeaderRest(FILE *                 const ifP,
         pm_error("Invalid BMP file: says width is zero");
     else
         headerP->cols = colsField;
-    
+
     pm_readlittleshortu(ifP, &rowsField);
     if (rowsField == 0)
         pm_error("Invalid BMP file: says height is zero");
@@ -332,16 +384,16 @@ readOs2InfoHeaderRest(FILE *                 const ifP,
        same as for Windows.
     */
     if (headerP->cBitCount <= 8)
-        headerP->cmapsize = 1 << headerP->cBitCount;
+        headerP->cmapSize = 1 << headerP->cBitCount;
     else if (headerP->cBitCount == 24)
-        headerP->cmapsize = 0;
+        headerP->cmapSize = 0;
     /* There is a 16 bit truecolor format, but we don't know how the
        bits are divided among red, green, and blue, so we can't handle it.
     */
     else
         pm_error("Unrecognized bits per pixel in OS/2 BMP file header: %d",
                  headerP->cBitCount);
-                 
+
     headerP->pixelformat = defaultPixelformat(headerP->cBitCount);
 
     headerP->compression = BMPCOMP_RGB;
@@ -353,24 +405,24 @@ static void
 validateCompression(unsigned long const compression,
                     enum rowOrder const rowOrder,
                     unsigned int  const cBitCount) {
-    
+
     if (compression != BMPCOMP_RGB && compression != BMPCOMP_BITFIELDS &&
-        compression != BMPCOMP_RLE4 && compression != BMPCOMP_RLE8) 
+        compression != BMPCOMP_RLE4 && compression != BMPCOMP_RLE8)
         pm_error("Input has unknown encoding.  "
                  "Compression type code = %ld.  The only ones we know "
                  "are RGB (%u), BITFIELDS (%u), "
                  "RLE4 (%u), and RLE8 (%u)",
                  compression, BMPCOMP_RGB, BMPCOMP_BITFIELDS,
                  BMPCOMP_RLE4, BMPCOMP_RLE8);
-                     
+
     if ((compression == BMPCOMP_RLE4 || compression == BMPCOMP_RLE8) &&
-        rowOrder == TOPDOWN )                        
+        rowOrder == TOPDOWN )
         pm_error("Invalid BMP header.  Claims image is top-down and also "
                  "compressed, which is an impossible combination.");
 
     if ((compression == BMPCOMP_RLE4 && cBitCount !=4 ) ||
-        (compression == BMPCOMP_RLE8 && cBitCount !=8 )) 
-        pm_error("Invalid BMP header.  " 
+        (compression == BMPCOMP_RLE8 && cBitCount !=8 ))
+        pm_error("Invalid BMP header.  "
                  "Compression type (%s) disagrees with "
                  "number of bits per pixel (%u).",
                  compression == BMPCOMP_RLE4 ? "RLE4" : "RLE8",
@@ -427,7 +479,7 @@ readWindowsBasic40ByteInfoHeader(FILE *                 const ifP,
 
         headerP->bitFields = (compression == BMPCOMP_BITFIELDS);
 
-        headerP->compression = compression;             
+        headerP->compression = compression;
     }
     /* And read the rest of the junk in the 40 byte header */
     headerP->imageSize = GetLong(ifP);   /* ImageSize */
@@ -435,7 +487,7 @@ readWindowsBasic40ByteInfoHeader(FILE *                 const ifP,
     GetLong(ifP);   /* YpixelsPerMeter */
     colorsused = GetLong(ifP);   /* ColorsUsed */
     /* See comments in bmp.h for info about the definition of the following
-       word and its relationship to the color map size (headerP->cmapsize).
+       word and its relationship to the color map size (headerP->cmapSize).
     */
     /* colorsimportant = */ GetLong(ifP);  /* ColorsImportant */
 
@@ -443,16 +495,22 @@ readWindowsBasic40ByteInfoHeader(FILE *                 const ifP,
         if (colorsused != 0) {
             if (colorsused > 1 << headerP->cBitCount)
                 pm_error("Invalid BMP header.  Says %u bits per pixel, "
-                         "but %d colors used", 
+                         "but %d colors used",
                          headerP->cBitCount, colorsused);
+            else if (colorsused == 1 && headerP->cBitCount == 1) {
+                pm_message("Abnormal BMP header.  Says 1 bit per pixel. "
+                           "Should have 2 colors, but says only 1 color used. "
+                    );
+                headerP->cmapSize = colorsused;
+        }
             else
-                headerP->cmapsize = colorsused;
-        } else 
-            headerP->cmapsize = 1 << headerP->cBitCount;
-    } else if (headerP->cBitCount == 24 || 
-               headerP->cBitCount == 16 || 
+                headerP->cmapSize = colorsused;
+        } else
+            headerP->cmapSize = 1 << headerP->cBitCount;
+    } else if (headerP->cBitCount == 24 ||
+               headerP->cBitCount == 16 ||
                headerP->cBitCount == 32)
-        headerP->cmapsize = 0;
+        headerP->cmapSize = 0;
     else
         pm_error("Unrecognized bits per pixel in Windows BMP file header: %d",
                  headerP->cBitCount);
@@ -465,18 +523,18 @@ lsbZeroCount(unsigned int const mask)
 /*----------------------------------------------------------------------------
    Return the number of consecutive zeroes in the mask 'mask', starting with
    the least significant bit and going up.  E.g. for 0x20, it would be 5.
-   
+
    Use GCC built-in when available.
 -----------------------------------------------------------------------------*/
 
-#if HAVE_GCC_BITCOUNT 
+#if HAVE_GCC_BITCOUNT
 {
       return ( mask==0 ? sizeof(mask)*8 : __builtin_ctz(mask) );
 }
 #else
 {
       unsigned int i=0;
-    
+
       while (((mask >> i) & 0x1) == 0 && i < sizeof(mask)*8)
         ++i;
 
@@ -526,51 +584,8 @@ computeConventionalBgr(struct pixelformat * const fP,
 
 
 
-static struct pixelformat
-defaultPixelformat(unsigned int const bitCount) {
-
-    struct pixelformat retval;
-
-    switch (bitCount) {
-    case 16:
-        /* This layout is sometimes called "RGB555".  A document from
-           Microsoft says this is the default (when the "compression"
-           field of the header says COMP_BITFIELDS).
-        */
-        retval.conventionalBgr = FALSE;
-        retval.red.shift = 10;
-        retval.grn.shift = 5;
-        retval.blu.shift = 0;
-        retval.trn.shift = 0;
-        retval.red.mask = 0x1f;  /* 5 bits */
-        retval.grn.mask = 0x1f;  /* 5 bits */
-        retval.blu.mask = 0x1f;  /* 5 bits */
-        retval.trn.mask = 0;
-        break;
-    case 24:
-    case 32:
-        retval.conventionalBgr = TRUE;
-        retval.red.shift = 16;
-        retval.grn.shift = 8;
-        retval.blu.shift = 0;
-        retval.trn.shift = 0;
-        retval.red.mask = 0xff;  /* 8 bits */
-        retval.grn.mask = 0xff;  /* 8 bits */
-        retval.blu.mask = 0xff;  /* 8 bits */
-        retval.trn.mask = 0;
-        break;
-    default:
-        /* colormapped - masks are undefined */
-        break;
-    }
-
-    return retval;
-}
-
-
-
 static void
-readV4InfoHeaderExtension(FILE *                 const ifP, 
+readV4InfoHeaderExtension(FILE *                 const ifP,
                           struct bmpInfoHeader * const headerP,
                           unsigned int *         const bytesReadP) {
 
@@ -605,12 +620,12 @@ readV4InfoHeaderExtension(FILE *                 const ifP,
     GetLong(ifP);  /* GammaBlue */
 
     *bytesReadP = 68;
-} 
+}
 
 
 
 static void
-readV5InfoHeaderExtension(FILE *                 const ifP, 
+readV5InfoHeaderExtension(FILE *                 const ifP,
                           struct bmpInfoHeader * const headerP,
                           unsigned int *         const bytesReadP) {
 
@@ -634,10 +649,31 @@ defaultV4InfoHeaderExtension(struct bmpInfoHeader * const headerP) {
 
 
 static void
-readWindowsInfoHeaderRest(FILE *                 const ifP, 
+readWindowsInfoHeaderRest(FILE *                 const ifP,
                           unsigned int           const cInfoHeaderSize,
                           struct bmpInfoHeader * const headerP) {
-
+/*----------------------------------------------------------------------------
+   Read the rest of the info header, after the length field, of a Windows BMP
+   from *ifP.
+
+   'cInfoHeaderSize' is the size of the info header, not counting its size
+   field.  Note that besides telling us how much data to read, this also
+   implies which of the three major formats the data is in.
+
+   Add the information from it to *headerP, in particular these members:
+
+     cols
+     rows
+     rowOrder
+     cPlanes
+     cBitCount
+     bitFields
+     compression
+     imageSize
+     cmapSize
+     pixelformat
+     endPoints
+-----------------------------------------------------------------------------*/
     /* There are 3 major formats of Windows
        BMP, identified by the 3 info header lengths.  The original
        one is 40 bytes.  The "V4 header" is 108 bytes and was
@@ -656,7 +692,7 @@ readWindowsInfoHeaderRest(FILE *                 const ifP,
         bytesRead += v4BytesRead;
 
         assert(bytesRead == BMP_HDRLEN_WIN_V4);
-    } else 
+    } else
         defaultV4InfoHeaderExtension(headerP);
 
     if (cInfoHeaderSize >= BMP_HDRLEN_WIN_V5) {
@@ -670,14 +706,14 @@ readWindowsInfoHeaderRest(FILE *                 const ifP,
         GetByte(ifP);
         ++bytesRead;
     }
-    
+
     assert(bytesRead == cInfoHeaderSize);
 }
 
 
 
 static void
-bmpReadinfoheader(FILE *                 const ifP, 
+bmpReadinfoheader(FILE *                 const ifP,
                   unsigned int *         const bytesReadP,
                   struct bmpInfoHeader * const headerP,
                   const char **          const errorP) {
@@ -694,11 +730,11 @@ bmpReadinfoheader(FILE *                 const ifP,
         pm_strfree(error);
     } else {
         switch (headerP->class) {
-        case BMP_C_WIN_V1: 
-        case BMP_C_WIN_V2: 
-        case BMP_C_WIN_V3: 
-        case BMP_C_WIN_V4: 
-        case BMP_C_WIN_V5: 
+        case BMP_C_WIN_V1:
+        case BMP_C_WIN_V2:
+        case BMP_C_WIN_V3:
+        case BMP_C_WIN_V4:
+        case BMP_C_WIN_V5:
             readWindowsInfoHeaderRest(ifP, cInfoHeaderSize, headerP);
             break;
         case BMP_C_OS2_1x:
@@ -721,29 +757,29 @@ bmpReadinfoheader(FILE *                 const ifP,
 
 
 static void
-bmpReadColormap(FILE *         const ifP, 
-                enum bmpClass  const class, 
-                xel **         const colormapP, 
-                unsigned int   const cmapsize,
+bmpReadColormap(FILE *         const ifP,
+                enum bmpClass  const class,
+                xel **         const colormapP,
+                unsigned int   const cmapSize,
                 unsigned int * const bytesReadP) {
 /*----------------------------------------------------------------------------
    Read the color map from the present position in the input BMP file
    *ifP.
 
-   The map has 'cmapsize' entries in it.  cmapsize == 0 means there is
+   The map has 'cmapSize' entries in it.  cmapSize == 0 means there is
    no color map.
 
    We return a color map as *colormapP.  If there is no color map in the
    BMP, this is just an arbitrary color map.
- 
+
    'class' is the class of BMP image - Windows or OS/2.
 -----------------------------------------------------------------------------*/
-    xel * const colormap = pnm_allocrow(MAX(1, cmapsize));
-    
+    xel * const colormap = pnm_allocrow(MAX(1, cmapSize));
+
     unsigned int i;
     unsigned int bytesRead;
 
-    for (i = 0, bytesRead = 0; i < cmapsize; ++i) {
+    for (i = 0, bytesRead = 0; i < cmapSize; ++i) {
         /* There is a document that says the bytes are ordered R,G,B,Z,
            but in practice it appears to be the following instead:
         */
@@ -778,13 +814,13 @@ extractBitFields(unsigned int       const rasterval,
                  pixval *           const bP,
                  pixval *           const aP) {
 
-    unsigned int const rbits = 
+    unsigned int const rbits =
         (rasterval >> pixelformat.red.shift) & pixelformat.red.mask;
-    unsigned int const gbits = 
+    unsigned int const gbits =
         (rasterval >> pixelformat.grn.shift) & pixelformat.grn.mask;
-    unsigned int const bbits = 
+    unsigned int const bbits =
         (rasterval >> pixelformat.blu.shift) & pixelformat.blu.mask;
-    unsigned int const abits = 
+    unsigned int const abits =
         (rasterval >> pixelformat.trn.shift) & pixelformat.trn.mask;
 
     *rP = pixelformat.red.mask > 0 ?
@@ -795,7 +831,7 @@ extractBitFields(unsigned int       const rasterval,
         (unsigned int) bbits * maxval / pixelformat.blu.mask : 0;
     *aP = pixelformat.trn.mask > 0 ?
         (unsigned int) abits * maxval / pixelformat.trn.mask : 0;
-}        
+}
 
 
 
@@ -818,7 +854,7 @@ convertRow16(unsigned char      const bmprow[],
         extractBitFields(rasterval, pixelformat, 255, &r, &g, &b, &a);
 
         PNM_ASSIGN(xelrow[col], r, g, b);
-        
+
         cursor += 2;
     }
 }
@@ -830,7 +866,7 @@ convertRow24(unsigned char      const bmprow[],
              xel                      xelrow[],
              int                const cols,
              struct pixelformat const pixelformat) {
-    
+
     /* It's truecolor */
     /* There is a document that gives a much different format for
        24 bit BMPs.  But this seems to be the de facto standard, and is,
@@ -840,7 +876,7 @@ convertRow24(unsigned char      const bmprow[],
 
     unsigned int col;
     unsigned int cursor;
-    
+
     cursor = 0;
     for (col = 0; col < cols; ++col) {
         pixval r, g, b, a;
@@ -851,17 +887,17 @@ convertRow24(unsigned char      const bmprow[],
             b = bmprow[cursor+0];
             a = 0;
         } else {
-            unsigned int const rasterval = 
+            unsigned int const rasterval =
                 (bmprow[cursor+0] << 16) +
                 (bmprow[cursor+1] << 8) +
                 (bmprow[cursor+2] << 0);
-            
+
             extractBitFields(rasterval, pixelformat, 255, &r, &g, &b, &a);
         }
         PNM_ASSIGN(xelrow[col], r, g, b);
         cursor += 3;
     }
-} 
+}
 
 
 
@@ -870,7 +906,7 @@ convertRow32(unsigned char      const bmprow[],
              xel                      xelrow[],
              int                const cols,
              struct pixelformat const pixelformat) {
-    
+
     /* It's truecolor */
 
     unsigned int col;
@@ -886,40 +922,40 @@ convertRow32(unsigned char      const bmprow[],
             b = bmprow[cursor+0];
             a = 0;
         } else {
-            unsigned int const rasterval = 
+            unsigned int const rasterval =
                 (bmprow[cursor+0] << 24) +
                 (bmprow[cursor+1] << 16) +
                 (bmprow[cursor+2] << 8) +
                 (bmprow[cursor+3] << 0);
-            
+
             extractBitFields(rasterval, pixelformat, 255, &r, &g, &b, &a);
         }
 
-        PNM_ASSIGN(xelrow[col], 
+        PNM_ASSIGN(xelrow[col],
                    bmprow[cursor+2], bmprow[cursor+1], bmprow[cursor+0]);
         cursor += 4;
     }
-} 
+}
 
 
 static void
 validateIndex(unsigned int const index,
-	      unsigned int const cmapsize ) {
+              unsigned int const cmapSize ) {
 
-    if (index >= cmapsize)
+    if (index >= cmapSize)
         pm_error("Error: invalid index to color palette.");
 }
 
 
 
 static void
-convertRow(unsigned char      const bmprow[], 
+convertRow(unsigned char      const bmprow[],
            xel                      xelrow[],
-           int                const cols, 
-           unsigned int       const cBitCount, 
+           int                const cols,
+           unsigned int       const cBitCount,
            struct pixelformat const pixelformat,
            xel                const colormap[],
-           unsigned int       const cmapsize
+           unsigned int       const cmapSize
            ) {
 /*----------------------------------------------------------------------------
    Convert a row in raw BMP raster format bmprow[] to a row of xels xelrow[].
@@ -931,20 +967,20 @@ convertRow(unsigned char      const bmprow[],
    If the image is colormapped, colormap[] is the colormap
    (colormap[i] is the color with color index i).
 -----------------------------------------------------------------------------*/
-    if (cBitCount == 24) 
+    if (cBitCount == 24)
         convertRow24(bmprow, xelrow, cols, pixelformat);
-    else if (cBitCount == 16) 
+    else if (cBitCount == 16)
         convertRow16(bmprow, xelrow, cols, pixelformat);
-    else if (cBitCount == 32) 
+    else if (cBitCount == 32)
         convertRow32(bmprow, xelrow, cols, pixelformat);
-    else if (cBitCount == 8) {            
+    else if (cBitCount == 8) {
         /* It's a whole byte colormap index */
-        unsigned int col; 
+        unsigned int col;
         for (col = 0; col < cols; ++col) {
             unsigned int const index = bmprow[col];
-            validateIndex(index, cmapsize);
+            validateIndex(index, cmapSize);
             xelrow[col] = colormap[index];
-	}
+    }
     } else if (cBitCount == 1 || cBitCount == 2 || cBitCount == 4) {
         /* It's a bit field color index */
         unsigned char const mask = ( 1 << cBitCount ) - 1;
@@ -954,9 +990,9 @@ convertRow(unsigned char      const bmprow[],
         for (col = 0; col < cols; ++col) {
             unsigned int const cursor = (col*cBitCount)/8;
             unsigned int const shift = 8 - ((col*cBitCount) % 8) - cBitCount;
-            unsigned int const index = 
+            unsigned int const index =
                 (bmprow[cursor] & (mask << shift)) >> shift;
-            validateIndex(index, cmapsize);
+            validateIndex(index, cmapSize);
             xelrow[col] = colormap[index];
         }
     } else {
@@ -971,8 +1007,8 @@ static unsigned char **
 allocBmpRaster(unsigned int const rows,
                unsigned int const bytesPerRow) {
 
-    unsigned int const storageSize = 
-        rows * sizeof(unsigned char *) + rows * bytesPerRow;        
+    unsigned int const storageSize =
+        rows * sizeof(unsigned char *) + rows * bytesPerRow;
     unsigned char ** bmpRaster;
     unsigned int row;
     unsigned char * startOfRows;
@@ -992,7 +1028,7 @@ allocBmpRaster(unsigned int const rows,
 
     startOfRows = (unsigned char *)(bmpRaster + rows);
 
-    for (row = 0; row < rows; ++row) 
+    for (row = 0; row < rows; ++row)
         bmpRaster[row] = startOfRows + row * bytesPerRow;
 
     return bmpRaster;
@@ -1010,47 +1046,51 @@ readrow(FILE *           const ifP,
     size_t bytesRead;
 
     assert(bytesPerRow > 0);
-    
+
     bytesRead = fread(bmpRaster[row], 1, bytesPerRow, ifP);
 
     if (bytesRead < bytesPerRow) {
         if (feof(ifP))
             pm_error("End of file reading row %u of BMP raster.", row);
-        else 
+        else
             pm_error("Error reading BMP raster.  Errno=%d (%s)",
                      errno, strerror(errno));
     }
     *bytesReadP += bytesRead;
 }
- 
+
 
 
 static void
-nibbleAlign(unsigned char * const ptr,
-            unsigned int    const nibbles){
+nybbleAlign(unsigned char * const bytes,
+            unsigned int    const nybbleCt){
 /*----------------------------------------------------------------------------
-  Shift data pointed by ptr one half byte toward the MSB (to the left).
- 
+  Shift the 'nybbleCt' nybbles of bytes[], after the first byte, one nybble
+  toward the left, with the first of those nybble shifting into the right half
+  of the first byte.  Leave the left half of the first byte alone.
+
   Example:
- 
-  (Numbers in hex, 8 nibbles)
-            5F 13 7E 89 A1
+
+  (Numbers in hex, 8 nybbles)
+            5? 13 7E 89 A1
    becomes  51 37 E8 9A 10
 -----------------------------------------------------------------------------*/
-    unsigned int const fullByteCount = (nibbles-1) / 2;
+    unsigned int const fullByteCt = (nybbleCt + 1) / 2;
     unsigned int i;
-              
-    ptr[0] = ptr[0] & ptr[1] >> 4;
-                                    
-    for (i = 0; i < fullByteCount; ++i)
-        ptr[i+1] = ptr[i+1] << 4 & ptr[i+2] >> 4;
-    
-    if (nibbles % 2 == 1)   /* if there is a final odd nibble */
-        ptr[fullByteCount+1] <<= 4; /* shift it a half byte */
+
+    bytes[0] >>= 4;
+
+    for (i = 0; i < fullByteCt; ++i)
+        bytes[i] = bytes[i] << 4 | bytes[i+1] >> 4;
+
+    if (nybbleCt % 2 == 0) {
+        /* There is a final right nybble.  Shift it. */
+        bytes[fullByteCt] <<= 4;
+    }
 }
 
 
-           
+
 enum rleStatus { ABS_MODE, ENC_MODE, END_OF_ROW, END_OF_BMP, DELTA };
 
 static enum rleStatus
@@ -1060,9 +1100,9 @@ readRLEcode(FILE *          const ifP,
 
     unsigned short s;
     enum rleStatus retval;
-    
+
     s = GetBigShort(ifP);
-    
+
     if      (s == 0) retval = END_OF_ROW;
     else if (s == 1) retval = END_OF_BMP;
     else if (s == 2) retval = DELTA;
@@ -1094,16 +1134,18 @@ readrowRLE(FILE *           const ifP,
     bool const rle4 = (compression == BMPCOMP_RLE4);
     int  const pixelsPerRowMargin = rle4 ? cols % 2 : 0;
 
-    char const err_decode[] = 
+    char const err_decode[] =
         "Error while decoding compressed BMP image.  "
-        "%s.  Row: %u  Pixel: %u" ; 
-     
+        "%s.  Row: %u  Pixel: %u" ;
+
     unsigned int totalBytesRead;
     unsigned int pixelsRead;
 
-    /* There are RLE4 images with rows coded up the byte boundary, resulting
-       in each row one pixel larger than the column length stated in the
-       BMP info header (header.cols) when the column length is odd.
+    /* There are RLE4 images with rows coded up to the byte boundary,
+       resulting in each row one pixel larger than the column length
+       stated in the BMP info header (header.cols) when the column length
+       is odd.
+
        pixelsPerRowMargin is a "wart" to provide for this case.
     */
 
@@ -1112,7 +1154,7 @@ readrowRLE(FILE *           const ifP,
 
     while (true) {
         unsigned int n;
-            /* decompressed bytes already read; current write point */ 
+            /* decompressed bytes already read; current write point */
         unsigned int cnt;
         unsigned char code;
 
@@ -1121,23 +1163,23 @@ readrowRLE(FILE *           const ifP,
         switch (readRLEcode(ifP, &cnt, &code)) {
         case ENC_MODE: {
             unsigned int const byteCnt = rle4 ? (cnt + 1) /2 : cnt;
-            unsigned int i; 
+            unsigned int i;
 
             if (pixelsRead + cnt > cols + pixelsPerRowMargin)
                 pm_error(err_decode,  "Too many pixels in encoded mode",
-                         row, pixelsRead ); 
-                 
+                         row, pixelsRead );
+
             for (i = 0; i < byteCnt; ++i)
                 bmpRaster[row][n+i] = code;
-                 
+
             if (rle4 && pixelsRead % 2 == 1)
                 /* previous read ended odd */
-                nibbleAlign(&bmpRaster[row][n-1], cnt); 
-            
+                nybbleAlign(&bmpRaster[row][n-1], cnt);
+
             pixelsRead += cnt;
             totalBytesRead += 2;
         } break;
-        
+
         case ABS_MODE: {
             unsigned int cmpBytesRead; /* compressed bytes read */
             /* align read-end to 16 bit boundary */
@@ -1146,43 +1188,43 @@ readrowRLE(FILE *           const ifP,
 
             if (pixelsRead + cnt > cols + pixelsPerRowMargin)
                 pm_error(err_decode,  "Too many pixels in absolute mode",
-                         row, pixelsRead); 
+                         row, pixelsRead);
 
-            cmpBytesRead = fread(&bmpRaster[row][n], 
+            cmpBytesRead = fread(&bmpRaster[row][n],
                                  sizeof(char), bytesToRead, ifP);
 
             if (cmpBytesRead < bytesToRead) {
                 if (feof(ifP))
                     pm_error("End of file reading row %u "
                              "of compressed BMP raster.", row);
-                else 
+                else
                     pm_error("Error reading BMP raster.  Errno=%d (%s)",
                              errno, strerror(errno));
             }
             if (rle4 && pixelsRead % 2 == 1) /* previous read ended odd */
-                nibbleAlign(&bmpRaster[row][n-1], cnt); 
-    
+                nybbleAlign(&bmpRaster[row][n-1], cnt);
+
             pixelsRead += cnt;
             totalBytesRead += cmpBytesRead + 2;
         } break;
-            
+
         case END_OF_ROW: {
             if (cols == pixelsRead ||
                 cols + pixelsPerRowMargin == pixelsRead) {
                 if (!lastrow) {
                     *bytesReadP += totalBytesRead + 2;
                     return;
-                } else if (readRLEcode(ifP, NULL, NULL) == END_OF_BMP) { 
+                } else if (readRLEcode(ifP, NULL, NULL) == END_OF_BMP) {
                     *bytesReadP += totalBytesRead +4;
                     return;
                 } else
                     /* lastrow and END_OF_BITMAP not detected */
                     pm_error(err_decode,  "End of bitmap not marked",
-                             row, pixelsRead ); 
+                             row, pixelsRead );
             } else
                 pm_error(err_decode,  "Premature end of row",
                          row, pixelsRead);
-        } break;  
+        } break;
 
         case END_OF_BMP: {
             if (lastrow && (cols == pixelsRead ||
@@ -1192,15 +1234,27 @@ readrowRLE(FILE *           const ifP,
             } else
                 pm_error(err_decode,  "Premature end of bitmap",
                          row, pixelsRead );
+            /* Windows programs do not reject premature end of bitmap.
+               Rather, they set the remaining pixels of the raster to
+               an arbitrary value.  In practice, images with incomplete
+               bitmaps are rare.
+            */
         } break;
 
         case DELTA: {
+            /* Delta means "move the point (col,row) by the amount given
+               in the next two bytes."  Like premature end of bitmap, the
+               official specs do not specify what value the skipped pixels
+               should be set to.  Judging from Windows utilities, there is
+               no consensus within Microsoft either.
+            */
             pm_error(err_decode,
                      "Delta code in compressed BMP image.  "
-                     "This program does not process deltas.",
+                     "This program does not process deltas",
                      row, pixelsRead);
+
         } break;
-         
+
         default:
             pm_error("Internal error processing RLE code in row %u", row);
         }
@@ -1210,13 +1264,13 @@ readrowRLE(FILE *           const ifP,
 
 
 static void
-bmpReadraster(FILE *            const ifP, 
-              unsigned int      const cols, 
-              unsigned int      const rows, 
+bmpReadraster(FILE *            const ifP,
+              unsigned int      const cols,
+              unsigned int      const rows,
               enum rowOrder     const rowOrder,
-              unsigned int      const cBitCount, 
+              unsigned int      const cBitCount,
               BMPCompType       const compression,
-              unsigned char *** const bmpRasterP, 
+              unsigned char *** const bmpRasterP,
               unsigned int *    const bytesReadP) {
 /*----------------------------------------------------------------------------
    Read the raster from the BMP file on *ifP (which is positioned to the
@@ -1246,33 +1300,33 @@ bmpReadraster(FILE *            const ifP,
 
     *bytesReadP = 0;
 
-    /* row order BOTTOMUP is by far the most common case - the bottom 
+    /* row order BOTTOMUP is by far the most common case - the bottom
        line is first in the file, the top line last.
-       
+
        We have never actually seen TOPDOWN, except in a Microsoft spec
     */
-    
+
     switch(compression){
     case BMPCOMP_RGB:
     case BMPCOMP_BITFIELDS: {
         unsigned int i;
         for (i = 0; i < rows; ++i)
-            readrow(ifP, rowOrder == TOPDOWN ? i : rows - i - 1, 
+            readrow(ifP, rowOrder == TOPDOWN ? i : rows - i - 1,
                     bytesPerRow, bmpRaster, bytesReadP);
     } break;
-    case BMPCOMP_RLE4: 
+    case BMPCOMP_RLE4:
     case BMPCOMP_RLE8: {
         unsigned int i;
         /* Read all rows except last */
         assert(rows >= 1);
         for (i = 0; i < rows - 1; ++i){
-            readrowRLE(ifP, rowOrder == TOPDOWN ? i : rows - i - 1, 
+            readrowRLE(ifP, rowOrder == TOPDOWN ? i : rows - i - 1,
                        cols, FALSE, compression, bmpRaster, bytesReadP);
         }
         /* Read last row */
-        readrowRLE(ifP, rowOrder == TOPDOWN ? i : rows - i - 1, 
+        readrowRLE(ifP, rowOrder == TOPDOWN ? i : rows - i - 1,
                    cols, TRUE,  compression, bmpRaster, bytesReadP);
-    } break;             
+    } break;
     case BMPCOMP_JPEG:
         pm_error("BMP file uses JPEG compression.  We don't know how to "
                  "interpret that.");
@@ -1291,19 +1345,19 @@ static void
 reportHeader(struct bmpInfoHeader const header,
              unsigned int         const offBits,
              bool                 const verbose) {
-             
+
     if (verbose) {
         pm_message("BMP image header says:");
         pm_message("  Class of BMP: %s", BMPClassName(header.class));
         pm_message("  Width: %d pixels", header.cols);
         pm_message("  Height: %d pixels", header.rows);
         pm_message("  Depth: %d planes", header.cPlanes);
-        pm_message("  Row order: %s", 
+        pm_message("  Row order: %s",
                    header.rowOrder == BOTTOMUP ? "bottom up" : "top down");
         pm_message("  Byte offset of raster within file: %u", offBits);
         pm_message("  Bits per pixel in raster: %u", header.cBitCount);
         pm_message("  Compression: %s", BMPCompTypeName(header.compression));
-        pm_message("  Colors in color map: %u", header.cmapsize);
+        pm_message("  Colors in color map: %u", header.cmapSize);
     } else {
         pm_message("%s BMP, %ux%ux%u",
                    BMPClassName(header.class),
@@ -1311,20 +1365,29 @@ reportHeader(struct bmpInfoHeader const header,
                    header.rows,
                    header.cBitCount);
     }
-}        
+}
+
+
+
+static void
+validateCPlanes(unsigned short const cPlanes) {
+
+    if (cPlanes != 1)
+        pm_error("Error: invalid planes value in BMP header.  Must be 1");
+}
 
 
 
 static void
 analyzeColors(xel          const colormap[],
-              unsigned int const cmapsize,
+              unsigned int const cmapSize,
               xelval       const maxval,
               bool *       const grayPresentP,
               bool *       const colorPresentP) {
-    
-    if (cmapsize == 0) {
+
+    if (cmapSize == 0) {
         /* No colormap, and we're not about to search the entire raster,
-           so we just assume it's full color 
+           so we just assume it's full color
         */
         *colorPresentP = TRUE;
         *grayPresentP = TRUE;
@@ -1333,7 +1396,7 @@ analyzeColors(xel          const colormap[],
 
         *colorPresentP = FALSE;  /* initial assumption */
         *grayPresentP = FALSE;   /* initial assumption */
-        for (i = 0; i < cmapsize; ++i) {
+        for (i = 0; i < cmapSize; ++i) {
             if (PPM_ISGRAY(colormap[i])) {
                 if (PPM_GETR(colormap[i]) != 0 &&
                     PPM_GETR(colormap[i]) != maxval)
@@ -1350,8 +1413,8 @@ static void
 warnIfOffBitsWrong(struct bmpInfoHeader const bmpHeader,
                    unsigned int         const offBits) {
 
-    if (offBits != BMPoffbits(bmpHeader.class, bmpHeader.cBitCount, 
-                              bmpHeader.cmapsize)) {
+    if (offBits != BMPoffbits(bmpHeader.class, bmpHeader.cBitCount,
+                              bmpHeader.cmapSize)) {
 
         pm_message("warning: the BMP header says the raster starts "
                    "at offset %u bytes into the file (offbits), "
@@ -1359,8 +1422,8 @@ warnIfOffBitsWrong(struct bmpInfoHeader const bmpHeader,
                    "the raster.  This inconsistency probably means the "
                    "input file is not a legal BMP file and is unusable.",
                    offBits,
-                   BMPoffbits(bmpHeader.class, bmpHeader.cBitCount, 
-                              bmpHeader.cmapsize));
+                   BMPoffbits(bmpHeader.class, bmpHeader.cBitCount,
+                              bmpHeader.cmapSize));
     }
 }
 
@@ -1374,8 +1437,8 @@ readColorMap(FILE *               const ifP,
 
     unsigned int bytesRead;
 
-    bmpReadColormap(ifP, bmpHeader.class, 
-                    colorMapP, bmpHeader.cmapsize, &bytesRead);
+    bmpReadColormap(ifP, bmpHeader.class,
+                    colorMapP, bmpHeader.cmapSize, &bytesRead);
 
     *posP += bytesRead;
 }
@@ -1385,7 +1448,7 @@ readColorMap(FILE *               const ifP,
 static void
 readRaster(FILE *               const ifP,
            struct bmpInfoHeader const bmpHeader,
-           unsigned char ***    const bmpRasterP, 
+           unsigned char ***    const bmpRasterP,
            unsigned int *       const posP) {
 
     unsigned int bytesRead;
@@ -1419,16 +1482,16 @@ isValidBmpBpp(unsigned int const cBitCount) {
 
 
 static void
-readBmp(FILE *               const ifP, 
-        unsigned char ***    const bmpRasterP, 
-        unsigned int *       const colsP, 
+readBmp(FILE *               const ifP,
+        unsigned char ***    const bmpRasterP,
+        unsigned int *       const colsP,
         unsigned int *       const rowsP,
-        bool *               const grayPresentP, 
+        bool *               const grayPresentP,
         bool *               const colorPresentP,
-        unsigned int *       const cBitCountP, 
+        unsigned int *       const cBitCountP,
         struct pixelformat * const pixelformatP,
         xel **               const colormapP,
-        unsigned int *       const cmapsizeP,
+        unsigned int *       const cmapSizeP,
         bool                 const verbose) {
 
     xel * colormap;  /* malloc'ed */
@@ -1436,13 +1499,13 @@ readBmp(FILE *               const ifP,
         /* Current byte position in the BMP file */
 
     /* The following are all information from the BMP headers */
-    
+
     unsigned int offBits;
         /* Byte offset into file of raster */
     struct bmpInfoHeader bmpHeader;
 
     pos = 0;  /* Starting at the beginning ... */
-    { 
+    {
         unsigned int bytesRead;
         bmpReadfileheader(ifP, &bytesRead, &offBits);
         pos += bytesRead;
@@ -1462,11 +1525,13 @@ readBmp(FILE *               const ifP,
 
     reportHeader(bmpHeader, offBits, verbose);
 
+    validateCPlanes(bmpHeader.cPlanes);
+
     warnIfOffBitsWrong(bmpHeader, offBits);
 
     readColorMap(ifP, bmpHeader, &colormap, &pos);
 
-    analyzeColors(colormap, bmpHeader.cmapsize, bmpMaxval, 
+    analyzeColors(colormap, bmpHeader.cmapSize, bmpMaxval,
                   grayPresentP, colorPresentP);
 
     readOffBytes(ifP, offBits - pos);
@@ -1477,7 +1542,7 @@ readBmp(FILE *               const ifP,
 
     if (fgetc(ifP) != EOF)
         pm_message("warning: some image data remains unread.");
-    
+
     if (!isValidBmpBpp(bmpHeader.cBitCount))
         pm_error("Invalid BMP image: 'cBitCount' field of header "
                  "(number of bits for each pixel in raster) is %u",
@@ -1489,23 +1554,23 @@ readBmp(FILE *               const ifP,
     *rowsP        = bmpHeader.rows;
     *pixelformatP = bmpHeader.pixelformat;
     *colormapP    = colormap;
-    *cmapsizeP    = bmpHeader.cmapsize;
+    *cmapSizeP    = bmpHeader.cmapSize;
 }
 
 
 
 static void
 writeRasterGen(unsigned char **   const bmpRaster,
-               unsigned int       const cols, 
-               unsigned int       const rows, 
+               unsigned int       const cols,
+               unsigned int       const rows,
                int                const format,
-               unsigned int       const cBitCount, 
+               unsigned int       const cBitCount,
                struct pixelformat const pixelformat,
                xel                const colormap[],
-               unsigned int       const cmapsize) {
+               unsigned int       const cmapSize) {
 /*----------------------------------------------------------------------------
   Write the PNM raster to Standard Output, corresponding to the raw BMP
-  raster bmpRaster.  Write the raster assuming the PNM image has 
+  raster bmpRaster.  Write the raster assuming the PNM image has
   dimensions 'cols' by 'rows' and format 'format', with maxval 255.
 
   The BMP image has 'cBitCount' bits per pixel, arranged in format
@@ -1513,7 +1578,7 @@ writeRasterGen(unsigned char **   const bmpRaster,
 
   If the image is colormapped, colormap[] is the colormap
   (colormap[i] is the color with color index i).
-  
+
   writeRasterPbm() is faster for a PBM image.
 -----------------------------------------------------------------------------*/
     xel * xelrow;
@@ -1523,7 +1588,7 @@ writeRasterGen(unsigned char **   const bmpRaster,
 
     for (row = 0; row < rows; ++row) {
         convertRow(bmpRaster[row], xelrow, cols, cBitCount, pixelformat,
-                   colormap, cmapsize);
+                   colormap, cmapSize);
         pnm_writepnmrow(stdout, xelrow, cols, bmpMaxval, format, FALSE);
     }
     pnm_freerow(xelrow);
@@ -1533,12 +1598,12 @@ writeRasterGen(unsigned char **   const bmpRaster,
 
 static void
 writeRasterPbm(unsigned char ** const bmpRaster,
-               unsigned int     const cols, 
-               unsigned int     const rows, 
+               unsigned int     const cols,
+               unsigned int     const rows,
                xel              const colormap[]) {
 /*----------------------------------------------------------------------------
   Write the PBM raster to Standard Output corresponding to the raw BMP
-  raster bmpRaster.  Write the raster assuming the PBM image has 
+  raster bmpRaster.  Write the raster assuming the PBM image has
   dimensions 'cols' by 'rows'.
 
   The BMP image has 'cBitCount' bits per pixel, arranged in format
@@ -1548,28 +1613,28 @@ writeRasterPbm(unsigned char ** const bmpRaster,
   (colormap[i] is the color with color index i).  We cannot handle the
   abnormal case in which colormap[0] and colormap[1] have the same
   value (i.e. both white or both black.)
-  
+
   We destroy *bmpRaster as a side effect.
 -----------------------------------------------------------------------------*/
     unsigned int const colCharCt = pbm_packed_bytes(cols);
-    
+
     unsigned int row;
     enum colorFormat {BlackWhite, WhiteBlack};
     enum colorFormat colorformat;
-                  
+
     if (PPM_GETR(colormap[0]) > 0)
         colorformat = WhiteBlack;
-    else                  
+    else
         colorformat = BlackWhite;
-        
+
     for (row = 0; row < rows; ++row){
-        unsigned char * const bitrow = bmpRaster[row]; 
+        unsigned char * const bitrow = bmpRaster[row];
 
         if (colorformat == BlackWhite) {
             unsigned int i;
-            for (i = 0; i < colCharCt; ++i) 
-                bitrow[i] = ~bitrow[i]; /* flip all pixels */ 
-        }   
+            for (i = 0; i < colCharCt; ++i)
+                bitrow[i] = ~bitrow[i]; /* flip all pixels */
+        }
 
         pbm_cleanrowend_packed(bitrow, cols);
         pbm_writepbmrow_packed(stdout, bitrow, cols, FALSE);
@@ -1605,13 +1670,12 @@ main(int argc, const char ** argv) {
         /* Malloc'ed colormap (palette) from the BMP.  Contents of map
            undefined if not a colormapped BMP.
          */
-    unsigned int cmapsize;
-        /* Number of colormap entries.  Described in the BMP header.
-           Note that a file may be 8 bits per pixel but have less than
-           256 colors.  In the 1 bit per pixel case, there should be
-           2 entries according to the official specification, but we
-           allow files with just 1.
-	 */
+    unsigned int cmapSize;
+        /* Number of colormap entries.  From BMP header.  Note that a file may
+           be 8 bits per pixel but have fewer than 256 colors.  In the 1 bit
+           per pixel case, there should be 2 entries according to the official
+           specification, but we allow files with just 1.
+        */
 
     pm_proginit(&argc, argv);
 
@@ -1620,11 +1684,11 @@ main(int argc, const char ** argv) {
     ifP = pm_openr(cmdline.inputFileName);
     if (streq(cmdline.inputFileName, "-"))
         ifname = "Standard Input";
-    else 
+    else
         ifname = cmdline.inputFileName;
 
-    readBmp(ifP, &bmpRaster, &cols, &rows, &grayPresent, &colorPresent, 
-            &cBitCount, &pixelformat, &colormap, &cmapsize,
+    readBmp(ifP, &bmpRaster, &cols, &rows, &grayPresent, &colorPresent,
+            &cBitCount, &pixelformat, &colormap, &cmapSize,
             cmdline.verbose);
     pm_close(ifP);
 
@@ -1638,14 +1702,14 @@ main(int argc, const char ** argv) {
         outputType = PBM_TYPE;
         pm_message("WRITING PBM IMAGE");
     }
-    
+
     if (outputType == PBM_TYPE  && cBitCount == 1){
         pbm_writepbminit(stdout, cols, rows, FALSE);
         writeRasterPbm(bmpRaster, cols, rows, colormap);
     } else {
         pnm_writepnminit(stdout, cols, rows, bmpMaxval, outputType, FALSE);
         writeRasterGen(bmpRaster, cols, rows, outputType, cBitCount,
-                       pixelformat, colormap, cmapsize); 
+                       pixelformat, colormap, cmapSize);
     }
     free(colormap);
     free(bmpRaster);
diff --git a/converter/other/gemtopnm.c b/converter/other/gemtopnm.c
index aac74793..d862213f 100644
--- a/converter/other/gemtopnm.c
+++ b/converter/other/gemtopnm.c
@@ -36,7 +36,7 @@
  * read 4-plane color IMG files.  Therefore changed from PBM to PPM.
  * Bryan changed it further to use the PNM facilities so it outputs
  * both PBM and PPM in the Netpbm tradition.  Name changed from
- * gemtopbm to gemtopnm.  
+ * gemtopbm to gemtopnm.
  */
 
 #include <assert.h>
@@ -50,106 +50,106 @@
 char pattern[8];
 
 static void getinit ARGS ((FILE *file, int *colsP, int *rowsP, int *padrightP,
-			   int *patlenP, int *planesP));
+               int *patlenP, int *planesP));
 
 int
 main(argc, argv)
-	int             argc;
-	char           *argv[];
+    int             argc;
+    char           *argv[];
 {
-	int     debug = 0;
-	FILE    *f;
+    int     debug = 0;
+    FILE    *f;
     int     row;
-	int     rows, cols, padright, patlen, planes;
+    int     rows, cols, padright, patlen, planes;
       /* attributes of input image */
     int type;  /* The format type (PBM/PPM) of the output image */
-	bit	*bitrow[4];
+    bit *bitrow[4];
       /* One row of input, one or four planes.  (If one, only [0] is defined)*/
     xel * xelrow;  /* One row of output */
-	const char * const usage = "[-debug] [gem IMG file]";
-	int argn;
+    const char * const usage = "[-debug] [gem IMG file]";
+    int argn;
 
 /* Process multiple planes by maintaining a separate row of bits for each
- * plane. In a single-plane image, all we have to do is write out the 
+ * plane. In a single-plane image, all we have to do is write out the
  * first plane; in a multiple-plane image, we combine them just before writing
  * out the row.
  */
-	pnm_init( &argc, argv );
-    
+    pnm_init( &argc, argv );
+
     argn = 1;
 
-	while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0')
-	  {
-	    if (pm_keymatch(argv[1], "-debug", 2))
-	      debug = 1;
-	    else
-	      pm_usage (usage);
-	    ++argn;
-	  }
+    while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0')
+      {
+        if (pm_keymatch(argv[1], "-debug", 2))
+          debug = 1;
+        else
+          pm_usage (usage);
+        ++argn;
+      }
 
-	if (argc == argn)
-		f = stdin;
-	else {
-		f = pm_openr (argv[argn]);
-		++argn;
-	}
+    if (argc == argn)
+        f = stdin;
+    else {
+        f = pm_openr (argv[argn]);
+        ++argn;
+    }
 
-	if (argn != argc)
-	  pm_usage (usage);
+    if (argn != argc)
+      pm_usage (usage);
 
-	getinit (f, &cols, &rows, &padright, &patlen, &planes);
+    getinit (f, &cols, &rows, &padright, &patlen, &planes);
 
-    if (planes == 1) 
+    if (planes == 1)
         type = PBM_TYPE;
-    else 
+    else
         type = PPM_TYPE;
 
-	pnm_writepnminit( stdout, cols, rows, MAXVAL, type, 0 );
+    pnm_writepnminit( stdout, cols, rows, MAXVAL, type, 0 );
 
-    { 
+    {
         /* allocate input row data structure */
         int plane;
-        for (plane = 0; plane < planes; plane++) 
+        for (plane = 0; plane < planes; plane++)
             bitrow[plane] = malloc (cols + padright);
     }
     xelrow = pnm_allocrow(cols+padright);   /* Output row */
 
-	for (row = 0; row < rows; ) {
+    for (row = 0; row < rows; ) {
       int linerep;
       int plane;
 
-	  linerep = 1;
-	  for (plane = 0; plane < planes; plane++) {
+      linerep = 1;
+      for (plane = 0; plane < planes; plane++) {
         int col;
-		col = 0;
-		while (col < cols) {
+        col = 0;
+        while (col < cols) {
             int c;
-			switch (c = getc(f)) {
-			case 0x80:	/* Bit String */
+            switch (c = getc(f)) {
+            case 0x80:  /* Bit String */
             {
                 int j;
-				c = getc(f);	/* Byte count */
-				if (debug)
+                c = getc(f);    /* Byte count */
+                if (debug)
                   pm_message("bit string of %d bytes", c);
-				
-				if (col + c * 8 > cols + padright)
-				  pm_error ("bad byte count");
-				for (j = 0; j < c; ++j) {
+
+                if (col + c * 8 > cols + padright)
+                  pm_error ("bad byte count");
+                for (j = 0; j < c; ++j) {
                     int cc, k;
-					cc = getc(f);
-					for (k = 0x80; k; k >>= 1) {
-						bitrow[plane][col] = (k & cc) ? 0 : 1;
-						++col;
-					}
-				}
+                    cc = getc(f);
+                    for (k = 0x80; k; k >>= 1) {
+                        bitrow[plane][col] = (k & cc) ? 0 : 1;
+                        ++col;
+                    }
+                }
             }
             break;
-			case 0:		/* Pattern run */
+            case 0:     /* Pattern run */
             {
                 int j, l;
-				c = getc(f);	/* Repeat count */
-				if (debug)
-					pm_message("pattern run of %d repetitions",	c);
+                c = getc(f);    /* Repeat count */
+                if (debug)
+                    pm_message("pattern run of %d repetitions", c);
                 /* line repeat */
                 if (c == 0) {
                     c = getc(f);
@@ -158,25 +158,25 @@ main(argc, argv)
                     linerep = getc(f);
                     break;
                 }
-				fread (pattern, 1, patlen, f);
-				if (col + c * patlen * 8 > cols + padright)
-				  pm_error ("bad pattern repeat count");
-				for (j = 0; j < c; ++j)
-					for (l = 0; l < patlen; ++l) {
+                fread (pattern, 1, patlen, f);
+                if (col + c * patlen * 8 > cols + padright)
+                  pm_error ("bad pattern repeat count");
+                for (j = 0; j < c; ++j)
+                    for (l = 0; l < patlen; ++l) {
                         int k;
-						for (k = 0x80; k; k >>= 1) {
-							bitrow[plane][col] = (k & pattern[l]) ? 0 : 1;
-							++col;
-						}
+                        for (k = 0x80; k; k >>= 1) {
+                            bitrow[plane][col] = (k & pattern[l]) ? 0 : 1;
+                            ++col;
+                        }
                     }
             }
             break;
 
-			default:	/* Solid run */
+            default:    /* Solid run */
             {
                 int l, j;
-				if (debug)
-					pm_message("solid run of %d bytes %s", c & 0x7f,
+                if (debug)
+                    pm_message("solid run of %d bytes %s", c & 0x7f,
                                c & 0x80 ? "on" : "off" );
                 /* each byte had eight bits DSB */
                 l = (c & 0x80) ? 0: 1;
@@ -185,23 +185,23 @@ main(argc, argv)
                     pm_error ("bad solid run repeat count");
                 for (j = 0; j < c; ++j) {
                     bitrow[plane][col] = l;
-					++col;
+                    ++col;
                 }
             }
-				break;
+                break;
 
-			case EOF:	/* End of file */
-				pm_error( "end of file reached" );
+            case EOF:   /* End of file */
+                pm_error( "end of file reached" );
 
-			}
-		}
+            }
+        }
                 if ( debug )
                         pm_message( "EOL plane %d row %d", plane, row );
                 if (col != cols + padright)
                         pm_error( "EOL beyond edge" );
-	  }
+      }
 
-	  if (planes == 4) {
+      if (planes == 4) {
           /* Construct a pixel from the 4 planes of bits for this row */
           int col;
           for (col = 0; col < cols; col++) {
@@ -212,21 +212,21 @@ main(argc, argv)
             const int b_bit = !bitrow[2][col];
             i = bitrow[3][col];
 
-			/* Deal with weird GEM palette - white/black/gray are
-               encoded oddly 
+            /* Deal with weird GEM palette - white/black/gray are
+               encoded oddly
             */
-			if (r_bit == g_bit && g_bit == b_bit) {
+            if (r_bit == g_bit && g_bit == b_bit) {
                 /* It's black, white, or gray */
-				if (r_bit && i) r = LIGHT;
-				else if (r_bit) r = BLACK;
-				else if (i) r = MAXVAL;
-				else r = DARK;
-				g = b = r;	
-			} else {
+                if (r_bit && i) r = LIGHT;
+                else if (r_bit) r = BLACK;
+                else if (i) r = MAXVAL;
+                else r = DARK;
+                g = b = r;
+            } else {
                 /* It's one of the twelve colored colors */
                 if (!i) {
                     /* Low intensity */
-                    r = r_bit * LIGHT; 
+                    r = r_bit * LIGHT;
                     g = g_bit * LIGHT;
                     b = b_bit * LIGHT;
                 } else {
@@ -237,21 +237,21 @@ main(argc, argv)
                 }
             }
             PPM_ASSIGN(xelrow[col], r, g, b);
-		}
-	  } else {
+        }
+      } else {
           int col;
-          for (col = 0; col < cols; col++) 
+          for (col = 0; col < cols; col++)
               PNM_ASSIGN1(xelrow[col], bitrow[0][col]);
       }
-	  while (linerep--) {
-		pnm_writepnmrow( stdout, xelrow, cols, MAXVAL, type, 0 );
-		++row;
-	  }
-	}
+      while (linerep--) {
+        pnm_writepnmrow( stdout, xelrow, cols, MAXVAL, type, 0 );
+        ++row;
+      }
+    }
     pnm_freerow(xelrow);
-	pm_close( f );
-	pm_close( stdout );
-	exit(0);
+    pm_close( f );
+    pm_close( stdout );
+    exit(0);
 }
 
 
@@ -303,3 +303,5 @@ getinit (file, colsP, rowsP, padrightP, patlenP, planesP)
     }
 }
 
+
+
diff --git a/converter/other/jbig/jbigtopnm.c b/converter/other/jbig/jbigtopnm.c
index 733ba227..0d55ccc1 100644
--- a/converter/other/jbig/jbigtopnm.c
+++ b/converter/other/jbig/jbigtopnm.c
@@ -1,22 +1,93 @@
 /*
     jbigtopnm - JBIG to PNM converter
-  
+
     This program was derived from jbgtopbm.c in Markus Kuhn's
     JBIG-KIT package by Bryan Henderson on 2000.05.11
 
     The main difference is that this version uses the Netpbm libraries.
-  
+
  */
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
+#include <limits.h>
+
 #include <jbig.h>
+
 #include "pnm.h"
+#include "shhopt.h"
+#include "mallocvar.h"
 
 #define BUFSIZE 8192
 
 
+
+typedef struct {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char * inputFileName;
+    const char * outputFileName;
+    unsigned long xmax;
+    unsigned long ymax;
+    unsigned int binary;
+    unsigned int diagnose;
+    unsigned int planeSpec;
+    unsigned int plane;
+} CmdlineInfo;
+
+
+
+static void
+parseCommandLine(int                 argc,
+                 const char ** const argv,
+                 CmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;
+
+    optStruct3 opt;
+
+    unsigned int xmaxSpec, ymaxSpec;
+
+    unsigned int option_def_index;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "binary",   OPT_FLAG, NULL,             &cmdlineP->binary,   0);
+    OPTENT3(0, "diagnose", OPT_FLAG, NULL,             &cmdlineP->diagnose, 0);
+    OPTENT3(0, "plane",    OPT_UINT, &cmdlineP->plane, &cmdlineP->planeSpec,0);
+    OPTENT3(0, "xmax",     OPT_UINT, &cmdlineP->xmax,  &xmaxSpec,           0);
+    OPTENT3(0, "ymax",     OPT_UINT, &cmdlineP->ymax,  &ymaxSpec,           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 (!xmaxSpec)
+        cmdlineP->xmax = UINT_MAX;
+    if (!ymaxSpec)
+        cmdlineP->ymax = UINT_MAX;
+
+    cmdlineP->inputFileName  = (argc-1 >= 1) ? argv[1] : "-";
+    cmdlineP->outputFileName = (argc-1 >= 2) ? argv[2] : "-";
+
+    if (argc-1 > 2)
+        pm_error("Too  many arguments: %u.  The only possible "
+                 "non-option arguments are input file name and "
+                 "output file name", argc-1);
+}
+
+
+
 static void
 collect_image (unsigned char *data, size_t len, void *image) {
     static int cursor = 0;
@@ -29,7 +100,7 @@ collect_image (unsigned char *data, size_t len, void *image) {
 
 
 
-static void 
+static void
 write_pnm (FILE *fout, const unsigned char * const image, const int bpp,
            const int rows, const int cols, const int maxval,
            const int format) {
@@ -46,22 +117,22 @@ write_pnm (FILE *fout, const unsigned char * const image, const int bpp,
         for (col = 0; col < cols; col++) {
             int j;
             for (j = 0; j < bpp; j++)
-                PNM_ASSIGN1(pnm_row[col], 
+                PNM_ASSIGN1(pnm_row[col],
                             image[(((row*cols)+col) * bpp) + j]);
         }
         pnm_writepnmrow(fout, pnm_row, cols, maxval, format, 0);
     }
-    
+
     pnm_freerow(pnm_row);
 }
 
 
 
 static void
-write_raw_pbm(FILE * const fout, 
+write_raw_pbm(FILE * const fout,
               const unsigned char * const binary_image,
               int                   const cols,
-              int                   const rows) { 
+              int                   const rows) {
 
     unsigned int const bytes_per_row = pbm_packed_bytes(cols);
 
@@ -70,7 +141,7 @@ write_raw_pbm(FILE * const fout,
     pbm_writepbminit(fout, cols, rows, 0);
 
     for (row = 0; row < rows; ++row)
-        pbm_writepbmrow_packed(fout, &binary_image[row*bytes_per_row], cols, 
+        pbm_writepbmrow_packed(fout, &binary_image[row*bytes_per_row], cols,
                                0);
 }
 
@@ -79,7 +150,7 @@ write_raw_pbm(FILE * const fout,
 /*
  *
  */
-static void 
+static void
 diagnose_bie(FILE *f)
 {
   unsigned char bih[20];
@@ -89,198 +160,153 @@ diagnose_bie(FILE *f)
   len = fread(bih, 1, 20, f);
   if (len < 20) {
     printf("Input file is %d < 20 bytes long and does therefore not "
-	   "contain an intact BIE header!\n", len);
+       "contain an intact BIE header!\n", len);
     return;
   }
 
   printf("Decomposition of BIH:\n\n  DL = %d\n  D  = %d\n  P  = %d\n"
-	 "  -  = %d\n  XD = %lu\n  YD = %lu\n  L0 = %lu\n  MX = %d\n"
-	 "  MY = %d\n",
-	 bih[0], bih[1], bih[2], bih[3],
-	 xd = ((unsigned long) bih[ 4] << 24) | ((unsigned long)bih[ 5] << 16)|
-	 ((unsigned long) bih[ 6] <<  8) | ((unsigned long) bih[ 7]),
-	 yd = ((unsigned long) bih[ 8] << 24) | ((unsigned long)bih[ 9] << 16)|
-	 ((unsigned long) bih[10] <<  8) | ((unsigned long) bih[11]),
-	 l0 = ((unsigned long) bih[12] << 24) | ((unsigned long)bih[13] << 16)|
-	 ((unsigned long) bih[14] <<  8) | ((unsigned long) bih[15]),
-	 bih[16], bih[17]);
+     "  -  = %d\n  XD = %lu\n  YD = %lu\n  L0 = %lu\n  MX = %d\n"
+     "  MY = %d\n",
+     bih[0], bih[1], bih[2], bih[3],
+     xd = ((unsigned long) bih[ 4] << 24) | ((unsigned long)bih[ 5] << 16)|
+     ((unsigned long) bih[ 6] <<  8) | ((unsigned long) bih[ 7]),
+     yd = ((unsigned long) bih[ 8] << 24) | ((unsigned long)bih[ 9] << 16)|
+     ((unsigned long) bih[10] <<  8) | ((unsigned long) bih[11]),
+     l0 = ((unsigned long) bih[12] << 24) | ((unsigned long)bih[13] << 16)|
+     ((unsigned long) bih[14] <<  8) | ((unsigned long) bih[15]),
+     bih[16], bih[17]);
   printf("  order   = %d %s%s%s%s%s\n", bih[18],
-	 bih[18] & JBG_HITOLO ? " HITOLO" : "",
-	 bih[18] & JBG_SEQ ? " SEQ" : "",
-	 bih[18] & JBG_ILEAVE ? " ILEAVE" : "",
-	 bih[18] & JBG_SMID ? " SMID" : "",
-	 bih[18] & 0xf0 ? " other" : "");
+     bih[18] & JBG_HITOLO ? " HITOLO" : "",
+     bih[18] & JBG_SEQ ? " SEQ" : "",
+     bih[18] & JBG_ILEAVE ? " ILEAVE" : "",
+     bih[18] & JBG_SMID ? " SMID" : "",
+     bih[18] & 0xf0 ? " other" : "");
   printf("  options = %d %s%s%s%s%s%s%s%s\n", bih[19],
-	 bih[19] & JBG_LRLTWO ? " LRLTWO" : "",
-	 bih[19] & JBG_VLENGTH ? " VLENGTH" : "",
-	 bih[19] & JBG_TPDON ? " TPDON" : "",
-	 bih[19] & JBG_TPBON ? " TPBON" : "",
-	 bih[19] & JBG_DPON ? " DPON" : "",
-	 bih[19] & JBG_DPPRIV ? " DPPRIV" : "",
-	 bih[19] & JBG_DPLAST ? " DPLAST" : "",
-	 bih[19] & 0x80 ? " other" : "");
+     bih[19] & JBG_LRLTWO ? " LRLTWO" : "",
+     bih[19] & JBG_VLENGTH ? " VLENGTH" : "",
+     bih[19] & JBG_TPDON ? " TPDON" : "",
+     bih[19] & JBG_TPBON ? " TPBON" : "",
+     bih[19] & JBG_DPON ? " DPON" : "",
+     bih[19] & JBG_DPPRIV ? " DPPRIV" : "",
+     bih[19] & JBG_DPLAST ? " DPLAST" : "",
+     bih[19] & 0x80 ? " other" : "");
   printf("\n  %lu stripes, %d layers, %d planes\n\n",
-	 ((yd >> bih[1]) +  ((((1UL << bih[1]) - 1) & xd) != 0) + l0 - 1) / l0,
-	 bih[1] - bih[0], bih[2]);
+     ((yd >> bih[1]) +  ((((1UL << bih[1]) - 1) & xd) != 0) + l0 - 1) / l0,
+     bih[1] - bih[0], bih[2]);
 
   return;
 }
 
 
-int main (int argc, char **argv)
+int main (int argc, const char **argv)
 {
-    FILE *fin = stdin, *fout = stdout;
-    const char *fnin = "<stdin>", *fnout = "<stdout>";
-    int i, j, result;
-    int all_args = 0, files = 0;
-    struct jbg_dec_state s;
-    char *buffer;
-    unsigned char *p;
-    size_t len, cnt;
-    unsigned long xmax = 4294967295UL, ymax = 4294967295UL;
-    int plane = -1, use_graycode = 1, diagnose = 0;
-
-    pnm_init(&argc, argv);
-
-    buffer = malloc(BUFSIZE);
-    if (!buffer)
-        pm_error("Sorry, not enough memory available!");
-
-    /* parse command line arguments */
-    for (i = 1; i < argc; i++) {
-        if (!all_args && argv[i][0] == '-') {
-            if (argv[i][1] == '\0' && files == 0)
-                ++files;
-            else {
-                for (j = 1; j > 0 && argv[i][j]; j++) {
-                    switch(tolower(argv[i][j])) {
-                    case '-' :
-                        all_args = 1;
-                        break;
-                    case 'b':
-                        use_graycode = 0;
-                        break;
-                    case 'd':
-                        diagnose = 1;
-                        break;
-                    case 'x':
-                        if (++i >= argc)
-                            pm_error("-x needs a value");
-                        xmax = atol(argv[i]);
-                        j = -1;
-                        break;
-                    case 'y':
-                        if (++i >= argc)
-                            pm_error("-y needs a value");
-                        ymax = atol(argv[i]);
-                        j = -1;
-                        break;
-                    case 'p':
-                        if (++i >= argc)
-                            pm_error("-p needs a value");
-                        plane = atoi(argv[i]);
-                        j = -1;
-                        break;
-                    default:
-                        pm_error("Unrecognized option: %c", argv[i][j]);
-                    }
-                }
-            }
-        } else {
-            switch (files++) {
-            case 0:
-                if (argv[i][0] != '-' || argv[i][1] != '\0') {
-                    fnin = argv[i];
-                    fin = fopen(fnin, "rb");
-                    if (!fin)
-                        pm_error("Can't open input file '%s'", fnin);
-                }
-                if (diagnose) {
-                    diagnose_bie(fin);
-                    exit(0);
-                }
-                break;
-            case 1:
-                fnout = argv[i];
-                fout = fopen(fnout, "wb");
-                if (!fout)
-                    pm_error("Can't open output file '%s'", fnout);
+    CmdlineInfo cmdline;
+    FILE * ifP;
+    FILE * ofP;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+    ofP = pm_openw(cmdline.outputFileName);
+
+    if (cmdline.diagnose)
+        diagnose_bie(ifP);
+    else {
+        struct jbg_dec_state s;
+        unsigned char * buffer;
+        int result;
+
+        MALLOCARRAY(buffer, BUFSIZE);
+        if (!buffer)
+            pm_error("Failed to get %u bytes of memory for buffer", BUFSIZE);
+
+        /* send input file to decoder */
+        jbg_dec_init(&s);
+        jbg_dec_maxsize(&s, cmdline.xmax, cmdline.ymax);
+        result = JBG_EAGAIN;
+        do {
+            size_t len;
+            size_t cnt;
+            unsigned char * p;
+
+            len = fread(buffer, 1, BUFSIZE, ifP);
+            if (len == 0)
                 break;
-            default:
-                pm_error("Too many non-option arguments");
+            cnt = 0;
+            p = &buffer[0];
+            while (len > 0 && (result == JBG_EAGAIN || result == JBG_EOK)) {
+                result = jbg_dec_in(&s, p, len, &cnt);
+                p += cnt;
+                len -= cnt;
+            }
+        } while (result == JBG_EAGAIN || result == JBG_EOK);
+        if (ferror(ifP))
+            pm_error("Error reading input file");
+        if (result != JBG_EOK && result != JBG_EOK_INTR)
+            pm_error("Invalid contents of input file.  %s",
+                     jbg_strerror(result));
+        if (cmdline.planeSpec && jbg_dec_getplanes(&s) <= cmdline.plane)
+            pm_error("Image has only %u planes", jbg_dec_getplanes(&s));
+
+        {
+            /* Write it out */
+
+            int rows, cols;
+            int maxval;
+            int bpp;
+            bool justOnePlane;
+            unsigned int plane_to_write;
+
+            cols = jbg_dec_getwidth(&s);
+            rows = jbg_dec_getheight(&s);
+            maxval = pm_bitstomaxval(jbg_dec_getplanes(&s));
+            bpp = (jbg_dec_getplanes(&s)+7)/8;
+
+            if (jbg_dec_getplanes(&s) == 1) {
+                justOnePlane = true;
+                plane_to_write = 0;
+            } else {
+                if (cmdline.planeSpec) {
+                    justOnePlane = true;
+                    plane_to_write = cmdline.plane;
+                } else
+                    justOnePlane = false;
             }
-        }
-    }
 
-    /* send input file to decoder */
-    jbg_dec_init(&s);
-    jbg_dec_maxsize(&s, xmax, ymax);
-    result = JBG_EAGAIN;
-    do {
-        len = fread(buffer, 1, BUFSIZE, fin);
-        if (!len) break;
-        cnt = 0;
-        p = (unsigned char *) buffer;
-        while (len > 0 && (result == JBG_EAGAIN || result == JBG_EOK)) {
-            result = jbg_dec_in(&s, p, len, &cnt);
-            p += cnt;
-            len -= cnt;
-        }
-    } while (result == JBG_EAGAIN || result == JBG_EOK);
-    if (ferror(fin)) 
-        pm_error("Problem while reading input file '%s", fnin);
-    if (result != JBG_EOK && result != JBG_EOK_INTR) 
-        pm_error("Problem with input file '%s': %s\n", 
-                 fnin, jbg_strerror(result));
-    if (plane >= 0 && jbg_dec_getplanes(&s) <= plane) 
-        pm_error("Image has only %d planes!\n", jbg_dec_getplanes(&s));
-
-    {
-        /* Write it out */
-
-        int rows, cols;
-        int maxval;
-        int bpp;
-        int plane_to_write;
-
-        cols = jbg_dec_getwidth(&s);
-        rows = jbg_dec_getheight(&s);
-        maxval = pm_bitstomaxval(jbg_dec_getplanes(&s));
-        bpp = (jbg_dec_getplanes(&s)+7)/8;
-
-        if (jbg_dec_getplanes(&s) == 1) 
-            plane_to_write = 0;
-        else 
-            plane_to_write = plane;
-
-        if (plane_to_write >= 0) {
-            /* Write just one plane */
-            unsigned char * binary_image;
-
-            pm_message("WRITING PBM FILE");
-
-            binary_image=jbg_dec_getimage(&s, plane_to_write);
-            write_raw_pbm(fout, binary_image, cols, rows);
-        } else {
-            unsigned char *image;
-            pm_message("WRITING PGM FILE");
-
-            /* Write out all the planes */
-            /* What jbig.doc doesn't tell you is that jbg_dec_merge_planes
-               delivers the image in chunks, in consecutive calls to 
-               the data-out callback function.  And a row can span two
-               chunks.
-            */
-            image = malloc(cols*rows*bpp);
-            jbg_dec_merge_planes(&s, use_graycode, collect_image, image);
-            write_pnm(fout, image, bpp, rows, cols, maxval, PGM_TYPE);
-            free(image);
+            if (justOnePlane) {
+                unsigned char * binary_image;
+
+                pm_message("WRITING PBM FILE");
+
+                binary_image=jbg_dec_getimage(&s, plane_to_write);
+                write_raw_pbm(ofP, binary_image, cols, rows);
+            } else {
+                unsigned char *image;
+                pm_message("WRITING PGM FILE");
+
+                /* Write out all the planes */
+                /* What jbig.doc doesn't tell you is that jbg_dec_merge_planes
+                   delivers the image in chunks, in consecutive calls to
+                   the data-out callback function.  And a row can span two
+                   chunks.
+                */
+                image = malloc(cols*rows*bpp);
+                jbg_dec_merge_planes(&s, !cmdline.binary, collect_image,
+                                     image);
+                write_pnm(ofP, image, bpp, rows, cols, maxval, PGM_TYPE);
+                free(image);
+            }
+            jbg_dec_free(&s);
         }
-    }
-  
-    pm_close(fout);
-
-    jbg_dec_free(&s);
 
+        pm_close(ofP);
+        pm_close(ifP);
+        free(buffer);
+    }
     return 0;
 }
+
+
+
diff --git a/converter/other/jbig/libjbig/jbig.c b/converter/other/jbig/libjbig/jbig.c
index ba9c6452..e8141070 100644
--- a/converter/other/jbig/libjbig/jbig.c
+++ b/converter/other/jbig/libjbig/jbig.c
@@ -22,7 +22,7 @@
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- * 
+ *
  *  If you want to use this program under different license conditions,
  *  then contact the author for an arrangement.
  */
@@ -66,7 +66,7 @@
 
 /* object code version id */
 
-const char jbg_version[] = 
+const char jbg_version[] =
   "JBIG-KIT " JBG_VERSION " -- (c) 1995-2014 Markus Kuhn -- "
   "Licence: " JBG_LICENCE "\n";
 
@@ -115,7 +115,7 @@ static const char *errmsg[] = {
  * then simply add the necessary semaphores or mutex primitives below.
  * In contrast to C's malloc() and realloc(), but like C's calloc(),
  * these functions take two parameters nmemb and size that are multiplied
- * before being passed on to the corresponding C function. 
+ * before being passed on to the corresponding C function.
  * This we can catch all overflows during a size_t multiplication a
  * a single place.
  */
@@ -135,7 +135,7 @@ static void *checked_malloc(size_t nmemb, size_t size)
   /* assert that nmemb * size <= SIZE_MAX */
   if (size > SIZE_MAX / nmemb)
     abort();
-  
+
   p = malloc(nmemb * size);
 
   if (!p)
@@ -161,7 +161,7 @@ static void *checked_realloc(void *ptr, size_t nmemb, size_t size)
   /* assert that nmemb * size <= SIZE_MAX */
   if (size > SIZE_MAX / nmemb)
     abort();
-  
+
   p = realloc(ptr, nmemb * size);
 
   if (!p)
@@ -210,7 +210,7 @@ static void checked_free(void *ptr)
 static struct jbg_buf *jbg_buf_init(struct jbg_buf **free_list)
 {
   struct jbg_buf *new_block;
-  
+
   /* Test whether a block from the free list is available */
   if (*free_list) {
     new_block = *free_list;
@@ -236,13 +236,13 @@ static struct jbg_buf *jbg_buf_init(struct jbg_buf **free_list)
 static void jbg_buf_free(struct jbg_buf **free_list)
 {
   struct jbg_buf *tmp;
-  
+
   while (*free_list) {
     tmp = (*free_list)->next;
     checked_free(*free_list);
     *free_list = tmp;
   }
-  
+
   return;
 }
 
@@ -306,7 +306,7 @@ static void jbg_buf_remove_zeros(struct jbg_buf *head)
    */
   if (head->last->len && head->last->d[head->last->len - 1] == MARKER_ESC)
     jbg_buf_write(MARKER_STUFF, head);
- 
+
   return;
 }
 
@@ -322,7 +322,7 @@ static void jbg_buf_prefix(struct jbg_buf *new_prefix, struct jbg_buf **start)
   new_prefix->last->next->previous = new_prefix->last;
   new_prefix->last = new_prefix->last->next->last;
   *start = new_prefix;
-  
+
   return;
 }
 
@@ -339,7 +339,7 @@ static void jbg_buf_output(struct jbg_buf **head,
 			void *file)
 {
   struct jbg_buf *tmp;
-  
+
   while (*head) {
     data_out((*head)->d, (*head)->len, file);
     tmp = (*head)->next;
@@ -347,7 +347,7 @@ static void jbg_buf_output(struct jbg_buf **head,
     *(*head)->free_list = *head;
     *head = tmp;
   }
-  
+
   return;
 }
 
@@ -362,7 +362,7 @@ static void jbg_buf_output(struct jbg_buf **head,
 unsigned long jbg_ceil_half(unsigned long x, int n)
 {
   unsigned long mask;
-  
+
   assert(n >= 0 && n < 32);
   mask = (1UL << n) - 1;     /* the lowest n bits are 1 here */
   return (x >> n) + ((mask & x) != 0);
@@ -794,7 +794,7 @@ void jbg_enc_init(struct jbg_enc_state *s, unsigned long x, unsigned long y,
   s->comment = NULL;
   s->dppriv = jbg_dptable;
   s->res_tab = jbg_resred;
-  
+
   s->highres = (int *) checked_malloc(planes, sizeof(int));
   s->lhp[0] = p;
   s->lhp[1] = (unsigned char **)
@@ -804,9 +804,9 @@ void jbg_enc_init(struct jbg_enc_state *s, unsigned long x, unsigned long y,
     s->lhp[1][i] = (unsigned char *)
       checked_malloc(jbg_ceil_half(y, 1), jbg_ceil_half(x, 1+3));
   }
-  
+
   s->free_list = NULL;
-  s->s = (struct jbg_arenc_state *) 
+  s->s = (struct jbg_arenc_state *)
     checked_malloc(s->planes, sizeof(struct jbg_arenc_state));
   s->tx = (int *) checked_malloc(s->planes, sizeof(int));
   lx = jbg_ceil_half(x, 1);
@@ -828,9 +828,9 @@ void jbg_enc_init(struct jbg_enc_state *s, unsigned long x, unsigned long y,
  * l0 (height of one stripe in the lowest resolution layer) is
  * selected, which obeys the recommended limitations for l0 in annex A
  * and C of the JBIG standard. The selected number of resolution layers
- * is returned. 
+ * is returned.
  */
-int jbg_enc_lrlmax(struct jbg_enc_state *s, unsigned long x, 
+int jbg_enc_lrlmax(struct jbg_enc_state *s, unsigned long x,
 		   unsigned long y)
 {
   for (s->d = 0; s->d < 6; s->d++)
@@ -844,8 +844,8 @@ int jbg_enc_lrlmax(struct jbg_enc_state *s, unsigned long x,
 
 
 /*
- * As an alternative to jbg_enc_lrlmax(), the following function allows
- * to specify the number of layers directly. The stripe height and layer
+ * As an alternative to jbg_enc_lrlmax(), the following function allows the
+ * user to specify the number of layers directly. The stripe height and layer
  * range is also adjusted automatically here.
  */
 void jbg_enc_layers(struct jbg_enc_state *s, int d)
@@ -877,9 +877,9 @@ int jbg_enc_lrange(struct jbg_enc_state *s, int dl, int dh)
 
 
 /*
- * The following function allows to specify the bits describing the
- * options of the format as well as the maximum AT movement window and
- * the number of layer 0 lines per stripes.
+ * The following function allows the user to specify the bits describing the
+ * options of the format as well as the maximum AT movement window and the
+ * number of layer 0 lines per stripes.
  */
 void jbg_enc_options(struct jbg_enc_state *s, int order, int options,
 		     unsigned long l0, int mx, int my)
@@ -955,7 +955,7 @@ static void encode_sde(struct jbg_enc_state *s,
   hp = s->lhp[s->highres[plane]][plane] + stripe * hl * hbpl;
   lp2 = s->lhp[1 - s->highres[plane]][plane] + stripe * ll * lbpl;
   lp1 = lp2 + lbpl;
-  
+
   /* check whether we can refer to any state of a previous stripe */
   reset = (stripe == 0) || (s->options & JBG_SDRST);
 
@@ -1033,7 +1033,7 @@ static void encode_sde(struct jbg_enc_state *s,
 	at_determined = 1;
       }
       assert(s->tx[plane] >= 0); /* i.e., tx can safely be cast to unsigned */
-      
+
       /* typical prediction */
       if (s->options & JBG_TPBON) {
 	ltp = 1;
@@ -1064,11 +1064,11 @@ static void encode_sde(struct jbg_enc_state *s,
        *          76543210765432107654321076543210     line_h2
        *  76543210765432107654321X76543210             line_h1
        */
-      
+
       line_h1 = line_h2 = line_h3 = 0;
       if (i > 0 || !reset) line_h2 = (long)*(hp - hbpl) << 8;
       if (i > 1 || !reset) line_h3 = (long)*(hp - hbpl - hbpl) << 8;
-      
+
       /* encode line */
       for (j = 0; j < hx; hp++) {
 	line_h1 |= *hp;
@@ -1175,7 +1175,7 @@ static void encode_sde(struct jbg_enc_state *s,
     /*
      *  Encode differential layer
      */
-    
+
     for (i = 0; i < hl && y < hy; i++, y++) {
 
       /* check whether it is worth to perform an ATMOVE */
@@ -1211,7 +1211,7 @@ static void encode_sde(struct jbg_enc_state *s,
 	}
 	at_determined = 1;
       }
-      
+
       if ((i >> 1) >= ll - 1 || (y >> 1) >= ly - 1)
 	lp1 = lp2;
 
@@ -1297,7 +1297,7 @@ static void encode_sde(struct jbg_enc_state *s,
        *            76543210 7654321Y 76543210 76543210     line_l2
        *            76543210 76543210 76543210 76543210     line_l1
        */
-      
+
 
       line_h1 = line_h2 = line_h3 = line_l1 = line_l2 = line_l3 = 0;
       if (i > 0 || !reset) line_h2 = (long)*(hp - hbpl) << 8;
@@ -1307,7 +1307,7 @@ static void encode_sde(struct jbg_enc_state *s,
       }
       line_l2 = (long)*lp2 << 8;
       line_l1 = (long)*lp1 << 8;
-      
+
       /* encode line */
       for (j = 0; j < hx; lp1++, lp2++) {
 	if ((j >> 1) < lbpl * 8 - 8) {
@@ -1401,8 +1401,8 @@ static void encode_sde(struct jbg_enc_state *s,
 #endif
 			continue;
 		      }
-		    }	
-		  }	
+		    }
+		  }
 		}
 
 		/* determine context */
@@ -1435,7 +1435,7 @@ static void encode_sde(struct jbg_enc_state *s,
 #ifdef DEBUG
 		encoded_pixels++;
 #endif
-		
+
 		/* statistics for adaptive template changes */
 		if (!at_determined && j >= s->mx) {
 		  c[0] += !(((line_h2 >> 6) ^ line_h1) & 0x100);
@@ -1443,7 +1443,7 @@ static void encode_sde(struct jbg_enc_state *s,
 		    c[t] += !(((line_h1 >> t) ^ line_h1) & 0x100);
 		  ++c_all;
 		}
-		
+
 	      } while (++j & 1 && j < hx);
 	  } while (j & 7 && j < hx);
 	  hp++;
@@ -1455,10 +1455,10 @@ static void encode_sde(struct jbg_enc_state *s,
 	lp1 -= lbpl;
 	lp2 -= lbpl;
       }
-      
+
     } /* for (i = ...) */
   }
-  
+
   arith_encode_flush(se);
   jbg_buf_remove_zeros(s->sde[stripe][layer][plane]);
   jbg_buf_write(MARKER_ESC, s->sde[stripe][layer][plane]);
@@ -1539,7 +1539,7 @@ static void resolution_reduction(struct jbg_enc_state *s, int plane,
   hp1 = hp2 + hbpl;
   hp3 = hp2 - hbpl;
   lp = s->lhp[1 - s->highres[plane]][plane];
-  
+
 #ifdef DEBUG
   fprintf(stderr, "resolution_reduction: plane = %d, higher_layer = %d\n",
 	  plane, higher_layer);
@@ -1606,7 +1606,7 @@ static void resolution_reduction(struct jbg_enc_state *s, int plane,
   {
     FILE *f;
     char fn[50];
-    
+
     sprintf(fn, "dbg_d=%02d.pbm", higher_layer - 1);
     f = fopen(fn, "wb");
     fprintf(f, "P4\n%lu %lu\n", lx, ly);
@@ -1619,7 +1619,7 @@ static void resolution_reduction(struct jbg_enc_state *s, int plane,
 }
 
 
-/* 
+/*
  * This function is called inside the three loops of jbg_enc_out() in
  * order to write the next SDE. It has first to generate the required
  * SDE and all SDEs which have to be encoded before this SDE can be
@@ -1640,7 +1640,7 @@ static void output_sde(struct jbg_enc_state *s,
   int lfcl;     /* lowest fully coded layer */
   long i;
   unsigned long u;
-  
+
   assert(s->sde[stripe][layer][plane] != SDE_DONE);
 
   if (s->sde[stripe][layer][plane] != SDE_TODO) {
@@ -1677,7 +1677,7 @@ static void output_sde(struct jbg_enc_state *s,
     if (lfcl > 1)
       resolution_reduction(s, plane, lfcl - 1);
   }
-  
+
   encode_sde(s, stripe, layer, plane);
 
 #ifdef DEBUG
@@ -1685,14 +1685,14 @@ static void output_sde(struct jbg_enc_state *s,
 #endif
   jbg_buf_output(&s->sde[stripe][layer][plane], s->data_out, s->file);
   s->sde[stripe][layer][plane] = SDE_DONE;
-  
+
   if (stripe == s->stripes - 1 && layer > 0 &&
       s->sde[0][layer-1][plane] == SDE_TODO) {
     s->highres[plane] ^= 1;
     if (layer > 1)
       resolution_reduction(s, plane, layer - 1);
   }
-  
+
   return;
 }
 
@@ -1727,7 +1727,7 @@ void jbg_int2dppriv(unsigned char *dptable, const char *internal)
   int trans1[ 9] = { 1, 0, 3, 2, 8, 7, 6, 5, 4 };
   int trans2[11] = { 1, 0, 3, 2, 10, 9, 8, 7, 6, 5, 4 };
   int trans3[12] = { 1, 0, 3, 2, 11, 10, 9, 8, 7, 6, 5, 4 };
-  
+
   for (i = 0; i < 1728; dptable[i++] = 0) ;
 
 #define FILL_TABLE1(offset, len, trans) \
@@ -1760,7 +1760,7 @@ void jbg_dppriv2int(char *internal, const unsigned char *dptable)
   int trans1[ 9] = { 1, 0, 3, 2, 8, 7, 6, 5, 4 };
   int trans2[11] = { 1, 0, 3, 2, 10, 9, 8, 7, 6, 5, 4 };
   int trans3[12] = { 1, 0, 3, 2, 11, 10, 9, 8, 7, 6, 5, 4 };
-  
+
 #define FILL_TABLE2(offset, len, trans) \
   for (i = 0; i < len; i++) { \
     k = 0; \
@@ -1788,7 +1788,7 @@ void jbg_enc_out(struct jbg_enc_state *s)
   unsigned long bpl;
   unsigned char buf[20];
   unsigned long xd, yd, y;
-  long ii[3], is[3], ie[3];    /* generic variables for the 3 nested loops */ 
+  long ii[3], is[3], ie[3];    /* generic variables for the 3 nested loops */
   unsigned long stripe;
   int layer, plane;
   int order;
@@ -1916,7 +1916,7 @@ void jbg_enc_out(struct jbg_enc_state *s)
   for (ii[0] = is[0]; ii[0] <= ie[0]; ii[0]++)
     for (ii[1] = is[1]; ii[1] <= ie[1]; ii[1]++)
       for (ii[2] = is[2]; ii[2] <= ie[2]; ii[2]++) {
-	
+
 	stripe = ii[iindex[order][STRIPE]];
 	if (s->order & JBG_HITOLO)
 	  layer = s->dh - (ii[iindex[order][LAYER]] - s->dl);
@@ -1947,7 +1947,7 @@ void jbg_enc_out(struct jbg_enc_state *s)
 	 */
 	if (s->yd1 > s->yd &&
 	    (stripe == s->stripes - 1 ||
-	     (stripe == s->stripes - 2 && 
+	     (stripe == s->stripes - 2 &&
 	      (s->dl != s->dh || s->planes > 1)))) {
 	  s->yd1 = s->yd;
 	  yd = jbg_ceil_half(s->yd, s->d - s->dh);
@@ -2015,10 +2015,10 @@ void jbg_enc_free(struct jbg_enc_state *s)
       checked_free(s->lhp[1][plane]);
     checked_free(s->lhp[1]);
   }
-  
+
   /* clear buffer for index of highres image in lhp */
   checked_free(s->highres);
-  
+
   return;
 }
 
@@ -2037,7 +2037,7 @@ const char *jbg_strerror(int errnum)
 
 
 /*
- * The constructor for a decoder 
+ * The constructor for a decoder
  */
 void jbg_dec_init(struct jbg_dec_state *s)
 {
@@ -2075,7 +2075,7 @@ void jbg_dec_maxsize(struct jbg_dec_state *s, unsigned long xmax,
 /*
  * Decode the new len PSDC bytes to which data points and add them to
  * the current stripe. Return the number of bytes which have actually
- * been read (this will be less than len if a marker segment was 
+ * been read (this will be less than len if a marker segment was
  * part of the data or if the final byte was 0xff, in which case
  * this code cannot determine whether we have a marker segment).
  */
@@ -2104,7 +2104,7 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
   se = s->s[plane] + layer - s->dl;
   se->pscd_ptr = data;
   se->pscd_end = data + len;
-  
+
   /* number of lines per stripe in highres image */
   hl = s->l0 << layer;
   /* number of lines per stripe in lowres image */
@@ -2192,7 +2192,7 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
 	/* this line is 'not typical' and has to be coded completely */
       }
       s->pseudo = 0;
-      
+
       /*
        * Layout of the variables line_h1, line_h2, line_h3, which contain
        * as bits the neighbour pixels of the currently decoded pixel X:
@@ -2201,7 +2201,7 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
        *                     76543210 76543210 76543210 76543210     line_h2
        *   76543210 76543210 76543210 76543210 X                     line_h1
        */
-      
+
       if (x == 0) {
 	line_h1 = line_h2 = line_h3 = 0;
 	if (s->i > 0 || (y > 0 && !s->reset[plane][layer - s->dl]))
@@ -2209,7 +2209,7 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
 	if (s->i > 1 || (y > 1 && !s->reset[plane][layer - s->dl]))
 	  line_h3 = (long)*(hp - hbpl - hbpl) << 8;
       }
-      
+
       /*
        * Another tiny JBIG standard bug:
        *
@@ -2313,7 +2313,7 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
 				      (line_h1 & 0x003)));
 	    if (pix < 0)
 	      goto leave;
-	    
+
 	    line_h1 = (line_h1 << 1) | pix;
 	    line_h2 <<= 1;
 	    line_h3 <<= 1;
@@ -2325,7 +2325,7 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
       x = 0;
       s->pseudo = 1;
     } /* for (i = ...) */
-    
+
   } else {
 
     /*
@@ -2376,7 +2376,7 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
        *                     76543210 76543210 Y6543210 76543210     line_l2
        *                     76543210 76543210 76543210 76543210     line_l1
        */
-      
+
 
       if (x == 0) {
 	line_h1 = line_h2 = line_h3 = line_l1 = line_l2 = line_l3 = 0;
@@ -2390,14 +2390,14 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
 	line_l2 = (long)*lp2 << 8;
 	line_l1 = (long)*lp1 << 8;
       }
-      
+
       /* decode line */
       while (x < hx) {
 	if ((x & 15) == 0)
 	  if ((x >> 1) < lbpl * 8 - 8) {
 	    line_l1 |= *(lp1 + 1);
 	    line_l2 |= *(lp2 + 1);
-	    if (s->i > 1 || 
+	    if (s->i > 1 ||
 		(y > 1 && !s->reset[plane][layer - s->dl]))
 	      line_l3 |= *(lp2 - lbpl + 1);
 	  }
@@ -2428,13 +2428,13 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
 		line_h1 = (line_h1 << 1) | (cx & 1);
 	      } while ((++x & 1) && x < hx);
 	      line_h2 <<= 2;  line_h3 <<= 2;
-	    } else 
+	    } else
 	      do {
-		
+
 		/* deterministic prediction */
 		if (s->options & JBG_DPON)
 		  if ((y & 1) == 0)
-		    if ((x & 1) == 0) 
+		    if ((x & 1) == 0)
 		      /* phase 0 */
 		      pix = s->dppriv[((line_l3 >> 15) & 0x003) |
 				      ((line_l2 >> 13) & 0x00c) |
@@ -2490,7 +2490,7 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
 		line_h1 = (line_h1 << 1) | pix;
 		line_h2 <<= 1;
 		line_h3 <<= 1;
-		
+
 	      } while ((++x & 1) && x < hx);
 	    line_l1 <<= 1; line_l2 <<= 1;  line_l3 <<= 1;
 	  } while ((x & 7) && x < hx);
@@ -2500,7 +2500,7 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
 	++lp2;
       } /* while */
       x = 0;
-      
+
       *(hp - 1) <<= hbpl * 8 - hx;
       if ((s->i & 1) == 0) {
 	/* low resolution pixels are used twice */
@@ -2508,9 +2508,9 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
 	lp2 -= lbpl;
       } else
 	s->pseudo = 1;
-      
+
     } /* for (i = ...) */
-    
+
   }
 
  leave:
@@ -2579,7 +2579,7 @@ int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
   if (s->bie_len < 20) {
     while (s->bie_len < 20 && *cnt < len)
       s->buffer[s->bie_len++] = data[(*cnt)++];
-    if (s->bie_len < 20) 
+    if (s->bie_len < 20)
       return JBG_EAGAIN;
     /* test whether this looks like a valid JBIG header at all */
     if (s->buffer[1] < s->buffer[0])
@@ -2640,7 +2640,7 @@ int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
 
     /* calculate number of stripes that will be required */
     s->stripes = jbg_stripes(s->l0, s->yd, s->d);
-    
+
     /* some initialization */
     s->ii[iindex[s->order & 7][STRIPE]] = 0;
     s->ii[iindex[s->order & 7][LAYER]] = s->dl;
@@ -2703,7 +2703,7 @@ int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
   }
 
   /* read in DPTABLE */
-  if (s->bie_len < 20 + 1728 && 
+  if (s->bie_len < 20 + 1728 &&
       (s->options & (JBG_DPON | JBG_DPPRIV | JBG_DPLAST)) ==
       (JBG_DPON | JBG_DPPRIV)) {
     assert(s->bie_len >= 20);
@@ -2711,7 +2711,7 @@ int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
       s->dppriv = (char *) checked_malloc(1728, sizeof(char));
     while (s->bie_len < 20 + 1728 && *cnt < len)
       s->dppriv[s->bie_len++ - 20] = data[(*cnt)++];
-    if (s->bie_len < 20 + 1728) 
+    if (s->bie_len < 20 + 1728)
       return JBG_EAGAIN;
     dppriv = (unsigned char *) s->dppriv;
     s->dppriv = (char *) checked_malloc(6912, sizeof(char));
@@ -2722,7 +2722,7 @@ int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
   /*
    * BID processing loop
    */
-  
+
   while (*cnt < len) {
 
     /* process floating marker segments */
@@ -2799,27 +2799,27 @@ int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
 	break;
       case MARKER_ABORT:
 	return JBG_EABORT;
-	
+
       case MARKER_SDNORM:
       case MARKER_SDRST:
 	/* decode final pixels based on trailing zero bytes */
 	decode_pscd(s, s->buffer, 2);
 
-	arith_decode_init(s->s[s->ii[iindex[s->order & 7][PLANE]]] + 
+	arith_decode_init(s->s[s->ii[iindex[s->order & 7][PLANE]]] +
 			  s->ii[iindex[s->order & 7][LAYER]] - s->dl,
 			  s->ii[iindex[s->order & 7][STRIPE]] != s->stripes - 1
 			  && s->buffer[1] != MARKER_SDRST);
-	
+
 	s->reset[s->ii[iindex[s->order & 7][PLANE]]]
 	  [s->ii[iindex[s->order & 7][LAYER]] - s->dl] =
 	    (s->buffer[1] == MARKER_SDRST);
-	
+
 	/* prepare for next SDE */
 	s->x = 0;
 	s->i = 0;
 	s->pseudo = 1;
 	s->at_moves = 0;
-	
+
 	/* increment layer/stripe/plane loop variables */
 	/* start and end value for each loop: */
 	is[iindex[s->order & 7][STRIPE]] = 0;
@@ -2840,7 +2840,7 @@ int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
 	} while (--i >= 0 && j);
 
 	s->buf_len = 0;
-	
+
 	/* check whether this have been all SDEs */
 	if (j) {
 #ifdef DEBUG
@@ -2885,7 +2885,7 @@ int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
 #endif
 	return JBG_EINVAL | 14;
       }
-      
+
     }
   }  /* of BID processing loop 'while (*cnt < len) ...' */
 
@@ -2928,7 +2928,7 @@ unsigned long jbg_dec_getheight(const struct jbg_dec_state *s)
     else
       return jbg_ceil_half(s->yd, s->d - (s->ii[0] - 1));
   }
-  
+
   return s->yd;
 }
 
@@ -2948,7 +2948,7 @@ unsigned char *jbg_dec_getimage(const struct jbg_dec_state *s, int plane)
     else
       return s->lhp[(s->ii[0] - 1) & 1][plane];
   }
-  
+
   return s->lhp[s->d & 1][plane];
 }
 
@@ -2966,11 +2966,11 @@ unsigned long jbg_dec_getsize(const struct jbg_dec_state *s)
     if (s->ii[0] < 1)
       return 0;
     else
-      return 
+      return
 	jbg_ceil_half(s->xd, s->d - (s->ii[0] - 1) + 3) * /* overflow risk? */
 	jbg_ceil_half(s->yd, s->d - (s->ii[0] - 1));
   }
-  
+
   return jbg_ceil_half(s->xd, 3) * s->yd;
 }
 
@@ -2988,17 +2988,17 @@ unsigned long jbg_dec_getsize_merged(const struct jbg_dec_state *s)
     if (s->ii[0] < 1)
       return 0;
     else
-      return 
+      return
 	jbg_ceil_half(s->xd, s->d - (s->ii[0] - 1)) * /* overflow risk? */
 	jbg_ceil_half(s->yd, s->d - (s->ii[0] - 1)) *
 	((s->planes + 7) / 8);
   }
-  
+
   return s->xd * s->yd * ((s->planes + 7) / 8);
 }
 
 
-/* 
+/*
  * The destructor function which releases any resources obtained by the
  * other decoder functions.
  */
@@ -3019,7 +3019,7 @@ void jbg_dec_free(struct jbg_dec_state *s)
     checked_free(s->lhp[0][i]);
     checked_free(s->lhp[1][i]);
   }
-  
+
   checked_free(s->s);
   checked_free(s->tx);
   checked_free(s->ty);
@@ -3061,10 +3061,10 @@ void jbg_split_planes(unsigned long x, unsigned long y, int has_planes,
   if (encode_planes > has_planes)
     encode_planes = has_planes;
   use_graycode = use_graycode != 0 && encode_planes > 1;
-  
+
   for (p = 0; p < encode_planes; p++)
     memset(dest[p], 0, bpl * y);
-  
+
   for (line = 0; line < y; line++) {                 /* lines loop */
     for (i = 0; i * 8 < x; i++) {                    /* dest bytes loop */
       for (k = 0; k < 8 && i * 8 + k < x; k++) {     /* pixel loop */
@@ -3096,11 +3096,11 @@ void jbg_split_planes(unsigned long x, unsigned long y, int has_planes,
     for (p = 0; p < encode_planes; p++)              /* right padding loop */
       dest[p][bpl * (line + 1) - 1] <<= 8 - k;
   }
-  
+
   return;
 }
 
-/* 
+/*
  * Merge the separate bit planes decoded by the JBIG decoder into an
  * integer pixel field. This is essentially the counterpart to
  * jbg_split_planes().
@@ -3121,7 +3121,7 @@ void jbg_dec_merge_planes(const struct jbg_dec_state *s, int use_graycode,
 
   /* sanity check */
   use_graycode = use_graycode != 0;
-  
+
   x = jbg_dec_getwidth(s);
   y = jbg_dec_getheight(s);
   if (x == 0 || y == 0)
@@ -3135,7 +3135,7 @@ void jbg_dec_merge_planes(const struct jbg_dec_state *s, int use_graycode,
       src = s->lhp[(s->ii[0] - 1) & 1];
   else
     src = s->lhp[s->d & 1];
-  
+
   for (line = 0; line < y; line++) {                    /* lines loop */
     for (i = 0; i * 8 < x; i++) {                       /* src bytes loop */
       for (k = 0; k < 8 && i * 8 + k < x; k++) {        /* pixel loop */
@@ -3155,10 +3155,10 @@ void jbg_dec_merge_planes(const struct jbg_dec_state *s, int use_graycode,
       }
     }
   }
-  
+
   if (bp - buf > 0)
     data_out(buf, bp - buf, file);
-  
+
   return;
 }
 
@@ -3173,7 +3173,7 @@ void jbg_dec_merge_planes(const struct jbg_dec_state *s, int use_graycode,
  *  - not enough bytes left for complete marker segment
  *  - no marker segment terminates the PSCD
  *  - unknown marker code encountered
- *  
+ *
  */
 static unsigned char *jbg_next_pscdms(unsigned char *p, size_t len)
 {
diff --git a/converter/other/jpeg2000/jpeg2ktopam.c b/converter/other/jpeg2000/jpeg2ktopam.c
index b7276241..b507f56e 100644
--- a/converter/other/jpeg2000/jpeg2ktopam.c
+++ b/converter/other/jpeg2000/jpeg2ktopam.c
@@ -62,7 +62,7 @@ parseCommandLine(int argc, char ** argv,
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENTRY */
-    OPTENT3(0, "verbose",      OPT_FLAG,   NULL, 
+    OPTENT3(0, "verbose",      OPT_FLAG,   NULL,
             &cmdlineP->verbose,   0);
     OPTENT3(0, "debuglevel",   OPT_UINT,   &cmdlineP->debuglevel,
             &debuglevelSpec,      0);
@@ -80,7 +80,7 @@ parseCommandLine(int argc, char ** argv,
         cmdlineP->inputFilename = strdup("-");  /* he wants stdin */
     else if (argc - 1 == 1)
         cmdlineP->inputFilename = strdup(argv[1]);
-    else 
+    else
         pm_error("Too many arguments.  The only argument accepted\n"
                  "is the input file specification");
 
@@ -107,11 +107,11 @@ validateJ2k(jas_stream_t * const instreamP) {
     }
 }
 
-        
+
 
 
 static void
-readJ2k(const char *   const inputFilename, 
+readJ2k(const char *   const inputFilename,
         jas_image_t ** const jasperPP) {
 
     jas_image_t * jasperP;
@@ -127,7 +127,7 @@ readJ2k(const char *   const inputFilename,
         instreamP = jas_stream_fopen(inputFilename, "rb");
         if (instreamP == NULL )
             pm_error("cannot open input image file '%s'", inputFilename);
-    } 
+    }
 
     validateJ2k(instreamP);
 
@@ -139,7 +139,7 @@ readJ2k(const char *   const inputFilename,
         pm_error("Unable to interpret JPEG-2000 input.  "
                  "The Jasper library jas_image_decode() subroutine failed.");
 
-	jas_stream_close(instreamP);
+    jas_stream_close(instreamP);
 
     *jasperPP = jasperP;
 }
@@ -150,7 +150,7 @@ static void
 getRgbComponents(int jasperCmpnt[], jas_image_t * const jasperP) {
 
     {
-        int const rc = 
+        int const rc =
             jas_image_getcmptbytype(jasperP,
                                     JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R));
         if (rc < 0)
@@ -159,12 +159,12 @@ getRgbComponents(int jasperCmpnt[], jas_image_t * const jasperP) {
         else
             jasperCmpnt[PAM_RED_PLANE] = rc;
 
-        if (jas_image_cmptsgnd(jasperP, rc)) 
+        if (jas_image_cmptsgnd(jasperP, rc))
             pm_error("Input image says it is RGB, but has signed values "
                      "for what should be the red intensities.");
     }
     {
-        int const rc = 
+        int const rc =
             jas_image_getcmptbytype(jasperP,
                                     JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G));
         if (rc < 0)
@@ -173,12 +173,12 @@ getRgbComponents(int jasperCmpnt[], jas_image_t * const jasperP) {
         else
             jasperCmpnt[PAM_GRN_PLANE] = rc;
 
-        if (jas_image_cmptsgnd(jasperP, rc)) 
+        if (jas_image_cmptsgnd(jasperP, rc))
             pm_error("Input image says it is RGB, but has signed values "
                      "for what should be the green intensities.");
     }
     {
-        int const rc = 
+        int const rc =
             jas_image_getcmptbytype(jasperP,
                                     JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B));
         if (rc < 0)
@@ -187,18 +187,18 @@ getRgbComponents(int jasperCmpnt[], jas_image_t * const jasperP) {
         else
             jasperCmpnt[PAM_BLU_PLANE] = rc;
 
-        if (jas_image_cmptsgnd(jasperP, rc)) 
+        if (jas_image_cmptsgnd(jasperP, rc))
             pm_error("Input image says it is RGB, but has signed values "
                      "for what should be the blue intensities.");
     }
-}            
+}
 
 
 
 static void
 getGrayComponent(int * jasperCmptP, jas_image_t * const jasperP) {
 
-    int const rc = 
+    int const rc =
         jas_image_getcmptbytype(jasperP,
                                 JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_GRAY_Y));
     if (rc < 0)
@@ -206,7 +206,7 @@ getGrayComponent(int * jasperCmptP, jas_image_t * const jasperP) {
                  "no gray intensity component");
     else
         *jasperCmptP = rc;
-    if (jas_image_cmptsgnd(jasperP, 0)) 
+    if (jas_image_cmptsgnd(jasperP, 0))
         pm_error("Input image says it is grayscale, but has signed values "
                  "for what should be the gray levels.");
 }
@@ -221,13 +221,13 @@ validateComponentsAlike(jas_image_t * const jasperP) {
    all the channels are the same, and abort the program if not.
 -----------------------------------------------------------------------------*/
     int cmptNo;
-    
+
     for (cmptNo = 0; cmptNo < jas_image_numcmpts(jasperP); ++cmptNo) {
-        if (jas_image_cmptwidth(jasperP, cmptNo) != 
+        if (jas_image_cmptwidth(jasperP, cmptNo) !=
             jas_image_cmptwidth(jasperP, 0))
             pm_message("Input image does not have components all the same "
                        "width.");
-        if (jas_image_cmptheight(jasperP, cmptNo) != 
+        if (jas_image_cmptheight(jasperP, cmptNo) !=
             jas_image_cmptheight(jasperP, 0))
             pm_message("Input image does not have components all the same "
                        "height.");
@@ -241,7 +241,7 @@ maxJasperComponentPrecision(jas_image_t * const jasperP) {
 
     int cmptNo;
     unsigned int max;
-    
+
     max = 1;
 
     for (cmptNo = 0; cmptNo < jas_image_numcmpts(jasperP); ++cmptNo)
@@ -262,8 +262,8 @@ computeOutputParm(jas_image_t * const jasperP,
           with the Jasper library that corresponds to Plane P of the PAM.
        */
 
-	switch (jas_clrspc_fam(jas_image_clrspc(jasperP))) {
-	case JAS_CLRSPC_FAM_GRAY:
+    switch (jas_clrspc_fam(jas_image_clrspc(jasperP))) {
+    case JAS_CLRSPC_FAM_GRAY:
         outpamP->depth = 1;
         MALLOCARRAY_NOFAIL(jasperCmptNo, 1);
         getGrayComponent(&jasperCmptNo[0], jasperP);
@@ -275,7 +275,7 @@ computeOutputParm(jas_image_t * const jasperP,
             strcpy(outpamP->tuple_type, PAM_PGM_TUPLETYPE);
         }
         break;
-	case JAS_CLRSPC_FAM_RGB:
+    case JAS_CLRSPC_FAM_RGB:
         outpamP->depth = 3;
         MALLOCARRAY_NOFAIL(jasperCmptNo, 3);
         getRgbComponents(jasperCmptNo, jasperP);
@@ -293,15 +293,15 @@ computeOutputParm(jas_image_t * const jasperP,
                 jasperCmptNo[plane] = plane;
         }
         strcpy(outpamP->tuple_type, "");
-        if (jas_image_cmptsgnd(jasperP, 0)) 
+        if (jas_image_cmptsgnd(jasperP, 0))
             pm_message("Warning: Input image has signed sample values.  "
                        "They will be represented in the PAM output in "
                        "two's complement.");
     }
     outpamP->plainformat = FALSE;
 
-	outpamP->width = jas_image_cmptwidth(jasperP, 0);
-	outpamP->height = jas_image_cmptheight(jasperP, 0);
+    outpamP->width = jas_image_cmptwidth(jasperP, 0);
+    outpamP->height = jas_image_cmptheight(jasperP, 0);
 
     validateComponentsAlike(jasperP);
 
@@ -309,7 +309,7 @@ computeOutputParm(jas_image_t * const jasperP,
         unsigned int const maxPrecision = maxJasperComponentPrecision(jasperP);
 
         outpamP->maxval = pm_bitstomaxval(maxPrecision);
-        
+
         outpamP->bytes_per_sample = (maxPrecision + 7)/8;
     }
     *jasperCmptNoP = jasperCmptNo;
@@ -320,7 +320,7 @@ computeOutputParm(jas_image_t * const jasperP,
 static void
 createMatrices(struct pam * const outpamP, jas_matrix_t *** matrixP) {
 
-    jas_matrix_t ** matrix; 
+    jas_matrix_t ** matrix;
     unsigned int plane;
 
     MALLOCARRAY_NOFAIL(matrix, outpamP->depth);
@@ -331,14 +331,14 @@ createMatrices(struct pam * const outpamP, jas_matrix_t *** matrixP) {
         if (matrix[plane] == NULL)
             pm_error("Unable to create matrix for plane %u.  "
                      "jas_matrix_create() failed.", plane);
-    }   
+    }
     *matrixP = matrix;
 }
 
 
 
 static void
-destroyMatrices(struct pam *    const outpamP, 
+destroyMatrices(struct pam *    const outpamP,
                 jas_matrix_t ** const matrix ) {
 
     unsigned int plane;
@@ -346,7 +346,7 @@ destroyMatrices(struct pam *    const outpamP,
     for (plane = 0; plane < outpamP->depth; ++plane)
         jas_matrix_destroy(matrix[plane]);
     free(matrix);
-}    
+}
 
 
 
@@ -356,7 +356,7 @@ computeComponentMaxval(struct pam *  const outpamP,
                        int           const jasperCmpt[],
                        sample **     const jasperMaxvalP,
                        bool *        const singleMaxvalP) {
-    
+
     sample * jasperMaxval;
     unsigned int plane;
 
@@ -364,7 +364,7 @@ computeComponentMaxval(struct pam *  const outpamP,
 
     *singleMaxvalP = TRUE;  /* initial assumption */
     for (plane = 0; plane < outpamP->depth; ++plane) {
-        jasperMaxval[plane] = 
+        jasperMaxval[plane] =
             pm_bitstomaxval(jas_image_cmptprec(jasperP, jasperCmpt[plane]));
         if (jasperMaxval[plane] != jasperMaxval[0])
             *singleMaxvalP = FALSE;
@@ -372,7 +372,7 @@ computeComponentMaxval(struct pam *  const outpamP,
     *jasperMaxvalP = jasperMaxval;
 }
 
-                       
+
 
 static void
 copyRowSingleMaxval(jas_seqent_t ** const jasperRow,
@@ -387,10 +387,10 @@ copyRowSingleMaxval(jas_seqent_t ** const jasperRow,
    This is significantly faster than copyRowAnyMaxval().
 -----------------------------------------------------------------------------*/
     unsigned int col;
-    
+
     for (col = 0; col < outpamP->width; ++col) {
         unsigned int plane;
-        for (plane = 0; plane < outpamP->depth; ++plane) 
+        for (plane = 0; plane < outpamP->depth; ++plane)
             tuplerow[col][plane] = jasperRow[plane][col];
     }
 }
@@ -411,12 +411,12 @@ copyRowAnyMaxval(jas_seqent_t ** const jasperRow,
    This is significantly slower than copyRowSingleMaxval().
 -----------------------------------------------------------------------------*/
     unsigned int col;
-            
+
     for (col = 0; col < outpamP->width; ++col) {
         unsigned int plane;
-        for (plane = 0; plane < outpamP->depth; ++plane) 
-            tuplerow[col][plane] = 
-                jasperRow[plane][col] * 
+        for (plane = 0; plane < outpamP->depth; ++plane)
+            tuplerow[col][plane] =
+                jasperRow[plane][col] *
                 outpamP->maxval / jasperMaxval[plane];
     }
 }
@@ -461,11 +461,11 @@ convertToPamPnm(struct pam *  const outpamP,
                                     matrix[plane]);
             if (rc != 0)
                 pm_error("jas_image_readcmpt() of row %u plane %u "
-                         "failed.", 
+                         "failed.",
                          row, plane);
             jasperRow[plane] = jas_matrix_getref(matrix[plane], 0, 0);
         }
-        if (singleMaxval) 
+        if (singleMaxval)
             copyRowSingleMaxval(jasperRow, tuplerow, outpamP);
         else
             copyRowAnyMaxval(jasperRow, tuplerow, outpamP, jasperMaxval);
@@ -489,25 +489,25 @@ main(int argc, char **argv)
     struct pam outpam;
     int * jasperCmpt;  /* malloc'ed */
        /* jaspercmpt[P] is the component number for use with the
-          Jasper library that corresponds to Plane P of the PAM.  
+          Jasper library that corresponds to Plane P of the PAM.
        */
     jas_image_t * jasperP;
 
     pnm_init(&argc, argv);
-    
+
     parseCommandLine(argc, argv, &cmdline);
-    
-    { 
+
+    {
         int rc;
-        
+
         rc = jas_init();
         if ( rc != 0 )
             pm_error("Failed to initialize Jasper library.  "
                      "jas_init() returns rc %d", rc );
     }
-    
+
     jas_setdbglevel(cmdline.debuglevel);
-    
+
     readJ2k(cmdline.inputFilename, &jasperP);
 
     outpam.file = stdout;
@@ -517,13 +517,16 @@ main(int argc, char **argv)
     computeOutputParm(jasperP, &outpam, &jasperCmpt);
 
     pnm_writepaminit(&outpam);
-    
+
     convertToPamPnm(&outpam, jasperP, jasperCmpt);
-    
+
     free(jasperCmpt);
-	jas_image_destroy(jasperP);
+    jas_image_destroy(jasperP);
 
     pm_close(stdout);
-    
+
     return 0;
 }
+
+
+
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_util.c b/converter/other/jpeg2000/libjasper/jpc/jpc_util.c
index ecc4b914..fede2bef 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_util.c
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_util.c
@@ -6,14 +6,14 @@
  */
 
 /* __START_OF_JASPER_LICENSE__
- * 
+ *
  * JasPer Software License
- * 
+ *
  * IMAGE POWER JPEG-2000 PUBLIC LICENSE
  * ************************************
- * 
+ *
  * GRANT:
- * 
+ *
  * Permission is hereby granted, free of charge, to any person (the "User")
  * obtaining a copy of this software and associated documentation, to deal
  * in the JasPer Software without restriction, including without limitation
@@ -21,22 +21,22 @@
  * and/or sell copies of the JasPer Software (in source and binary forms),
  * and to permit persons to whom the JasPer Software is furnished to do so,
  * provided further that the License Conditions below are met.
- * 
+ *
  * License Conditions
  * ******************
- * 
+ *
  * A.  Redistributions of source code must retain the above copyright notice,
  * and this list of conditions, and the following disclaimer.
- * 
+ *
  * B.  Redistributions in binary form must reproduce the above copyright
  * notice, and this list of conditions, and the following disclaimer in
  * the documentation and/or other materials provided with the distribution.
- * 
+ *
  * C.  Neither the name of Image Power, Inc. nor any other contributor
  * (including, but not limited to, the University of British Columbia and
  * Michael David Adams) may be used to endorse or promote products derived
  * from this software without specific prior written permission.
- * 
+ *
  * D.  User agrees that it shall not commence any action against Image Power,
  * Inc., the University of British Columbia, Michael David Adams, or any
  * other contributors (collectively "Licensors") for infringement of any
@@ -56,17 +56,17 @@
  * trade dress, or service mark rights); and (v) divisions, continuations,
  * renewals, reissues and extensions of the foregoing (as and to the extent
  * applicable) now existing, hereafter filed, issued or acquired.
- * 
+ *
  * E.  If User commences an infringement action against any Licensor(s) then
  * such Licensor(s) shall have the right to terminate User's license and
  * all sublicenses that have been granted hereunder by User to other parties.
- * 
+ *
  * F.  This software is for use only in hardware or software products that
  * are compliant with ISO/IEC 15444-1 (i.e., JPEG-2000 Part 1).  No license
  * or right to this Software is granted for products that do not comply
  * with ISO/IEC 15444-1.  The JPEG-2000 Part 1 standard can be purchased
  * from the ISO.
- * 
+ *
  * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
  * NO USE OF THE JASPER SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER
  * THIS DISCLAIMER.  THE JASPER SOFTWARE IS PROVIDED BY THE LICENSORS AND
@@ -106,7 +106,7 @@
  * TECHNOLOGY OR PRODUCTS FOR HIGH RISK ACTIVITIES AND WILL ENSURE THAT ITS
  * CUSTOMERS AND END-USERS OF ITS PRODUCTS ARE PROVIDED WITH A COPY OF THE
  * NOTICE SPECIFIED IN THIS SECTION.
- * 
+ *
  * __END_OF_JASPER_LICENSE__
  */
 
diff --git a/converter/other/jpeg2000/pamtojpeg2k.c b/converter/other/jpeg2000/pamtojpeg2k.c
index 1272a422..4d73316a 100644
--- a/converter/other/jpeg2000/pamtojpeg2k.c
+++ b/converter/other/jpeg2000/pamtojpeg2k.c
@@ -98,7 +98,7 @@ parseCommandLine(int argc, char ** argv,
     char * modeOpt;
 
     unsigned int option_def_index;
-    
+
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENTRY */
@@ -134,25 +134,25 @@ parseCommandLine(int argc, char ** argv,
             &numrlvlsSpec,       0);
     OPTENT3(0, "numgbits",     OPT_UINT,   &cmdlineP->numgbits,
             &numgbitsSpec,       0);
-    OPTENT3(0, "nomct",        OPT_FLAG,   NULL, 
+    OPTENT3(0, "nomct",        OPT_FLAG,   NULL,
             &cmdlineP->nomct,    0);
-    OPTENT3(0, "sop",          OPT_FLAG,   NULL, 
+    OPTENT3(0, "sop",          OPT_FLAG,   NULL,
             &cmdlineP->sop,      0);
-    OPTENT3(0, "eph",          OPT_FLAG,   NULL, 
+    OPTENT3(0, "eph",          OPT_FLAG,   NULL,
             &cmdlineP->eph,      0);
-    OPTENT3(0, "lazy",         OPT_FLAG,   NULL, 
+    OPTENT3(0, "lazy",         OPT_FLAG,   NULL,
             &cmdlineP->lazy,     0);
-    OPTENT3(0, "termall",      OPT_FLAG,   NULL, 
+    OPTENT3(0, "termall",      OPT_FLAG,   NULL,
             &cmdlineP->termall,  0);
-    OPTENT3(0, "segsym",       OPT_FLAG,   NULL, 
+    OPTENT3(0, "segsym",       OPT_FLAG,   NULL,
             &cmdlineP->segsym,    0);
-    OPTENT3(0, "vcausal",      OPT_FLAG,   NULL, 
+    OPTENT3(0, "vcausal",      OPT_FLAG,   NULL,
             &cmdlineP->vcausal,   0);
-    OPTENT3(0, "pterm",        OPT_FLAG,   NULL, 
+    OPTENT3(0, "pterm",        OPT_FLAG,   NULL,
             &cmdlineP->pterm,     0);
-    OPTENT3(0, "resetprob",    OPT_FLAG,   NULL, 
+    OPTENT3(0, "resetprob",    OPT_FLAG,   NULL,
             &cmdlineP->resetprob, 0);
-    OPTENT3(0, "verbose",      OPT_FLAG,   NULL, 
+    OPTENT3(0, "verbose",      OPT_FLAG,   NULL,
             &cmdlineP->verbose,   0);
     OPTENT3(0, "debuglevel",   OPT_UINT,   &cmdlineP->debuglevel,
             &debuglevelSpec,      0);
@@ -223,7 +223,7 @@ parseCommandLine(int argc, char ** argv,
         cmdlineP->inputFilename = strdup("-");  /* he wants stdin */
     else if (argc - 1 == 1)
         cmdlineP->inputFilename = strdup(argv[1]);
-    else 
+    else
         pm_error("Too many arguments.  The only argument accepted\n"
                  "is the input file specification");
 
@@ -232,7 +232,7 @@ parseCommandLine(int argc, char ** argv,
 
 
 static void
-createJasperRaster(struct pam *  const inpamP, 
+createJasperRaster(struct pam *  const inpamP,
                    jas_image_t * const jasperP) {
 /*----------------------------------------------------------------------------
    Create the raster in the *jasperP object, reading the raster from the
@@ -254,7 +254,7 @@ createJasperRaster(struct pam *  const inpamP,
         if (matrix[plane] == NULL)
             pm_error("Unable to create matrix for plane %u.  "
                      "jas_matrix_create() failed.", plane);
-    }   
+    }
     tuplerow = pnm_allocpamrow(inpamP);
 
     jasperMaxval = pm_bitstomaxval(pm_maxvaltobits(inpamP->maxval));
@@ -271,7 +271,7 @@ createJasperRaster(struct pam *  const inpamP,
                 unsigned int jasperSample;
 
                 if (oddMaxval)
-                    jasperSample = tuplerow[col][plane] * 
+                    jasperSample = tuplerow[col][plane] *
                         jasperMaxval / inpamP->maxval;
                 else
                     jasperSample = tuplerow[col][plane];
@@ -279,16 +279,16 @@ createJasperRaster(struct pam *  const inpamP,
                 jas_matrix_set(matrix[plane], 0, col, jasperSample);
             }
         }
-        { 
+        {
             unsigned int plane;
 
             for (plane = 0; plane < inpamP->depth; ++plane) {
                 int rc;
-                rc = jas_image_writecmpt(jasperP, plane, 0, row, 
+                rc = jas_image_writecmpt(jasperP, plane, 0, row,
                                          inpamP->width, 1,
                                          matrix[plane]);
                 if (rc != 0)
-                    pm_error("jas_image_writecmpt() of plane %u failed.", 
+                    pm_error("jas_image_writecmpt() of plane %u failed.",
                              plane);
             }
         }
@@ -297,14 +297,14 @@ createJasperRaster(struct pam *  const inpamP,
     pnm_freepamrow(tuplerow);
     for (plane = 0; plane < inpamP->depth; ++plane)
         jas_matrix_destroy(matrix[plane]);
-    
+
     free(matrix);
 }
 
 
 
 static void
-createJasperImage(struct pam *   const inpamP, 
+createJasperImage(struct pam *   const inpamP,
                   jas_image_t ** const jasperPP) {
 
 	jas_image_cmptparm_t * cmptparms;
@@ -322,7 +322,7 @@ createJasperImage(struct pam *   const inpamP,
         cmptparms[plane].prec = pm_maxvaltobits(inpamP->maxval);
         cmptparms[plane].sgnd = 0;
     }
-    *jasperPP = 
+    *jasperPP =
         jas_image_create(inpamP->depth, cmptparms, JAS_CLRSPC_UNKNOWN);
     if (*jasperPP == NULL)
         pm_error("Unable to create jasper image structure.  "
@@ -371,7 +371,7 @@ convertToJasperImage(struct pam *   const inpamP,
 
 
 static void
-writeJpc(jas_image_t *      const jasperP, 
+writeJpc(jas_image_t *      const jasperP,
          struct cmdlineInfo const cmdline,
          FILE *             const ofP) {
 
@@ -383,8 +383,8 @@ writeJpc(jas_image_t *      const jasperP,
 
     /* Note: ilyrrates is a hack because we're too lazy to properly parse
        command line options to get the information and then compose
-       a proper input to Jasper.  So the user can screw things up by 
-       specifying garbage for the -ilyrrates option 
+       a proper input to Jasper.  So the user can screw things up by
+       specifying garbage for the -ilyrrates option
     */
     if (strlen(cmdline.ilyrrates) > 0)
         pm_asprintf(&ilyrratesOpt, "ilyrrates=%s", cmdline.ilyrrates);
@@ -410,7 +410,7 @@ writeJpc(jas_image_t *      const jasperP,
         */
         rateOpt[0] = '\0';
     }
-    pm_asprintf(&options, 
+    pm_asprintf(&options,
                 "imgareatlx=%u "
                 "imgareatly=%u "
                 "tilegrdtlx=%u "
@@ -428,7 +428,7 @@ writeJpc(jas_image_t *      const jasperP,
                 "numrlvls=%u "
                 "numgbits=%u "
                 "%s %s %s %s %s %s %s %s %s",
-                
+
                 cmdline.imgareatlx,
                 cmdline.imgareatly,
                 cmdline.tilegrdtlx,
@@ -471,8 +471,8 @@ writeJpc(jas_image_t *      const jasperP,
             pm_message("Using Jasper to encode to 'jpc' format with options "
                        "'%s'", options);
 
-        rc = jas_image_encode(jasperP, outStreamP, 
-                              jas_image_strtofmt((char*)"jpc"), 
+        rc = jas_image_encode(jasperP, outStreamP,
+                              jas_image_strtofmt((char*)"jpc"),
                               (char *)options);
         if (rc != 0)
             pm_error("jas_image_encode() failed to encode the JPEG 2000 "
@@ -484,11 +484,11 @@ writeJpc(jas_image_t *      const jasperP,
         int rc;
 
         rc = jas_stream_close(outStreamP);
-            
+
         if (rc != 0)
             pm_error("Failed to close output stream, "
                      "jas_stream_close() rc = %d", rc);
-    }                     
+    }
 
 	jas_image_clearfmts();
 
@@ -506,33 +506,33 @@ main(int argc, char **argv)
     jas_image_t * jasperP;
 
     pnm_init(&argc, argv);
-    
+
     parseCommandLine(argc, argv, &cmdline);
-    
-    { 
+
+    {
         int rc;
-        
+
         rc = jas_init();
         if ( rc != 0 )
             pm_error("Failed to initialize Jasper library.  "
                      "jas_init() returns rc %d", rc );
     }
-    
+
     jas_setdbglevel(cmdline.debuglevel);
-    
+
     ifP = pm_openr(cmdline.inputFilename);
-    
+
     pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
-    
+
     convertToJasperImage(&inpam, &jasperP);
-    
+
     writeJpc(jasperP, cmdline, stdout);
-    
+
 	jas_image_destroy(jasperP);
 
     pm_close(ifP);
 
     pm_close(stdout);
-    
+
     return 0;
 }
diff --git a/converter/other/pamtotga.c b/converter/other/pamtotga.c
index 27974dd3..1daa1e25 100644
--- a/converter/other/pamtotga.c
+++ b/converter/other/pamtotga.c
@@ -14,6 +14,7 @@
 #define _BSD_SOURCE  /* Make sure string.h contains strdup() */
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 
+#include <assert.h>
 #include <string.h>
 
 #include "pm_c_util.h"
@@ -27,22 +28,24 @@
 /* Max number of colors allowed for colormapped output. */
 #define MAXCOLORS 256
 
-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 *inputFilespec;  /* Filespec of input file */
-    char *outName;
+    const char *          inputFileName;
+    const char *          outName;
     enum TGAbaseImageType imgType;
-    bool defaultFormat;
-    unsigned int norle;
+    enum TGAmapType       mapType;
+    bool                  defaultFormat;
+    unsigned int          norle;
+    unsigned int          verbose;
 };
 
 
 
 static void
-parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Parse the program arguments (given by argc and argv) into a form
    the program can deal with more easily -- a cmdline_info structure.
@@ -57,38 +60,47 @@ parseCommandLine(int argc, char ** argv,
     unsigned int option_def_index;
 
     unsigned int outNameSpec;
-    unsigned int cmap, mono, rgb;
+    unsigned int cmap, cmap16, mono, rgb;
 
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0,   "name",       OPT_STRING, 
+    OPTENT3(0,   "name",       OPT_STRING,
             &cmdlineP->outName, &outNameSpec, 0);
-    OPTENT3(0,   "cmap",       OPT_FLAG, 
+    OPTENT3(0,   "cmap",       OPT_FLAG,
             NULL, &cmap, 0);
-    OPTENT3(0,   "mono",       OPT_FLAG, 
+    OPTENT3(0,   "cmap16",     OPT_FLAG,
+            NULL, &cmap16, 0);
+    OPTENT3(0,   "mono",       OPT_FLAG,
             NULL, &mono, 0);
-    OPTENT3(0,   "rgb",        OPT_FLAG, 
+    OPTENT3(0,   "rgb",        OPT_FLAG,
             NULL, &rgb, 0);
-    OPTENT3(0,   "norle",      OPT_FLAG, 
+    OPTENT3(0,   "norle",      OPT_FLAG,
             NULL, &cmdlineP->norle, 0);
-    
+    OPTENT3(0,   "verbose",    OPT_FLAG,
+            NULL, &cmdlineP->verbose, 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, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdline_p and others. */
 
-    if (cmap + mono + rgb > 1)
-        pm_error("You may specify only one of -cmap, -mono, and -rgb.");
+    if (cmap + cmap16 + mono + rgb > 1)
+        pm_error("You may specify only one of -cmap, -cmap16, "
+                 "-mono, and -rgb.");
 
-    if (cmap + mono + rgb == 0)
+    if (cmap + cmap16 + mono + rgb == 0)
         cmdlineP->defaultFormat = TRUE;
     else {
         cmdlineP->defaultFormat = FALSE;
-    
-        if (cmap)
+
+        if (cmap) {
             cmdlineP->imgType = TGA_MAP_TYPE;
-        else if (mono)
+            cmdlineP->mapType = TGA_MAPTYPE_LONG;
+        } else if (cmap16) {
+            cmdlineP->imgType = TGA_MAP_TYPE;
+            cmdlineP->mapType = TGA_MAPTYPE_SHORT;
+        } else if (mono)
             cmdlineP->imgType = TGA_MONO_TYPE;
         else if (rgb)
             cmdlineP->imgType = TGA_RGB_TYPE;
@@ -96,56 +108,22 @@ parseCommandLine(int argc, char ** argv,
 
     if (!outNameSpec)
         cmdlineP->outName = NULL;
-    
-    if (argc-1 == 0) 
-        cmdlineP->inputFilespec = "-";
+
+    if (argc-1 == 0)
+        cmdlineP->inputFileName = "-";
     else if (argc-1 != 1)
         pm_error("Program takes zero or one argument (filename).  You "
                  "specified %d", argc-1);
     else
-        cmdlineP->inputFilespec = argv[1];
-
-}
-
-
-static void
-writeTgaHeader(struct ImageHeader const tgaHeader) {
-
-    unsigned char flags;
-
-    putchar(tgaHeader.IdLength);
-    putchar(tgaHeader.CoMapType);
-    putchar(tgaHeader.ImgType);
-    putchar(tgaHeader.Index_lo);
-    putchar(tgaHeader.Index_hi);
-    putchar(tgaHeader.Length_lo);
-    putchar(tgaHeader.Length_hi);
-    putchar(tgaHeader.CoSize);
-    putchar(tgaHeader.X_org_lo);
-    putchar(tgaHeader.X_org_hi);
-    putchar(tgaHeader.Y_org_lo);
-    putchar(tgaHeader.Y_org_hi);
-    putchar(tgaHeader.Width_lo);
-    putchar(tgaHeader.Width_hi);
-    putchar(tgaHeader.Height_lo);
-    putchar(tgaHeader.Height_hi);
-    putchar(tgaHeader.PixelSize);
-    flags = (tgaHeader.AttBits & 0xf) | 
-        ((tgaHeader.Rsrvd & 0x1) << 4) |
-        ((tgaHeader.OrgBit & 0x1) << 5) | 
-        ((tgaHeader.OrgBit & 0x3) << 6);
-    putchar(flags);
+        cmdlineP->inputFileName = argv[1];
 
-    if (tgaHeader.IdLength > 0)
-        fwrite(tgaHeader.Id, 1, (int) tgaHeader.IdLength, stdout);
 }
-    
 
 
 static void
 putPixel(struct pam *          const pamP,
-         tuple                 const tuple, 
-         enum TGAbaseImageType const imgType, 
+         tuple                 const tuple,
+         enum TGAbaseImageType const imgType,
          bool                  const withAlpha,
          tuplehash             const cht) {
 /*----------------------------------------------------------------------------
@@ -167,22 +145,22 @@ putPixel(struct pam *          const pamP,
         if (imgType == TGA_RGB_TYPE && pamP->depth < 3) {
             /* Make RGB pixel out of a single input plane */
             unsigned int plane;
-            
-            for (plane = 0; plane < 3; ++plane) 
-                putchar(pnm_scalesample(tuple[0], 
+
+            for (plane = 0; plane < 3; ++plane)
+                putchar(pnm_scalesample(tuple[0],
                                         pamP->maxval, TGA_MAXVAL));
         } else if (imgType == TGA_MONO_TYPE)
-            putchar(pnm_scalesample(tuple[0], 
+            putchar(pnm_scalesample(tuple[0],
                                     pamP->maxval, TGA_MAXVAL));
         else {
-            putchar(pnm_scalesample(tuple[PAM_BLU_PLANE], 
+            putchar(pnm_scalesample(tuple[PAM_BLU_PLANE],
                                     pamP->maxval, TGA_MAXVAL));
-            putchar(pnm_scalesample(tuple[PAM_GRN_PLANE], 
+            putchar(pnm_scalesample(tuple[PAM_GRN_PLANE],
                                     pamP->maxval, TGA_MAXVAL));
-            putchar(pnm_scalesample(tuple[PAM_RED_PLANE], 
+            putchar(pnm_scalesample(tuple[PAM_RED_PLANE],
                                     pamP->maxval, TGA_MAXVAL));
             if (withAlpha)
-                putchar(pnm_scalesample(tuple[PAM_TRN_PLANE], 
+                putchar(pnm_scalesample(tuple[PAM_TRN_PLANE],
                                         pamP->maxval, TGA_MAXVAL));
         }
     }
@@ -191,39 +169,47 @@ putPixel(struct pam *          const pamP,
 
 
 static void
-putMapEntry(struct pam * const pamP, 
-            tuple        const value, 
+putMapEntry(struct pam * const pamP,
+            tuple        const value,
             int          const size) {
 
-    if (size == 15 || size == 16) {
-        /* 5 bits each of red, green, and blue.  Watch for byte order */
-
+    if (size == 8)
+        putchar(pnm_scalesample(value[0],
+                                pamP->maxval, TGA_MAXVAL));
+    else if (size == 15 || size == 16) {
         tuple const tuple31 = pnm_allocpamtuple(pamP);
 
+        assert(pamP->depth >= 3);
+
         pnm_scaletuple(pamP, tuple31, value, 31);
         {
-            int const mapentry = 
+            unsigned int const trn =
+                size == 16 && tuple31[PAM_TRN_PLANE] > 0 ? 1 : 0;
+
+            unsigned int const mapentry =
                 tuple31[PAM_BLU_PLANE] << 0 |
                 tuple31[PAM_GRN_PLANE] << 5 |
-                tuple31[PAM_RED_PLANE] << 10;
-            
+                tuple31[PAM_RED_PLANE] << 10 |
+                trn                    << 15;
+
+            /* Note little-endian byte swapping */
             putchar(mapentry % 256);
             putchar(mapentry / 256);
         }
         pnm_freepamtuple(tuple31);
-    } else if (size == 8)
-        putchar(pnm_scalesample(value[0], 
-                                pamP->maxval, TGA_MAXVAL));
-    else {
-        /* Must be 24 or 32 */
-        putchar(pnm_scalesample(value[PAM_BLU_PLANE], 
+    } else {
+        assert(size == 24 || size == 32);
+
+        assert(pamP->depth >= 3);
+
+        putchar(pnm_scalesample(value[PAM_BLU_PLANE],
                                 pamP->maxval, TGA_MAXVAL));
-        putchar(pnm_scalesample(value[PAM_GRN_PLANE], 
+        putchar(pnm_scalesample(value[PAM_GRN_PLANE],
                                 pamP->maxval, TGA_MAXVAL));
-        putchar(pnm_scalesample(value[PAM_RED_PLANE], 
+        putchar(pnm_scalesample(value[PAM_RED_PLANE],
                                     pamP->maxval, TGA_MAXVAL));
         if (size == 32)
-            putchar(pnm_scalesample(value[PAM_TRN_PLANE], 
+            putchar(pnm_scalesample(value[PAM_TRN_PLANE],
                                     pamP->maxval, TGA_MAXVAL));
     }
 }
@@ -231,8 +217,8 @@ putMapEntry(struct pam * const pamP,
 
 
 static void
-computeRunlengths(struct pam * const pamP, 
-                   tuple *      const tuplerow, 
+computeRunlengths(struct pam * const pamP,
+                   tuple *      const tuplerow,
                    int *        const runlength) {
 
     int col, start;
@@ -240,7 +226,7 @@ computeRunlengths(struct pam * const pamP,
     /* Initialize all run lengths to 0.  (This is just an error check.) */
     for (col = 0; col < pamP->width; ++col)
         runlength[col] = 0;
-    
+
     /* Find runs of identical pixels. */
     for ( col = 0; col < pamP->width; ) {
         start = col;
@@ -251,7 +237,7 @@ computeRunlengths(struct pam * const pamP,
                   pnm_tupleequal(pamP, tuplerow[col], tuplerow[start]));
         runlength[start] = col - start;
     }
-    
+
     /* Now look for runs of length-1 runs, and turn them into negative runs. */
     for (col = 0; col < pamP->width; ) {
         if (runlength[col] == 1) {
@@ -271,23 +257,23 @@ computeRunlengths(struct pam * const pamP,
 
 
 static void
-computeOutName(struct cmdlineInfo const cmdline, 
+computeOutName(struct CmdlineInfo const cmdline,
                const char **      const outNameP) {
-    
+
     char * workarea;
 
     if (cmdline.outName)
         workarea = strdup(cmdline.outName);
-    else if (streq(cmdline.inputFilespec, "-"))
+    else if (streq(cmdline.inputFileName, "-"))
         workarea = NULL;
     else {
         char * cp;
-        workarea = strdup(cmdline.inputFilespec);
+        workarea = strdup(cmdline.inputFileName);
         cp = strchr(workarea, '.');
         if (cp != NULL)
         	*cp = '\0';	/* remove extension */
     }
-    
+
     if (workarea == NULL)
         *outNameP = NULL;
     else {
@@ -306,16 +292,16 @@ validateTupleType(struct pam * const pamP) {
     if (streq(pamP->tuple_type, "RGB_ALPHA")) {
         if (pamP->depth < 4)
             pm_error("Invalid depth for tuple type RGB_ALPHA.  "
-                     "Should have at least 4 planes, but has %d.", 
+                     "Should have at least 4 planes, but has %d.",
                      pamP->depth);
     } else if (streq(pamP->tuple_type, "RGB")) {
         if (pamP->depth < 3)
             pm_error("Invalid depth for tuple type RGB.  "
-                     "Should have at least 3 planes, but has %d.", 
+                     "Should have at least 3 planes, but has %d.",
                      pamP->depth);
     } else if (streq(pamP->tuple_type, "GRAYSCALE")) {
     } else if (streq(pamP->tuple_type, "BLACKANDWHITE")) {
-    } else 
+    } else
         pm_error("Invalid type of input.  PAM tuple type is '%s'.  "
                  "This programs understands only RGB_ALPHA, RGB, GRAYSCALE, "
                  "and BLACKANDWHITE.", pamP->tuple_type);
@@ -325,69 +311,76 @@ validateTupleType(struct pam * const pamP) {
 
 static void
 computeImageType_cht(struct pam *            const pamP,
-                     struct cmdlineInfo      const cmdline, 
+                     struct CmdlineInfo      const cmdline,
                      tuple **                const tuples,
                      enum TGAbaseImageType * const baseImgTypeP,
+                     enum TGAmapType *       const mapTypeP,
                      bool *                  const withAlphaP,
                      tupletable *            const chvP,
-                     tuplehash *             const chtP, 
+                     tuplehash *             const chtP,
                      int *                   const ncolorsP) {
 
-    unsigned int ncolors;
+    unsigned int          ncolors;
     enum TGAbaseImageType baseImgType;
-    bool withAlpha;
+    enum TGAmapType       mapType;
+    bool                  withAlpha;
 
     validateTupleType(pamP);
 
-    withAlpha = (streq(pamP->tuple_type, "RGB_ALPHA"));
-
     if (cmdline.defaultFormat) {
         /* default the image type */
-        if (withAlpha) {
+        if (streq(pamP->tuple_type, "RGB_ALPHA")) {
             baseImgType = TGA_RGB_TYPE;
             *chvP = NULL;
-        } else if (pamP->depth > 1) {
+            withAlpha = true;
+        } else if (streq(pamP->tuple_type, "RGB")) {
             pm_message("computing colormap...");
-            *chvP = 
+            *chvP =
                 pnm_computetuplefreqtable(pamP, tuples, MAXCOLORS, &ncolors);
             if (*chvP == NULL) {
                 pm_message("Too many colors for colormapped TGA.  Doing RGB.");
                 baseImgType = TGA_RGB_TYPE;
-            } else 
+            } else {
                 baseImgType = TGA_MAP_TYPE;
+                mapType = TGA_MAPTYPE_LONG;
+            }
+            withAlpha = false;
         } else {
             baseImgType = TGA_MONO_TYPE;
             *chvP = NULL;
+            withAlpha = false;
         }
     } else {
+        withAlpha = (streq(pamP->tuple_type, "RGB_ALPHA"));
+
         baseImgType = cmdline.imgType;
 
         if (baseImgType == TGA_MAP_TYPE) {
+            mapType = cmdline.mapType;
+
             if (withAlpha)
                 pm_error("Can't do a colormap because image has transparency "
                          "information");
             pm_message("computing colormap...");
-            *chvP = 
+            *chvP =
                 pnm_computetuplefreqtable(pamP, tuples, MAXCOLORS, &ncolors);
-            if (*chvP == NULL) 
+            if (*chvP == NULL)
                 pm_error("Too many colors for colormapped TGA.  "
-                         "Use 'pnmquant %d' to reduce the number of colors.", 
+                         "Use 'pnmquant %d' to reduce the number of colors.",
                          MAXCOLORS);
         } else
             *chvP = NULL;
-        if (baseImgType == TGA_MONO_TYPE && pamP->depth > 1)
-            pm_error("For Mono TGA output, input must be "
-                     "GRAYSCALE or BLACKANDWHITE PAM or PBM or PGM");
     }
-    
+
     if (baseImgType == TGA_MAP_TYPE) {
-        pm_message("%d colors found.", ncolors);
+        pm_message("%u colors found.", ncolors);
         /* Make a hash table for fast color lookup. */
         *chtP = pnm_computetupletablehash(pamP, *chvP, ncolors);
     } else
         *chtP = NULL;
 
     *baseImgTypeP = baseImgType;
+    *mapTypeP     = mapType;
     *withAlphaP   = withAlpha;
     *ncolorsP     = ncolors;
 }
@@ -397,8 +390,9 @@ computeImageType_cht(struct pam *            const pamP,
 static void
 computeTgaHeader(struct pam *          const pamP,
                  enum TGAbaseImageType const baseImgType,
+                 enum TGAmapType       const mapType,
                  bool                  const withAlpha,
-                 bool                  const rle, 
+                 bool                  const rle,
                  int                   const ncolors,
                  unsigned char         const orgBit,
                  const char *          const id,
@@ -417,7 +411,7 @@ computeTgaHeader(struct pam *          const pamP,
         case TGA_RGB_TYPE:  tgaHeaderP->ImgType = TGA_RGB;           break;
         }
     }
-    
+
     if (id) {
         tgaHeaderP->IdLength = strlen(id);
         tgaHeaderP->Id = strdup(id);
@@ -429,7 +423,18 @@ computeTgaHeader(struct pam *          const pamP,
         tgaHeaderP->CoMapType = 1;
         tgaHeaderP->Length_lo = ncolors % 256;
         tgaHeaderP->Length_hi = ncolors / 256;
-        tgaHeaderP->CoSize = 8 * pamP->depth;
+        if (pamP->depth < 3)
+            tgaHeaderP->CoSize = 8;
+        else {
+            switch (mapType) {
+            case TGA_MAPTYPE_SHORT:
+                tgaHeaderP->CoSize = withAlpha ? 16 : 15;
+                break;
+            case TGA_MAPTYPE_LONG:
+                tgaHeaderP->CoSize = withAlpha ? 32 : 24;
+                break;
+            }
+        }
     } else {
         tgaHeaderP->CoMapType = 0;
         tgaHeaderP->Length_lo = 0;
@@ -441,7 +446,7 @@ computeTgaHeader(struct pam *          const pamP,
         tgaHeaderP->PixelSize = 8;
         break;
     case TGA_RGB_TYPE:
-        tgaHeaderP->PixelSize = 8 * MAX((withAlpha ? 4: 3), pamP->depth);
+        tgaHeaderP->PixelSize = 8 * (withAlpha ? 4: 3);
         break;
     case TGA_MONO_TYPE:
         tgaHeaderP->PixelSize = 8;
@@ -461,6 +466,70 @@ computeTgaHeader(struct pam *          const pamP,
 
 
 static void
+reportTgaHeader(struct ImageHeader const tgaHeader) {
+
+    switch (tgaHeader.ImgType) {
+    case TGA_RLEMono:
+        pm_message("Generating monochrome, run-length encoded");
+        break;
+    case TGA_RLEMap:
+        pm_message("Generating colormapped, run-length encoded");
+        pm_message("%u bits per colormap entry", tgaHeader.CoSize);
+        break;
+    case TGA_RLERGB:
+        pm_message("Generating RGB truecolor, run-length encoded");
+        break;
+    case TGA_Mono:
+        pm_message("Generating monochrome, uncompressed");
+        break;
+    case TGA_Map:
+        pm_message("Generating colormapped, uncompressed");
+        pm_message("%u bits per colormap entry", tgaHeader.CoSize);
+        break;
+    case TGA_RGB:
+        pm_message("Generating RGB truecolor, uncompressed");
+        break;
+    }
+    pm_message("%u bits per pixel", tgaHeader.PixelSize);
+}
+
+
+
+static void
+writeTgaHeader(struct ImageHeader const tgaHeader) {
+
+    unsigned char flags;
+
+    putchar(tgaHeader.IdLength);
+    putchar(tgaHeader.CoMapType);
+    putchar(tgaHeader.ImgType);
+    putchar(tgaHeader.Index_lo);
+    putchar(tgaHeader.Index_hi);
+    putchar(tgaHeader.Length_lo);
+    putchar(tgaHeader.Length_hi);
+    putchar(tgaHeader.CoSize);
+    putchar(tgaHeader.X_org_lo);
+    putchar(tgaHeader.X_org_hi);
+    putchar(tgaHeader.Y_org_lo);
+    putchar(tgaHeader.Y_org_hi);
+    putchar(tgaHeader.Width_lo);
+    putchar(tgaHeader.Width_hi);
+    putchar(tgaHeader.Height_lo);
+    putchar(tgaHeader.Height_hi);
+    putchar(tgaHeader.PixelSize);
+    flags = (tgaHeader.AttBits & 0xf) |
+        ((tgaHeader.Rsrvd & 0x1) << 4) |
+        ((tgaHeader.OrgBit & 0x1) << 5) |
+        ((tgaHeader.OrgBit & 0x3) << 6);
+    putchar(flags);
+
+    if (tgaHeader.IdLength > 0)
+        fwrite(tgaHeader.Id, 1, (int) tgaHeader.IdLength, stdout);
+}
+
+
+
+static void
 releaseTgaHeader(struct ImageHeader const tgaHeader) {
 
     if (tgaHeader.IdLength > 0)
@@ -469,9 +538,9 @@ releaseTgaHeader(struct ImageHeader const tgaHeader) {
 
 
 
-static void 
+static void
 writeTgaRaster(struct pam *          const pamP,
-               tuple **              const tuples, 
+               tuple **              const tuples,
                tuplehash             const cht,
                enum TGAbaseImageType const imgType,
                bool                  const withAlpha,
@@ -500,7 +569,7 @@ writeTgaRaster(struct pam *          const pamP,
                     int i;
                     putchar(-runlength[col] - 1);
                     for (i = 0; i < -runlength[col]; ++i)
-                        putPixel(pamP, tuples[realrow][col+i], 
+                        putPixel(pamP, tuples[realrow][col+i],
                                  imgType, withAlpha, cht);
                     col += -runlength[col];
                 } else
@@ -519,47 +588,53 @@ writeTgaRaster(struct pam *          const pamP,
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char **argv) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     FILE * ifP;
     tuple ** tuples;
     struct pam pam;
-    int ncolors;
+    int colorCt;
     tupletable chv;
     tuplehash cht;
     struct ImageHeader tgaHeader;
     enum TGAbaseImageType baseImgType;
+    enum TGAmapType mapType;
     bool withAlpha;
-    const char *outName;
+    const char * outName;
 
-    pnm_init( &argc, argv );
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
-    ifP = pm_openr(cmdline.inputFilespec);
+    ifP = pm_openr(cmdline.inputFileName);
 
     computeOutName(cmdline, &outName);
 
     tuples = pnm_readpam(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
     pm_close(ifP);
 
-    computeImageType_cht(&pam, cmdline, tuples, 
-                         &baseImgType, &withAlpha, &chv, &cht, &ncolors);
+    computeImageType_cht(&pam, cmdline, tuples,
+                         &baseImgType, &mapType,
+                         &withAlpha, &chv, &cht, &colorCt);
 
     /* Do the Targa header */
-    computeTgaHeader(&pam, baseImgType, withAlpha, !cmdline.norle,
-                     ncolors, 0, outName, &tgaHeader);
+    computeTgaHeader(&pam, baseImgType, mapType, withAlpha, !cmdline.norle,
+                     colorCt, 0, outName, &tgaHeader);
+
+    if (cmdline.verbose)
+        reportTgaHeader(tgaHeader);
+
     writeTgaHeader(tgaHeader);
-    
+
     if (baseImgType == TGA_MAP_TYPE) {
         /* Write out the Targa colormap. */
-        int i;
-        for (i = 0; i < ncolors; ++i)
+        unsigned int i;
+        for (i = 0; i < colorCt; ++i)
             putMapEntry(&pam, chv[i]->tuple, tgaHeader.CoSize);
     }
 
-    writeTgaRaster(&pam, tuples, cht, baseImgType, withAlpha, 
+    writeTgaRaster(&pam, tuples, cht, baseImgType, withAlpha,
                    !cmdline.norle, 0);
 
     if (cht)
diff --git a/converter/other/pamtotiff.c b/converter/other/pamtotiff.c
index 72c7dc31..115b8b4a 100644
--- a/converter/other/pamtotiff.c
+++ b/converter/other/pamtotiff.c
@@ -142,30 +142,30 @@ parseIndexbits(bool          const indexbitsSpec,
         unsigned int i;
 
         /* Set initial values */
-        cmdlineP->indexsizeAllowed.b1 = FALSE;
-        cmdlineP->indexsizeAllowed.b2 = FALSE;
-        cmdlineP->indexsizeAllowed.b4 = FALSE;
-        cmdlineP->indexsizeAllowed.b8 = FALSE;
+        cmdlineP->indexsizeAllowed.b1 = false;
+        cmdlineP->indexsizeAllowed.b2 = false;
+        cmdlineP->indexsizeAllowed.b4 = false;
+        cmdlineP->indexsizeAllowed.b8 = false;
 
         for (i = 0; indexbits[i]; ++i) {
             const char * const thisItem = indexbits[i];
             if (streq(thisItem, "1"))
-                cmdlineP->indexsizeAllowed.b1 = TRUE;
+                cmdlineP->indexsizeAllowed.b1 = true;
             else if (streq(thisItem, "2"))
-                cmdlineP->indexsizeAllowed.b2 = TRUE;
+                cmdlineP->indexsizeAllowed.b2 = true;
             else if (streq(thisItem, "4"))
-                cmdlineP->indexsizeAllowed.b4 = TRUE;
+                cmdlineP->indexsizeAllowed.b4 = true;
             else if (streq(thisItem, "8"))
-                cmdlineP->indexsizeAllowed.b8 = TRUE;
+                cmdlineP->indexsizeAllowed.b8 = true;
             else
                 pm_error("Invalid item in -indexbits list: '%s'.  "
                          "We recognize only 1, 2, 4, and 8", thisItem);
-        }           
+        }
     } else {
-        cmdlineP->indexsizeAllowed.b1 = FALSE;
-        cmdlineP->indexsizeAllowed.b2 = FALSE;
-        cmdlineP->indexsizeAllowed.b4 = FALSE;
-        cmdlineP->indexsizeAllowed.b8 = TRUE;
+        cmdlineP->indexsizeAllowed.b1 = false;
+        cmdlineP->indexsizeAllowed.b2 = false;
+        cmdlineP->indexsizeAllowed.b4 = false;
+        cmdlineP->indexsizeAllowed.b8 = true;
     }
 }
 
@@ -233,8 +233,8 @@ parseCommandLine(int                 argc,
     OPTENT3(0, "tag",          OPT_NAMELIST, &cmdlineP->taglist, &tagSpec, 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 */
+    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. */
@@ -610,7 +610,7 @@ analyzeColorsInRgbInput(struct pam *   const pamP,
 -----------------------------------------------------------------------------*/
     if (cmdline.color && cmdline.truecolor) {
         *chvP = NULL;
-        *grayscaleP = FALSE;
+        *grayscaleP = false;
     } else {
         tupletable chv;
         bool grayscale;
@@ -620,15 +620,15 @@ analyzeColorsInRgbInput(struct pam *   const pamP,
                                          pamP->maxval,
                                          colorCtP);
         if (chv == NULL) {
-            grayscale = FALSE;
+            grayscale = false;
         } else {
             unsigned int i;
             pm_message("%u color%s found",
                        *colorCtP, *colorCtP == 1 ? "" : "s");
-            grayscale = TRUE;  /* initial assumption */
+            grayscale = true;  /* initial assumption */
             for (i = 0; i < *colorCtP && grayscale; ++i) {
                 if (!pnm_rgbtupleisgray(chv[i]->tuple))
-                    grayscale = FALSE;
+                    grayscale = false;
             }
         }
         *grayscaleP = grayscale;
@@ -686,7 +686,7 @@ analyzeColors(struct pam *   const pamP,
                                 chvP, colorCtP, grayscaleP);
     else {
         *chvP = NULL;
-        *grayscaleP = TRUE;
+        *grayscaleP = true;
     }
 }
 
@@ -727,7 +727,7 @@ computeRasterParm(struct pam *     const pamP,
    Compute the parameters of the raster portion of the TIFF image.
 
    'minisblack' and 'miniswhite' mean the user requests the corresponding
-   photometric.  Both FALSE means user has no explicit requirement.
+   photometric.  Both false means user has no explicit requirement.
 -----------------------------------------------------------------------------*/
     unsigned short defaultPhotometric;
     /* The photometric we use if the user specified no preference */
@@ -813,9 +813,9 @@ computeRasterParm(struct pam *     const pamP,
 /*----------------------------------------------------------------------------
   WRITE MODES
   -----------
-  
+
   The Tiff library does all output.  There are several issues:
-  
+
     1) The manner of output is opaque to the library client.  I.e.  we cannot
        see or control it.
 
@@ -826,22 +826,22 @@ computeRasterParm(struct pam *     const pamP,
 
     4) The Tiff library produces unhelpful error messages when the above
        conditions are not met.
-  
+
   We provide two modes for output:
-  
+
   1. Tmpfile mode (default)
-  
+
      We have the Tiff library direct output to an unnamed temporary file we
      create which is seekable and readable.  When output is complete, we copy
      the file's contents to Standard Output.
-  
+
   2. Direct mode (specified with -output)
-  
+
      We have the Tiff library write output to the specified file.  As the Tiff
      library requires taht it be be seekable and readable, we fail the program
      rather than ask the Tiff library to use the file if it does not meet
      these requirements.
-  
+
      Direct mode is further divided into append and create.  They are the same
      except that in append mode, we insist that the file already exist,
      whereas with create mode, we create it if necessary.  In either case, if
@@ -1253,7 +1253,7 @@ main(int argc, const char *argv[]) {
     int ofd;
     int eof;
     unsigned int imageSeq;
-    
+
     pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
@@ -1277,7 +1277,7 @@ main(int argc, const char *argv[]) {
         break;
     }
 
-    eof = FALSE;  /* initial assumption */
+    eof = false;  /* initial assumption */
     imageSeq = 0;
 
     while (!eof) {
diff --git a/converter/pbm/Makefile b/converter/pbm/Makefile
index b74bbb68..352b73de 100644
--- a/converter/pbm/Makefile
+++ b/converter/pbm/Makefile
@@ -38,6 +38,8 @@ OBJECTS = $(BINARIES:%=%.o) $(EXTRA_OBJECTS)
 MERGEBINARIES = $(BINARIES)
 MERGE_OBJECTS = $(MERGEBINARIES:%=%.o2) $(EXTRA_OBJECTS)
 
+HAVE_MERGE_COMPAT=YES
+
 SUBDIRS=pbmtoppa
 
 .PHONY: all
@@ -74,7 +76,7 @@ thinkjettopbm.c:%.c:%.c1 $(SRCDIR)/lib/util/lexheader
 	  grep -v "^[[:space:]]*int yywrap(void);" \
 	  >$@
 
-install.bin: install.bin.local
+install.bin install.merge: install.bin.local
 .PHONY: install.bin.local
 install.bin.local: $(PKGDIR)/bin
 # Remember that $(SYMLINK) might just be a copy command.
@@ -82,6 +84,10 @@ install.bin.local: $(PKGDIR)/bin
 	cd $(PKGDIR)/bin ; \
 	$(SYMLINK) pbmtosunicon$(EXE) pbmtoicon$(EXE)
 
+mergecomptrylist:
+	cat /dev/null >$@
+	echo "TRY(\"pbmtoicon\",   main_pbmtosunicon);"     >>$@
+
 thisdirclean: localclean
 .PHONY: localclean
 localclean:
diff --git a/converter/pbm/pbmtoln03.c b/converter/pbm/pbmtoln03.c
index f7cf53c7..235429cd 100644
--- a/converter/pbm/pbmtoln03.c
+++ b/converter/pbm/pbmtoln03.c
@@ -40,116 +40,130 @@ work.
  */
 
 #include <stdio.h>
-#include "pbm.h"
-
-FILE *input ;
-
-#ifndef print
-#define print(s)        fputs (s, stdout)
-#define fprint(f, s)    fputs (s, f)
-#endif
 
+#include "mallocvar.h"
+#include "pbm.h"
 
-static void 
-output_sixel_record (unsigned char * record, int width) {
 
-   int i, j, k ;
-   unsigned char last_char ;
-   int start_repeat = 0 ;
-   int repeated ;
-   char repeated_str[16] ;
-   char *p ;
 
-   /* Do RLE */
-   last_char = record[0] ;
-   j = 0 ;
+static void
+outputSixelRecord(unsigned char * const record,
+                  unsigned int    const width) {
 
-   /* This will make the following loop complete */
-   record[width] = '\0' ;
+    unsigned int i, j;
+    unsigned char lastChar;
+    int startRepeat;
+    char repeatedStr[16];
 
-   for (i = 1 ; i <= width ; i++) {
+    /* Do RLE */
+    lastChar = record[0];
+    j = 0;
 
-      repeated = i - start_repeat ;
+    /* This will make the following loop complete */
+    record[width] = '\0' ;
 
-      if (record[i] != last_char || repeated >= 32766) {
+    for (i = 1, startRepeat = 0; i <= width; ++i) {
+        unsigned int const repeated = i - startRepeat;
 
-         /* Repeat has ended */
+        if (record[i] != lastChar || repeated >= 32766) {
 
-         if (repeated > 3) {
+            /* Repeat has ended */
 
-            /* Do an encoding */
-            record[j++] = '!' ;
-            sprintf (repeated_str, "%d", i - start_repeat) ;
-            for (p = repeated_str ; *p ; p++)
-               record[j++] = *p ;
-               record[j++] = last_char ; }
+            if (repeated > 3) {
+                /* Do an encoding */
+                char * p;
+                record[j++] = '!' ;
+                sprintf(repeatedStr, "%u", i - startRepeat);
+                for (p = repeatedStr; *p; ++p)
+                    record[j++] = *p;
+                record[j++] = lastChar;
+            } else {
+                unsigned int k;
 
-         else {
-            for (k = 0 ; k < repeated ; k++)
-               record[j++] = last_char ; }
+                for (k = 0; k < repeated; ++k)
+                    record[j++] = lastChar;
+            }
 
-         start_repeat = i ;
-         last_char = record[i] ; }
-      }
+            startRepeat = i ;
+            lastChar = record[i];
+        }
+    }
 
-   fwrite ((char *) record, j, 1, stdout) ;
-   putchar ('-') ;      /* DECGNL (graphics new-line) */
-   putchar ('\n') ;
-   }
+    fwrite((char *) record, j, 1, stdout) ;
+    putchar('-') ;      /* DECGNL (graphics new-line) */
+    putchar('\n') ;
+}
 
 
-static void 
-convert (int width, int height, int format) {
-
-   int i ;
-   unsigned char *sixel ;               /* A row of sixels */
-   int sixel_row ;
-
-   bit *row = pbm_allocrow (width) ;
-
-   sixel = (unsigned char *) malloc (width + 2) ;
-
-   sixel_row = 0 ;
-   while (height--) {
-      pbm_readpbmrow (input, row, width, format) ;
-      switch (sixel_row) {
-         case 0 :
-           for (i = 0 ; i < width ; i++)
-              sixel[i] = row[i] ;
-           break ;
-         case 1 :
-           for (i = 0 ; i < width ; i++)
-              sixel[i] += row[i] << 1 ;
-           break ;
-         case 2 :
-           for (i = 0 ; i < width ; i++)
-              sixel[i] += row[i] << 2 ;
-           break ;
-         case 3 :
-           for (i = 0 ; i < width ; i++)
-              sixel[i] += row[i] << 3 ;
-           break ;
-         case 4 :
-           for (i = 0 ; i < width ; i++)
-              sixel[i] += row[i] << 4 ;
-           break ;
-         case 5 :
-           for (i = 0 ; i < width ; i++)
-              sixel[i] += (row[i] << 5) + 077 ;
-           output_sixel_record (sixel, width) ;
-           break ; }
-      if (sixel_row == 5)
-         sixel_row = 0 ;
-      else
-         sixel_row++ ;
-      }
 
-   if (sixel_row > 0) {
-      /* Incomplete sixel record needs to be output */
-      for (i = 0 ; i < width ; i++)
-         sixel[i] += 077 ;
-      output_sixel_record (sixel, width) ; }
-   }
+static void
+convert(FILE *       const ifP,
+        unsigned int const width,
+        unsigned int const height,
+        unsigned int const format) {
+
+    unsigned char * sixel;  /* A row of sixels */
+    unsigned int sixelRow;
+    bit * bitrow;
+    unsigned int remainingHeight;
+
+    bitrow = pbm_allocrow(width);
+
+    MALLOCARRAY(sixel, width + 2);
+    if (!sixel)
+        pm_error("Unable to allocation %u bytes for a row buffer", width + 2);
+
+    for (remainingHeight = height, sixelRow = 0;
+         remainingHeight > 0;
+         --remainingHeight) {
+
+        unsigned int i;
+
+        pbm_readpbmrow(ifP, bitrow, width, format);
+
+        switch (sixelRow) {
+        case 0 :
+            for (i = 0; i < width; ++i)
+                sixel[i] = bitrow[i] ;
+            break ;
+        case 1 :
+            for (i = 0; i < width; ++i)
+                sixel[i] += bitrow[i] << 1;
+            break ;
+        case 2 :
+            for (i = 0; i < width; ++i)
+                sixel[i] += bitrow[i] << 2;
+            break ;
+        case 3 :
+            for (i = 0; i < width; ++i)
+                sixel[i] += bitrow[i] << 3;
+            break ;
+        case 4 :
+            for (i = 0; i < width; ++i)
+                sixel[i] += bitrow[i] << 4;
+            break ;
+        case 5 :
+            for (i = 0; i < width; ++i)
+                sixel[i] += (bitrow[i] << 5) + 077;
+            outputSixelRecord(sixel, width);
+            break ; }
+        if (sixelRow == 5)
+            sixelRow = 0;
+        else
+            ++sixelRow;
+    }
+
+    if (sixelRow > 0) {
+        /* Incomplete sixel record needs to be output */
+        unsigned int i;
+        for (i = 0; i < width; ++i)
+            sixel[i] += 077;
+        outputSixelRecord(sixel, width);
+    }
+
+    pbm_freerow(bitrow);
+    free(sixel);
+}
 
 
 
@@ -169,6 +183,7 @@ main (int argc, char **argv) {
    const char *opt_bottom_margin = "3400";
    const char *opt_form_length = opt_bottom_margin;
 
+   FILE * ifP;
    int width, height, format ;
 
    pbm_init (&argc_copy, argv_copy) ;
@@ -210,16 +225,16 @@ main (int argc, char **argv) {
    }
 
    if( argn < argc ) {
-      input = pm_openr( argv[argn] );
+      ifP = pm_openr( argv[argn] );
       argn++;
    }
    else
-      input = stdin;
+      ifP = stdin;
 
    if( argn != argc )
       pm_usage(usage);
 
-   pbm_readpbminit (input, &width, &height, &format) ;
+   pbm_readpbminit (ifP, &width, &height, &format) ;
 
 /*
  * In explanation of the sequence below:
@@ -241,10 +256,10 @@ main (int argc, char **argv) {
       opt_form_length);
 
    /* Convert data */
-   convert (width, height, format) ;
+   convert (ifP, width, height, format) ;
 
    /* Terminate sixel data */
-   print ("\033\\\n") ;
+   puts ("\033\\") ;
 
    /* If the program failed, it previously aborted with nonzero completion
       code, via various function calls.
diff --git a/converter/pbm/pbmtomacp.c b/converter/pbm/pbmtomacp.c
index df5cbb0c..e02f5559 100644
--- a/converter/pbm/pbmtomacp.c
+++ b/converter/pbm/pbmtomacp.c
@@ -177,7 +177,7 @@ calculateCropPad(struct CmdlineInfo         const cmdline,
             pm_message("Specified -bottom value %u is beyond edge of "
                        "input image", cmdline.bottom);
 
-            bottom = MIN3(cmdline.bottom, rows - 1, top + MACP_ROWS - 1);
+        bottom = MIN3(cmdline.bottom, rows - 1, top + MACP_ROWS - 1);
     } else
         bottom = MIN(rows - 1, top + MACP_ROWS - 1);
 
@@ -234,7 +234,7 @@ writeMacpRowUnpacked(const bit  * const imageBits,
     char const marginByte = 0x00;  /* White bits for margin */
     unsigned int const rightMarginCharCt =
         MACP_COLCHARS - leftMarginCharCt - imageColCharCt;
-    
+
     unsigned int i;
 
     fputc(MACP_COLCHARS - 1, ofP);
@@ -361,7 +361,7 @@ encodeRowsWithShift(bit *                    const bitrow,
 
     for (row = 0; row < cropPad.imageHeight; ++row) {
         pbm_readpbmrow_bitoffset(ifP, bitrow, inCols, format, offset);
-        
+
         /* Trim off fractional margin portion in first byte of image data */
         if (leftTrim > 0) {
             bitrow[startChar] <<= leftTrim;
diff --git a/converter/pbm/pbmtoppa/pbm.c b/converter/pbm/pbmtoppa/pbm.c
index 2f8a42b1..ae36e0d2 100644
--- a/converter/pbm/pbmtoppa/pbm.c
+++ b/converter/pbm/pbmtoppa/pbm.c
@@ -11,126 +11,185 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <limits.h>
 
+#include "pm.h"
+#include "nstring.h"
 #include "ppapbm.h"
 
-int make_pbm_stat(pbm_stat* pbm,FILE* fptr)
-{
-  char line[1024];
-
-  pbm->fptr=fptr;
-  pbm->version=none;
-  pbm->current_line=0;
-  pbm->unread = 0;
+int
+make_pbm_stat(pbm_stat * const pbmStatP,
+              FILE *     const ifP) {
+
+    char line[1024];
+    char * rc;
+    int retval;
+
+    pbmStatP->fptr         = ifP;
+    pbmStatP->version      = none;
+    pbmStatP->current_line = 0;
+    pbmStatP->unread       = 0;
+
+    rc = fgets(line, 1024, ifP);
+    if (rc == NULL)
+        retval = 0;
+    else {
+        line[strlen(line)-1] = 0;
+
+        if (streq(line,"P1"))
+            pbmStatP->version=P1;
+        if (streq(line,"P4"))
+            pbmStatP->version=P4;
+
+        if (pbmStatP->version == none) {
+            pm_message("unknown PBM magic '%s'", line);
+            retval = 0;
+        } else {
+            do {
+                char * rc;
+                rc = fgets(line, 1024, ifP);
+                if (rc == NULL)
+                    return 0;
+            } while (line[0] == '#');
+            {
+                int rc;
+                rc = sscanf(line, "%d %d",
+                            &pbmStatP->width, &pbmStatP->height);
+                if (rc != 2)
+                    retval = 0;
+                else {
+                    if (pbmStatP->width < 0) {
+                        pm_message("Image has negative width");
+                        retval = 0;
+                    } else if (pbmStatP->width > INT_MAX/2) {
+                        pm_message("Uncomputeably large width: %d",
+                                   pbmStatP->width);
+                        retval = 0;
+                    } else if (pbmStatP->height < 0) {
+                        pm_message("Image has negative height");
+                        retval = 0;
+                    } else if (pbmStatP->height > INT_MAX/2) {
+                        pm_message("Uncomputeably large height: %d",
+                                   pbmStatP->height);
+                        retval = 0;
+                    } else
+                        retval = 1;
+                }
+            }
+        }
+    }
+    return retval;
+}
 
-  if (fgets (line, 1024, fptr) == NULL)
-    return 0;
-  line[strlen(line)-1] = 0;
 
-  if(!strcmp(line,"P1")) pbm->version=P1;
-  if(!strcmp(line,"P4")) pbm->version=P4;
-  if(pbm->version == none)
-  {
-    fprintf(stderr,"pbm_readheader(): unknown PBM magic '%s'\n",line);
-    return 0;
-  }
 
-  do
-    if (fgets (line, 1024, fptr) == NULL)
-      return 0;
-  while (line[0] == '#');
+static int
+getbytes(FILE *          const ifP,
+         unsigned int    const width,
+         unsigned char * const data) {
+
+    unsigned char mask;
+    unsigned char acc;
+    unsigned char * place;
+    unsigned int num;
+    int retval;
+
+    if (width == 0)
+        retval = 0;
+    else {
+        for (mask = 0x80, acc = 0, num = 0, place = data; num < width; ) {
+            switch (getc(ifP)) {
+            case EOF:
+                return 0;
+            case '1':
+                acc |= mask;
+                /* fall through */
+            case '0':
+                mask >>= 1;
+                ++num;
+                if (mask == 0x00) { /* if (num % 8 == 0) */
+                    *place++ = acc;
+                    acc = 0;
+                    mask = 0x80;
+                }
+            }
+        }
+        if (width % 8 != 0)
+            *place = acc;
+
+        retval = 1;
+    }
+    return retval;
+}
 
-  if (2 != sscanf (line, "%d %d", &pbm->width, &pbm->height))
-    return 0;
 
-  return 1;
-}
 
-static int getbytes(FILE *fptr,int width,unsigned char* data)
-{
-  unsigned char mask,acc,*place;
-  int num;
-
-  if(!width) return 0;
-  for(mask=0x80, acc=0, num=0, place=data; num<width; )
-  {
-    switch(getc(fptr))
-    {
-    case EOF:      
-      return 0;
-    case '1':
-      acc|=mask;
-      /* fall through */
-    case '0':
-      mask>>=1;
-      num++;
-      if(!mask) /* if(num%8 == 0) */
-      {
-	*place++ = acc;
-	acc=0;
-	mask=0x80;
-      }
+int
+pbm_readline(pbm_stat *      const pbmStatP,
+             unsigned char * const data) {
+/*----------------------------------------------------------------------------
+  Read a single line into data which must be at least (pbmStatP->width+7)/8
+  bytes of storage.
+-----------------------------------------------------------------------------*/
+    int retval;
+
+    if (pbmStatP->current_line >= pbmStatP->height)
+        retval = 0;
+    else {
+        if (pbmStatP->unread) {
+            memcpy(data, pbmStatP->revdata, (pbmStatP->width+7)/8);
+            ++pbmStatP->current_line;
+            pbmStatP->unread = 0;
+            free(pbmStatP->revdata);
+            pbmStatP->revdata = NULL;
+            retval = 1;
+        } else {
+            switch (pbmStatP->version) {
+            case P1:
+                if (getbytes(pbmStatP->fptr, pbmStatP->width, data)) {
+                    pbmStatP->current_line++;
+                    retval = 1;
+                } else
+                    retval = 0;
+                break;
+            case P4: {
+                int tmp, tmp2;
+                tmp = (pbmStatP->width+7)/8;
+                tmp2 = fread(data,1,tmp,pbmStatP->fptr);
+                if (tmp2 == tmp) {
+                    ++pbmStatP->current_line;
+                    retval = 1;
+                } else {
+                    pm_message("error reading line data (%d)", tmp2);
+                    retval = 0;
+                }
+            } break;
+
+            default:
+                pm_message("unknown PBM version");
+                retval = 0;
+            }
+        }
     }
-  }
-  if(width%8)
-    *place=acc;
-  return 1;
+    return retval;
 }
 
-/* Reads a single line into data which must be at least (pbm->width+7)/8
-   bytes of storage */
-int pbm_readline(pbm_stat* pbm,unsigned char* data)
-{
-  int tmp,tmp2;
-
-  if(pbm->current_line >= pbm->height) return 0;
-
-  if (pbm->unread)
-    {
-      memcpy (data, pbm->revdata, (pbm->width+7)/8);
-      pbm->current_line++;
-      pbm->unread = 0;
-      free (pbm->revdata);
-      pbm->revdata = NULL;
-      return 1;
-    }
 
-  switch(pbm->version)
-  {
-  case P1:
-    if(getbytes(pbm->fptr,pbm->width,data))
-    {
-      pbm->current_line++;
-      return 1;
-    }
-    return 0;
-
-  case P4:
-    tmp=(pbm->width+7)/8;
-    tmp2=fread(data,1,tmp,pbm->fptr);
-    if(tmp2 == tmp)
-    {
-      pbm->current_line++;
-      return 1;
-    }
-    fprintf(stderr,"pbm_readline(): error reading line data (%d)\n",tmp2);
-    return 0;
 
-  default:
-    fprintf(stderr,"pbm_readline(): unknown PBM version\n");
-    return 0;
-  }
-}
+void
+pbm_unreadline(pbm_stat * const pbmStatP,
+               void *     const data) {
+/*----------------------------------------------------------------------------
+  Push a line back into the buffer; we read too much!
+-----------------------------------------------------------------------------*/
+    /* can store only one line in the unread buffer */
 
-/* push a line back into the buffer; we read too much! */
-void pbm_unreadline (pbm_stat *pbm, void *data)
-{
-  /* can only store one line in the unread buffer */
-  if (pbm->unread)
-    return;
-
-  pbm->unread = 1;
-  pbm->revdata = malloc ((pbm->width+7)/8);
-  memcpy (pbm->revdata, data, (pbm->width+7)/8);
-  pbm->current_line--;
+    if (!pbmStatP->unread) {
+        pbmStatP->unread = 1;
+        pbmStatP->revdata = malloc ((pbmStatP->width+7)/8);
+        memcpy(pbmStatP->revdata, data, (pbmStatP->width+7)/8);
+        --pbmStatP->current_line;
+    }
 }
+
+
diff --git a/converter/ppm/hpcdtoppm/Makefile b/converter/ppm/hpcdtoppm/Makefile
index ddf79ee5..59ba3630 100644
--- a/converter/ppm/hpcdtoppm/Makefile
+++ b/converter/ppm/hpcdtoppm/Makefile
@@ -14,12 +14,12 @@ MERGE_OBJECTS =
 
 include $(SRCDIR)/common.mk
 
-install: install.bin.local
+install.bin install.merge: install.bin.local
 .PHONY: install.bin.local
 install.bin.local: $(PKGDIR)/bin
 # In June 2002, pcdovtoppm replaced pcdindex
 	cd $(PKGDIR)/bin ; \
-	$(SYMLINK) pcdindex$(EXE) pcdovtoppm$(EXE)
+	$(SYMLINK) pcdovtoppm$(EXE) pcdindex$(EXE) 
 
 
 FORCE:
diff --git a/converter/ppm/picttoppm.c b/converter/ppm/picttoppm.c
index 8b633725..b8fb8642 100644
--- a/converter/ppm/picttoppm.c
+++ b/converter/ppm/picttoppm.c
@@ -15,7 +15,7 @@
  * University of British Columbia
  *
  *
- * 2003-02:    Handling for DirectBitsRgn opcode (0x9b) added by 
+ * 2003-02:    Handling for DirectBitsRgn opcode (0x9b) added by
  *             kabe@sra-tohoku.co.jp.
  *
  * 2004-03-27: Several bugs fixed by Steve Summit, scs@eskimo.com.
@@ -153,7 +153,7 @@ struct raster {
 
    Each pixel is either a palette index or an RGB triple, depending on
    the format of the associated PICT.
-   
+
    Each pixel is one byte if the associated PICT has 8 or fewer bits
    per pixel.  If the associated PICT has 16 or 32 bits per pixel, an
    element herein is 2 or 4 bytes, respectively.
@@ -231,7 +231,7 @@ allocateRaster(struct raster * const rasterP,
     default:
         pm_error("INTERNAL ERROR: impossible bitsPerPixel value in "
                  "unpackbits(): %u", bitsPerPixel);
-    }    
+    }
     if (UINT_MAX / rasterP->rowSize < rasterP->rowCount)
         pm_error("Arithmetic overflow computing size of %u x %u pixel "
                  "array.", rasterP->rowSize, rasterP->rowCount);
@@ -360,7 +360,7 @@ readSignedByte(void) {
 
 
 
-static void 
+static void
 readShortPoint(struct Point * const p) {
     p->x = readSignedByte();
     p->y = readSignedByte();
@@ -457,15 +457,15 @@ const_name(const struct const_name * const table,
     for (i = 0; table[i].name; ++i)
         if (table[i].value == ct)
             return table[i].name;
-    
+
     sprintf(numbuf, "? (%u)", ct);
     return numbuf;
 }
 
 
 
-static void 
-picComment(Word const type, 
+static void
+picComment(Word const type,
            int const length) {
 
     unsigned int remainingLength;
@@ -736,7 +736,7 @@ parseFontLine(const char **      const token,
 
 
 
-static int 
+static int
 load_fontdir(const char * const dirfile) {
 /*----------------------------------------------------------------------------
    Load the font directory from file named 'dirfile'.  Add its contents
@@ -744,7 +744,7 @@ load_fontdir(const char * const dirfile) {
 -----------------------------------------------------------------------------*/
     FILE * ifP;
     unsigned int nFont;
-    char line[1024]; 
+    char line[1024];
 
     ifP = pm_openr(dirfile);
 
@@ -832,7 +832,7 @@ rectheight(const struct Rect * const r) {
 
 
 static bool
-rectsamesize(struct Rect const r1, 
+rectsamesize(struct Rect const r1,
              struct Rect const r2) {
     return r1.right - r1.left == r2.right - r2.left &&
            r1.bottom - r1.top == r2.bottom - r2.top ;
@@ -841,8 +841,8 @@ rectsamesize(struct Rect const r1,
 
 
 static void
-rectinter(struct Rect   const r1, 
-          struct Rect   const r2, 
+rectinter(struct Rect   const r1,
+          struct Rect   const r2,
           struct Rect * const intersectionP) {
 
     intersectionP->left   = MAX(r1.left,   r2.left);
@@ -854,8 +854,8 @@ rectinter(struct Rect   const r1,
 
 
 static void
-rectscale(struct Rect * const r, 
-          double        const xscale, 
+rectscale(struct Rect * const r,
+          double        const xscale,
           double        const yscale) {
     r->left *= xscale;
     r->right *= xscale;
@@ -886,7 +886,7 @@ addBlitList(blitList *        const blitListP,
             int               const mode) {
 
     struct blit_info * biP;
-    
+
     MALLOCVAR(biP);
     if (biP == NULL)
         pm_error("out of memory for blit list");
@@ -940,8 +940,8 @@ rgbIsBlack(const struct RGBColor * const colorP) {
 }
 
 
-static void 
-srcCopy(struct RGBColor * const src, 
+static void
+srcCopy(struct RGBColor * const src,
         struct RGBColor * const dst) {
 
     if (rgbIsBlack(src))
@@ -952,8 +952,8 @@ srcCopy(struct RGBColor * const src,
 
 
 
-static void 
-srcOr(struct RGBColor * const src, 
+static void
+srcOr(struct RGBColor * const src,
       struct RGBColor * const dst) {
     if (rgbIsBlack(src))
         *dst = foreground;
@@ -961,8 +961,8 @@ srcOr(struct RGBColor * const src,
 
 
 
-static void 
-srcXor(struct RGBColor * const src, 
+static void
+srcXor(struct RGBColor * const src,
        struct RGBColor * const dst) {
     dst->red ^= ~src->red;
     dst->grn ^= ~src->grn;
@@ -971,8 +971,8 @@ srcXor(struct RGBColor * const src,
 
 
 
-static void 
-srcBic(struct RGBColor * const src, 
+static void
+srcBic(struct RGBColor * const src,
        struct RGBColor * const dst) {
     if (rgbIsBlack(src))
         *dst = background;
@@ -980,8 +980,8 @@ srcBic(struct RGBColor * const src,
 
 
 
-static void 
-notSrcCopy(struct RGBColor * const src, 
+static void
+notSrcCopy(struct RGBColor * const src,
            struct RGBColor * const dst) {
     if (rgbIsWhite(src))
         *dst = foreground;
@@ -991,8 +991,8 @@ notSrcCopy(struct RGBColor * const src,
 
 
 
-static void 
-notSrcOr(struct RGBColor * const src, 
+static void
+notSrcOr(struct RGBColor * const src,
          struct RGBColor * const dst) {
     if (rgbIsWhite(src))
         *dst = foreground;
@@ -1000,8 +1000,8 @@ notSrcOr(struct RGBColor * const src,
 
 
 
-static void 
-notSrcBic(struct RGBColor * const src, 
+static void
+notSrcBic(struct RGBColor * const src,
           struct RGBColor * const dst) {
     if (rgbIsWhite(src))
         *dst = background;
@@ -1009,8 +1009,8 @@ notSrcBic(struct RGBColor * const src,
 
 
 
-static void 
-notSrcXor(struct RGBColor * const src, 
+static void
+notSrcXor(struct RGBColor * const src,
           struct RGBColor * const dst) {
     dst->red ^= src->red;
     dst->grn ^= src->grn;
@@ -1019,8 +1019,8 @@ notSrcXor(struct RGBColor * const src,
 
 
 
-static void 
-addOver(struct RGBColor * const src, 
+static void
+addOver(struct RGBColor * const src,
         struct RGBColor * const dst) {
     dst->red += src->red;
     dst->grn += src->grn;
@@ -1029,8 +1029,8 @@ addOver(struct RGBColor * const src,
 
 
 
-static void 
-addPin(struct RGBColor * const src, 
+static void
+addPin(struct RGBColor * const src,
        struct RGBColor * const dst) {
     if ((long)dst->red + (long)src->red > (long)op_color.red)
         dst->red = op_color.red;
@@ -1050,8 +1050,8 @@ addPin(struct RGBColor * const src,
 
 
 
-static void 
-subOver(struct RGBColor * const src, 
+static void
+subOver(struct RGBColor * const src,
         struct RGBColor * const dst) {
     dst->red -= src->red;
     dst->grn -= src->grn;
@@ -1063,8 +1063,8 @@ subOver(struct RGBColor * const src,
 /* or maybe its src - dst; my copy of Inside Mac is unclear */
 
 
-static void 
-subPin(struct RGBColor * const src, 
+static void
+subPin(struct RGBColor * const src,
        struct RGBColor * const dst) {
     if ((long)dst->red - (long)src->red < (long)op_color.red)
         dst->red = op_color.red;
@@ -1084,8 +1084,8 @@ subPin(struct RGBColor * const src,
 
 
 
-static void 
-adMax(struct RGBColor * const src, 
+static void
+adMax(struct RGBColor * const src,
       struct RGBColor * const dst) {
     if (src->red > dst->red) dst->red = src->red;
     if (src->grn > dst->grn) dst->grn = src->grn;
@@ -1094,8 +1094,8 @@ adMax(struct RGBColor * const src,
 
 
 
-static void 
-adMin(struct RGBColor * const src, 
+static void
+adMin(struct RGBColor * const src,
       struct RGBColor * const dst) {
     if (src->red < dst->red) dst->red = src->red;
     if (src->grn < dst->grn) dst->grn = src->grn;
@@ -1104,8 +1104,8 @@ adMin(struct RGBColor * const src,
 
 
 
-static void 
-blend(struct RGBColor * const src, 
+static void
+blend(struct RGBColor * const src,
       struct RGBColor * const dst) {
 #define blend_component(cmp)    \
     ((long)src->cmp * (long)op_color.cmp) / 65536 +    \
@@ -1118,8 +1118,8 @@ blend(struct RGBColor * const src,
 
 
 
-static void 
-transparent(struct RGBColor * const src, 
+static void
+transparent(struct RGBColor * const src,
             struct RGBColor * const dst) {
     if (src->red != background.red ||
         src->grn != background.grn ||
@@ -1130,7 +1130,7 @@ transparent(struct RGBColor * const src,
 
 
 
-static transfer_func 
+static transfer_func
 transfer(int const mode) {
     switch (mode) {
     case  0: return srcCopy;
@@ -1162,7 +1162,7 @@ transfer(int const mode) {
 static pixval
 redepth(pixval const c,
         pixval const oldMaxval) {
-    
+
     return ROUNDDIV(c * PPM_MAXMAXVAL, oldMaxval);
 }
 
@@ -1185,7 +1185,7 @@ decode16(unsigned char * const sixteen) {
     retval.red = (sixteen[0] & 0x7c) >> 2;
     retval.grn = (sixteen[0] & 0x03) << 3 | (sixteen[1] & 0xe0) >> 5;
     retval.blu = (sixteen[1] & 0x1f) >> 0;
-                
+
     return retval;
 }
 
@@ -1198,9 +1198,9 @@ doDiffSize(struct Rect       const clipsrc,
            int               const xsize,
            int               const ysize,
            transfer_func     const trf,
-           struct RGBColor * const color_map, 
+           struct RGBColor * const color_map,
            unsigned char *   const src,
-           int               const srcwid, 
+           int               const srcwid,
            struct rgbPlanes  const dst,
            unsigned int      const dstwid) {
 
@@ -1275,7 +1275,7 @@ doDiffSize(struct Rect       const clipsrc,
     case 32: {
         unsigned int const planeSize = srcwid / 4;
         unsigned int rowNumber;
-        
+
         for (rowNumber = 0; rowNumber < ysize; ++rowNumber) {
             unsigned char * const row = &src[rowNumber * srcwid];
             unsigned char * const redPlane = &row[planeSize * 0];
@@ -1300,16 +1300,16 @@ doDiffSize(struct Rect       const clipsrc,
     ppm_readppminit(scaled = pm_openr(tempFilename), &cols, &rows,
                     &maxval, &format);
     row = ppm_allocrow(cols);
-    /* couldn't hurt to assert cols, rows and maxval... */  
+    /* couldn't hurt to assert cols, rows and maxval... */
 
     if (trf == NULL) {
         while (rows-- > 0) {
             unsigned int i;
             ppm_readppmrow(scaled, row, cols, maxval, format);
             for (i = 0, rowp = row; i < cols; ++i, ++rowp) {
-                *reddst++ = PPM_GETR(*rowp) * 65536L / (maxval + 1); 
-                *grndst++ = PPM_GETG(*rowp) * 65536L / (maxval + 1); 
-                *bludst++ = PPM_GETB(*rowp) * 65536L / (maxval + 1); 
+                *reddst++ = PPM_GETR(*rowp) * 65536L / (maxval + 1);
+                *grndst++ = PPM_GETG(*rowp) * 65536L / (maxval + 1);
+                *bludst++ = PPM_GETB(*rowp) * 65536L / (maxval + 1);
             }
             reddst += dstadd;
             grndst += dstadd;
@@ -1325,9 +1325,9 @@ doDiffSize(struct Rect       const clipsrc,
                 dst_c.red = *reddst;
                 dst_c.grn = *grndst;
                 dst_c.blu = *bludst;
-                src_c.red = PPM_GETR(*rowp) * 65536L / (maxval + 1); 
-                src_c.grn = PPM_GETG(*rowp) * 65536L / (maxval + 1); 
-                src_c.blu = PPM_GETB(*rowp) * 65536L / (maxval + 1); 
+                src_c.red = PPM_GETR(*rowp) * 65536L / (maxval + 1);
+                src_c.grn = PPM_GETG(*rowp) * 65536L / (maxval + 1);
+                src_c.blu = PPM_GETB(*rowp) * 65536L / (maxval + 1);
                 (*trf)(&src_c, &dst_c);
                 *reddst++ = dst_c.red;
                 *grndst++ = dst_c.grn;
@@ -1480,7 +1480,7 @@ blitIdempotent(unsigned int          const pixSize,
                unsigned int          const ysize,
                unsigned char *       const src,
                unsigned int          const srcwid,
-               struct RGBColor *     const colorMap, 
+               struct RGBColor *     const colorMap,
                struct rgbPlanes      const dst,
                unsigned int          const dstwid) {
 /*----------------------------------------------------------------------------
@@ -1494,7 +1494,7 @@ blitIdempotent(unsigned int          const pixSize,
     switch (pixSize) {
     case 8: {
         unsigned int rowNumber;
-        
+
         for (rowNumber = 0; rowNumber < ysize; ++rowNumber) {
             unsigned char * const srcrow = &src[rowNumber * srcwid];
             unsigned int const dstRowCurs = rowNumber * dstwid;
@@ -1554,15 +1554,15 @@ blitIdempotent(unsigned int          const pixSize,
 
 
 static void
-doBlit(struct Rect       const srcRect, 
-       struct Rect       const dstRect, 
-       struct Rect       const srcBounds, 
+doBlit(struct Rect       const srcRect,
+       struct Rect       const dstRect,
+       struct Rect       const srcBounds,
        struct raster     const srcplane,
-       struct Rect       const dstBounds, 
+       struct Rect       const dstBounds,
        struct rgbPlanes  const canvasPlanes,
-       int               const pixSize, 
-       int               const dstwid, 
-       struct RGBColor * const color_map, 
+       int               const pixSize,
+       int               const dstwid,
+       struct RGBColor * const color_map,
        int               const mode) {
 /*----------------------------------------------------------------------------
    Transfer some pixels from 'srcplane' to 'canvasPlanes', applying the
@@ -1633,16 +1633,16 @@ doBlit(struct Rect       const srcRect,
 
 
 static int
-blit(struct Rect       const srcRect, 
-     struct Rect       const srcBounds, 
+blit(struct Rect       const srcRect,
+     struct Rect       const srcBounds,
      struct raster     const srcplane,
      struct canvas *   const canvasP,
      blitList *        const blitListP,
-     int               const pixSize, 
-     struct Rect       const dstRect, 
-     struct Rect       const dstBounds, 
-     int               const dstwid, 
-     struct RGBColor * const color_map, 
+     int               const pixSize,
+     struct Rect       const dstRect,
+     struct Rect       const dstBounds,
+     int               const dstwid,
+     struct RGBColor * const color_map,
      int               const mode) {
 /*----------------------------------------------------------------------------
    'srcplane' contains the rectangle 'srcBounds' of the image.
@@ -1655,7 +1655,7 @@ blit(struct Rect       const srcRect,
 
     /* I can't tell what the result value of this function is supposed to mean,
        but I found several return statements that did not set it to anything,
-       and several calls that examine it.  I'm guessing that "1" is the 
+       and several calls that examine it.  I'm guessing that "1" is the
        appropriate thing to return in those cases, so I made it so.
        -Bryan 00.03.02
     */
@@ -1699,7 +1699,7 @@ blit(struct Rect       const srcRect,
  * even only a bit, but that would require even more extra work).
  */
 
-static void 
+static void
 allocPlanes(unsigned int       const width,
             unsigned int       const height,
             struct rgbPlanes * const planesP) {
@@ -1856,7 +1856,7 @@ doBlitList(struct canvas * const canvasP,
 
     if (xscale != 1.0 || yscale != 1.0) {
         struct blit_info * biP;
-        
+
         for (biP = blitListP->firstP; biP; biP = biP->next)
             rectscale(&biP->dstRect, xscale, yscale);
 
@@ -2076,7 +2076,7 @@ readColorTable(void) {
 
 static void
 readBytes(FILE *          const ifP,
-          unsigned int    const n, 
+          unsigned int    const n,
           unsigned char * const buf) {
 
     align += n;
@@ -2109,7 +2109,7 @@ expand4Bits(unsigned char * const packed,
     unsigned char * dst;
 
     dst = &expanded[0];
-    
+
     for (i = 0; i < packedLen; ++i) {
         *dst++ = (packed[i] >> 4) & 0x0f;
         *dst++ = (packed[i] >> 0) & 0x0f;
@@ -2122,12 +2122,12 @@ static void
 expand2Bits(unsigned char * const packed,
             unsigned char * const expanded,
             unsigned int    const packedLen) {
-        
+
     unsigned int i;
     unsigned char * dst;
 
     dst = &expanded[0];
-    
+
     for (i = 0; i < packedLen; ++i) {
         *dst++ = (packed[i] >> 6) & 0x03;
         *dst++ = (packed[i] >> 4) & 0x03;
@@ -2147,7 +2147,7 @@ expand1Bit(unsigned char * const packed,
     unsigned char * dst;
 
     dst = &expanded[0];
-    
+
     for (i = 0; i < packedLen; ++i) {
         *dst++ = (packed[i] >> 7) & 0x01;
         *dst++ = (packed[i] >> 6) & 0x01;
@@ -2163,7 +2163,7 @@ expand1Bit(unsigned char * const packed,
 
 
 static void
-unpackBuf(unsigned char *  const packed, 
+unpackBuf(unsigned char *  const packed,
           unsigned int     const packedLen,
           int              const bitsPerPixel,
           unsigned char ** const expandedP,
@@ -2240,7 +2240,7 @@ unpackUncompressedBits(FILE *          const ifP,
     if (linebuf == NULL)
         pm_error("can't allocate memory for line buffer");
 
-    for (rowOfRect = 0; rowOfRect < raster.rowCount; ++rowOfRect) { 
+    for (rowOfRect = 0; rowOfRect < raster.rowCount; ++rowOfRect) {
         unsigned char * bytePixels;
         unsigned int expandedByteCount;
         unsigned char * rasterRow;
@@ -2324,12 +2324,12 @@ expandRun(unsigned char * const block,
                  "Invalid PICT file.");
     else {
         unsigned int const runLength = (block[0] ^ 0xff) + 2;
-        
+
         unsigned int i;
         unsigned char * bytePixels;  /* Points to static storage */
         unsigned int expandedByteCount;
         unsigned int outputCursor;
-        
+
         assert(block[0] & 0x80);  /* It's a run */
 
         if (verbose > 1)
@@ -2349,13 +2349,13 @@ expandRun(unsigned char * const block,
 
            That is what I saw in a test image.
         */
-        
+
         if (expandedByteCount * runLength > expandedSize)
             pm_error("Invalid PICT image.  It contains a row with more pixels "
                      "than the width of the rectangle containing it, "
                      "even padded up to a "
                      "multiple of 16 pixels.  Use -verbose to see details.");
-        
+
         outputCursor = 0;
         for (i = 0; i < runLength; ++i) {
             unsigned int j;
@@ -2407,14 +2407,14 @@ copyPixelGroup(unsigned char * const block,
         unsigned char * bytePixels;  /* Points to static storage */
         unsigned int bytePixelLen;
         unsigned int rasterBytesGenerated;
-        
+
         assert(blockLimit >= 1);  /* block[0] exists */
         assert((block[0] & 0x80) == 0);  /* It's not a run */
-        
+
         if (verbose > 1)
             pm_message("Block: %u explicit packed %u-byte units",
                        groupLen, pkpixsize);
-        
+
         unpackBuf(&block[1], groupLen * pkpixsize, bitsPerPixel,
                   &bytePixels, &bytePixelLen);
 
@@ -2432,7 +2432,7 @@ copyPixelGroup(unsigned char * const block,
 
         for (i = 0; i < rasterBytesGenerated; ++i)
             dest[i] = bytePixels[i];
-        
+
         *blockLengthP = blockLength;
         *rasterBytesGeneratedP = rasterBytesGenerated;
     }
@@ -2499,9 +2499,9 @@ interpretCompressedLine(unsigned char * const linebuf,
 
     for (lineCursor = 0, rasterCursor = 0; lineCursor < linelen; ) {
         unsigned int blockLength, rasterBytesGenerated;
-        
+
         assert(lineCursor <= linelen);
-            
+
         if (verbose > 2)
             pm_message("At Byte %u of line, Column %u of row",
                        lineCursor, rasterCursor);
@@ -2511,7 +2511,7 @@ interpretCompressedLine(unsigned char * const linebuf,
             bitsPerPixel,
             &rowRaster[rasterCursor], rowSize - rasterCursor,
             &blockLength, &rasterBytesGenerated);
-        
+
         lineCursor += blockLength;
         rasterCursor += rasterBytesGenerated;
         assert(rasterCursor <= rowSize);
@@ -2539,7 +2539,7 @@ interpretCompressedLine(unsigned char * const linebuf,
   Of course, neither 200 nor 250 make any logical sense.  In the worst case,
   you can represent 254 pixels of 8 bpp or less in a 255 byte line.
   In the worst case, you can represent 127 16bpp pixels in a 255 byte line.
-  So with 200 being the cutoff, it's actually impossible to represent some 
+  So with 200 being the cutoff, it's actually impossible to represent some
   16 bpp images with 200 pixels per row.
 
   We have not been able to find an official spec for PICT.
@@ -2609,13 +2609,13 @@ unpackCompressedBits(FILE *          const ifP,
 static void
 unpackbits(FILE *           const ifP,
            struct Rect *    const boundsP,
-           Word             const rowBytesArg, 
+           Word             const rowBytesArg,
            int              const bitsPerPixel,
            struct raster *  const rasterP) {
 
     unsigned int const rectHeight = boundsP->bottom - boundsP->top;
     unsigned int const rectWidth  = boundsP->right  - boundsP->left;
-    
+
     struct raster raster;
     unsigned int rowBytes;
 
@@ -2624,7 +2624,7 @@ unpackbits(FILE *           const ifP,
     if (verbose)
         pm_message("rowBytes = %u, bitsPerPixel = %d",
                    rowBytesArg, bitsPerPixel);
-        
+
     allocateRaster(&raster, rectWidth, rectHeight, bitsPerPixel);
 
     rowBytes = rowBytesArg ? rowBytesArg : raster.rowSize;
@@ -2762,7 +2762,7 @@ read8x8Pattern(struct Pattern * const pat) {
 
 static drawFn BkPat;
 
-static void 
+static void
 BkPat(struct canvas * const canvasP,
       blitList *      const blitListP,
       int             const version) {
@@ -2774,7 +2774,7 @@ BkPat(struct canvas * const canvasP,
 
 static drawFn PnPat;
 
-static void 
+static void
 PnPat(struct canvas * const canvasP,
       blitList *      const blitListP,
       int             const version) {
@@ -2786,7 +2786,7 @@ PnPat(struct canvas * const canvasP,
 
 static drawFn FillPat;
 
-static void 
+static void
 FillPat(struct canvas * const canvasP,
         blitList *      const blitListP,
         int             const version) {
@@ -2798,7 +2798,7 @@ FillPat(struct canvas * const canvasP,
 
 static drawFn PnSize;
 
-static void 
+static void
 PnSize(struct canvas * const canvasP,
        blitList *      const blitListP,
        int             const version) {
@@ -2813,7 +2813,7 @@ PnSize(struct canvas * const canvasP,
 
 static drawFn PnSize;
 
-static void 
+static void
 PnMode(struct canvas * const canvasP,
        blitList *      const blitListP,
        int             const version) {
@@ -2825,13 +2825,13 @@ PnMode(struct canvas * const canvasP,
     if (verbose)
         pm_message("pen transfer mode = %s",
             const_name(transfer_name, pen_mode));
-    
+
     pen_trf = transfer(pen_mode);
 }
 
 
 
-static void 
+static void
 readRgb(struct RGBColor * const rgb) {
     rgb->red = readWord();
     rgb->grn = readWord();
@@ -2842,14 +2842,14 @@ readRgb(struct RGBColor * const rgb) {
 
 static drawFn RGBFgCol;
 
-static void 
+static void
 RGBFgCol(struct canvas * const canvasP,
          blitList *      const blitListP,
          int             const version) {
 
     readRgb(&foreground);
     if (verbose)
-        pm_message("foreground now [%d,%d,%d]", 
+        pm_message("foreground now [%d,%d,%d]",
             foreground.red, foreground.grn, foreground.blu);
 }
 
@@ -2857,14 +2857,14 @@ RGBFgCol(struct canvas * const canvasP,
 
 static drawFn RGBBkCol;
 
-static void 
+static void
 RGBBkCol(struct canvas * const canvasP,
          blitList *      const blitListP,
          int             const version) {
 
     readRgb(&background);
     if (verbose)
-        pm_message("background now [%d,%d,%d]", 
+        pm_message("background now [%d,%d,%d]",
             background.red, background.grn, background.blu);
 }
 
@@ -2872,11 +2872,11 @@ RGBBkCol(struct canvas * const canvasP,
 
 #define PIXEL_INDEX(x,y) ((y) - picFrame.top) * rowlen + (x) - picFrame.left
 
-static void 
+static void
 draw_pixel(struct canvas *   const canvasP,
-           int               const x, 
-           int               const y, 
-           struct RGBColor * const clr, 
+           int               const x,
+           int               const y,
+           struct RGBColor * const clr,
            transfer_func           trf) {
 
     if (x < clip_rect.left || x >= clip_rect.right ||
@@ -2889,7 +2889,7 @@ draw_pixel(struct canvas *   const canvasP,
         dst.red = canvasP->planes.red[i];
         dst.grn = canvasP->planes.grn[i];
         dst.blu = canvasP->planes.blu[i];
- 
+
         (*trf)(clr, &dst);
 
         canvasP->planes.red[i] = dst.red;
@@ -2900,7 +2900,7 @@ draw_pixel(struct canvas *   const canvasP,
 
 
 
-static void 
+static void
 draw_pen_rect(struct canvas * const canvasP,
               struct Rect *   const r) {
 
@@ -2911,7 +2911,7 @@ draw_pen_rect(struct canvas * const canvasP,
     struct RGBColor dst;
 
     i = PIXEL_INDEX(r->left, r->top);  /* initial value */
-    
+
     for (y = r->top; y < r->bottom; y++) {
         for (x = r->left; x < r->right; x++) {
             dst.red = canvasP->planes.red[i];
@@ -2935,9 +2935,9 @@ draw_pen_rect(struct canvas * const canvasP,
 
 
 
-static void 
+static void
 draw_pen(struct canvas * const canvasP,
-         int             const x, 
+         int             const x,
          int             const y) {
 
     struct Rect penrect;
@@ -2965,11 +2965,11 @@ draw_pen(struct canvas * const canvasP,
  *
  * Paul Heckbert    3 Sep 85
  */
-static void 
+static void
 scan_line(struct canvas * const canvasP,
-          short           const x1, 
-          short           const y1, 
-          short           const x2, 
+          short           const x1,
+          short           const y1,
+          short           const x2,
           short           const y2) {
 
     int d, x, y, ax, ay, sx, sy, dx, dy;
@@ -3016,7 +3016,7 @@ scan_line(struct canvas * const canvasP,
 
 static drawFn Line;
 
-static void 
+static void
 Line(struct canvas * const canvasP,
      blitList *      const blitListP,
      int             const version) {
@@ -3034,7 +3034,7 @@ Line(struct canvas * const canvasP,
 
 static drawFn LineFrom;
 
-static void 
+static void
 LineFrom(struct canvas * const canvasP,
          blitList *      const blitListP,
          int             const version) {
@@ -3055,7 +3055,7 @@ LineFrom(struct canvas * const canvasP,
 
 static drawFn ShortLine;
 
-static void 
+static void
 ShortLine(struct canvas * const canvasP,
           blitList *      const blitListP,
           int             const version) {
@@ -3067,7 +3067,7 @@ ShortLine(struct canvas * const canvasP,
         pm_message("(%d,%d) delta (%d, %d)", p1.x, p1.y, current.x, current.y);
     current.x += p1.x;
     current.y += p1.y;
-    
+
     if (!blitListP)
         scan_line(canvasP, p1.x, p1.y, current.x, current.y);
 }
@@ -3076,7 +3076,7 @@ ShortLine(struct canvas * const canvasP,
 
 static drawFn ShortLineFrom;
 
-static void 
+static void
 ShortLineFrom(struct canvas * const canvasP,
               blitList *      const blitListP,
               int             const version) {
@@ -3096,12 +3096,12 @@ ShortLineFrom(struct canvas * const canvasP,
 
 
 
-static void 
+static void
 do_paintRect(struct canvas * const canvasP,
              struct Rect     const prect) {
 
     struct Rect rect;
-  
+
     if (verbose)
         dumpRect("painting", prect);
 
@@ -3114,7 +3114,7 @@ do_paintRect(struct canvas * const canvasP,
 
 static drawFn paintRect;
 
-static void 
+static void
 paintRect(struct canvas * const canvasP,
           blitList *      const blitListP,
           int             const version) {
@@ -3128,7 +3128,7 @@ paintRect(struct canvas * const canvasP,
 
 static drawFn paintSameRect;
 
-static void 
+static void
 paintSameRect(struct canvas * const canvasP,
               blitList *      const blitListP,
               int             const version) {
@@ -3139,7 +3139,7 @@ paintSameRect(struct canvas * const canvasP,
 
 
 
-static void 
+static void
 do_frameRect(struct canvas * const canvasP,
              struct Rect     const rect) {
 
@@ -3153,7 +3153,7 @@ do_frameRect(struct canvas * const canvasP,
             draw_pen(canvasP, x, rect.top);
             draw_pen(canvasP, x, rect.bottom - pen_height);
         }
-        
+
         for (y = rect.top; y <= rect.bottom - pen_height ; y += pen_height) {
             draw_pen(canvasP, rect.left, y);
             draw_pen(canvasP, rect.right - pen_width, y);
@@ -3165,7 +3165,7 @@ do_frameRect(struct canvas * const canvasP,
 
 static drawFn frameRect;
 
-static void 
+static void
 frameRect(struct canvas * const canvasP,
           blitList *      const blitListP,
           int             const version) {
@@ -3179,7 +3179,7 @@ frameRect(struct canvas * const canvasP,
 
 static drawFn frameSameRect;
 
-static void 
+static void
 frameSameRect(struct canvas * const canvasP,
               blitList *      const blitListP,
               int             const version) {
@@ -3192,7 +3192,7 @@ frameSameRect(struct canvas * const canvasP,
 
 /* a stupid shell sort - I'm so embarrassed  */
 
-static void 
+static void
 poly_sort(int const sort_index, struct Point points[]) {
   int d, i, j, temp;
 
@@ -3225,9 +3225,9 @@ poly_sort(int const sort_index, struct Point points[]) {
 
 /* Watch out for the lack of error checking in the next two functions ... */
 
-static void 
+static void
 scan_poly(struct canvas * const canvasP,
-          int             const np, 
+          int             const np,
           struct Point          pts[]) {
 
   int dx,dy,dxabs,dyabs,i,scan_index,j,k,px,py;
@@ -3253,7 +3253,7 @@ scan_poly(struct canvas * const canvasP,
     scan_index++;
   }
 
-#define sign(x) ((x) > 0 ? 1 : ((x)==0 ? 0:(-1)) )   
+#define sign(x) ((x) > 0 ? 1 : ((x)==0 ? 0:(-1)) )
 
   old_sdy = sy0 = sign(pts[1].y - pts[0].y);
   for (j=0; j<np; j++) {
@@ -3312,7 +3312,7 @@ scan_poly(struct canvas * const canvasP,
   if (sy0 + sdy == 0) scan_index--;
 
   poly_sort(scan_index, coord);
-  
+
   toggle = 0;
   for (i = 0; i < scan_index; i++) {
     if ((coord[i].y == coord[i+1].y) && (toggle == 0))
@@ -3325,12 +3325,12 @@ scan_poly(struct canvas * const canvasP,
       toggle = 0;
   }
 }
-  
+
 
 
 static drawFn paintPoly;
-  
-static void 
+
+static void
 paintPoly(struct canvas * const canvasP,
           blitList *      const blitListP,
           int             const version) {
@@ -3352,7 +3352,7 @@ paintPoly(struct canvas * const canvasP,
 
 static drawFn PnLocHFrac;
 
-static void 
+static void
 PnLocHFrac(struct canvas * const canvasP,
            blitList *      const blitListP,
            int             const version) {
@@ -3367,7 +3367,7 @@ PnLocHFrac(struct canvas * const canvasP,
 
 static drawFn TxMode;
 
-static void 
+static void
 TxMode(struct canvas * const canvasP,
        blitList *      const blitListP,
        int             const version) {
@@ -3379,7 +3379,7 @@ TxMode(struct canvas * const canvasP,
     if (verbose)
         pm_message("text transfer mode = %s",
             const_name(transfer_name, text_mode));
-    
+
     /* ignore the text mask bit 'cause we don't handle it yet */
     text_trf = transfer(text_mode & ~64);
 }
@@ -3388,7 +3388,7 @@ TxMode(struct canvas * const canvasP,
 
 static drawFn TxFont;
 
-static void 
+static void
 TxFont(struct canvas * const canvasP,
        blitList *      const blitListP,
        int             const version) {
@@ -3402,7 +3402,7 @@ TxFont(struct canvas * const canvasP,
 
 static drawFn TxFace;
 
-static void 
+static void
 TxFace(struct canvas * const canvasP,
        blitList *      const blitListP,
        int             const version) {
@@ -3416,7 +3416,7 @@ TxFace(struct canvas * const canvasP,
 
 static drawFn TxSize;
 
-static void 
+static void
 TxSize(struct canvas * const canvasP,
        blitList *      const blitListP,
        int             const version) {
@@ -3438,7 +3438,7 @@ skip_text(blitList * const blitListP) {
 
 
 
-static int 
+static int
 abs_value(int const x) {
     if (x < 0)
         return -x;
@@ -3448,9 +3448,9 @@ abs_value(int const x) {
 
 
 
-static struct font* 
-get_font(int const font, 
-         int const size, 
+static struct font*
+get_font(int const font,
+         int const size,
          int const style) {
 
     int closeness, bestcloseness;
@@ -3483,8 +3483,8 @@ get_font(int const font,
 
 /* This only does 0, 90, 180 and 270 degree rotations */
 
-static void 
-rotate(int * const x, 
+static void
+rotate(int * const x,
        int * const y) {
     int tmp;
 
@@ -3515,7 +3515,7 @@ rotate(int * const x,
 
 static void
 do_ps_text(struct canvas * const canvasP,
-           Word            const tx, 
+           Word            const tx,
            Word            const ty) {
 
     int len, width, i, w, h, x, y, rx, ry, o;
@@ -3556,7 +3556,7 @@ do_ps_text(struct canvas * const canvasP,
     for (i = 0; i < len; i++) {
         if (!(glyph = tfont->glyph[str[i]]))
             continue;
-        
+
         y = ty - glyph->height - glyph->y;
         for (h = 0; h < glyph->height; h++) {
             for (w = 0; w < glyph->width; w++) {
@@ -3585,7 +3585,7 @@ do_ps_text(struct canvas * const canvasP,
 static void
 do_text(struct canvas *  const canvasP,
         blitList *       const blitListP,
-        Word             const startx, 
+        Word             const startx,
         Word             const starty) {
 
     if (blitListP)
@@ -3608,11 +3608,11 @@ do_text(struct canvas *  const canvasP,
                     int dy;
                     int h;
                     for (h = 0, dy = y - glyph->height - glyph->y;
-                         h < glyph->height; 
+                         h < glyph->height;
                          ++h, ++dy) {
                         int w;
                         for (w = 0; w < glyph->width; ++w) {
-                            struct RGBColor * const colorP = 
+                            struct RGBColor * const colorP =
                                 glyph->bmap[h * glyph->width + w] ?
                                 &black : &white;
                             draw_pixel(canvasP,
@@ -3703,7 +3703,7 @@ DHDVText(struct canvas * const canvasP,
 static void
 directBits(struct canvas * const canvasP,
            blitList *      const blitListP,
-           unsigned int    const pictVersion, 
+           unsigned int    const pictVersion,
            bool            const skipRegion) {
 
     struct pixMap   p;
@@ -3741,7 +3741,7 @@ directBits(struct canvas * const canvasP,
     if (verbose)
         pm_message("transfer mode = %s", const_name(transfer_name, mode));
 
-    if (skipRegion) 
+    if (skipRegion)
         skip_poly_or_region(canvasP, blitListP, pictVersion);
 
     unpackbits(ifp, &p.Bounds, 0, p.pixelSize, &raster);
@@ -3784,8 +3784,8 @@ DirectBitsRgn(struct canvas * const canvasP,
 static void
 do_pixmap(struct canvas * const canvasP,
           blitList *      const blitListP,
-          int             const version, 
-          Word            const rowBytes, 
+          int             const version,
+          Word            const rowBytes,
           int             const is_region) {
 /*----------------------------------------------------------------------------
    Do a paletted image.
@@ -3841,8 +3841,8 @@ static void
 do_bitmap(FILE *          const ifP,
           struct canvas * const canvasP,
           blitList *      const blitListP,
-          int             const version, 
-          int             const rowBytes, 
+          int             const version,
+          int             const rowBytes,
           int             const is_region) {
 /*----------------------------------------------------------------------------
    Do a bitmap.  That's one bit per pixel, 0 is white, 1 is black.
@@ -3857,7 +3857,7 @@ do_bitmap(FILE *          const ifP,
         /* This raster contains padding on the right to make a multiple
            of 16 pixels per row.
         */
-    static struct RGBColor color_table[] = { 
+    static struct RGBColor color_table[] = {
         {65535L, 65535L, 65535L}, {0, 0, 0} };
 
     readRect(&Bounds);
@@ -3912,7 +3912,7 @@ static void
 BitsRegion(struct canvas * const canvasP,
            blitList *      const blitListP,
            int             const version) {
-    
+
     Word rowBytesWord;
     bool pixMap;
     unsigned int rowBytes;
@@ -3969,18 +3969,18 @@ static struct opdef const optable[] = {
 /* 0x1f */  { "OpColor", NA, OpColor, "RGB OpColor for arithmetic modes" },
 /* 0x20 */  { "Line", 8, Line, "pnLoc (point), newPt (point)" },
 /* 0x21 */  { "LineFrom", 4, LineFrom, "newPt (point)" },
-/* 0x22 */  { "ShortLine", 6, ShortLine, 
+/* 0x22 */  { "ShortLine", 6, ShortLine,
               "pnLoc (point, dh, dv (-128 .. 127))" },
 /* 0x23 */  { "ShortLineFrom", 2, ShortLineFrom, "dh, dv (-128 .. 127)" },
 /* 0x24 */  RESERVED_OP(WORD_LEN),
 /* 0x25 */  RESERVED_OP(WORD_LEN),
 /* 0x26 */  RESERVED_OP(WORD_LEN),
 /* 0x27 */  RESERVED_OP(WORD_LEN),
-/* 0x28 */  { "LongText", NA, LongText, 
+/* 0x28 */  { "LongText", NA, LongText,
               "txLoc (point), count (0..255), text" },
 /* 0x29 */  { "DHText", NA, DHText, "dh (0..255), count (0..255), text" },
 /* 0x2a */  { "DVText", NA, DVText, "dv (0..255), count (0..255), text" },
-/* 0x2b */  { "DHDVText", NA, DHDVText, 
+/* 0x2b */  { "DHDVText", NA, DHDVText,
               "dh, dv (0..255), count (0..255), text" },
 /* 0x2c */  RESERVED_OP(WORD_LEN),
 /* 0x2d */  RESERVED_OP(WORD_LEN),
@@ -4092,23 +4092,23 @@ static struct opdef const optable[] = {
 /* 0x97 */  RESERVED_OP(WORD_LEN),
 /* 0x98 */  { "PackBitsRect", NA, BitsRect, "packed copybits, rect clipped" },
 /* 0x99 */  { "PackBitsRgn", NA, BitsRegion, "packed copybits, rgn clipped" },
-/* 0x9a */  { "DirectBitsRect", NA, DirectBitsRect, 
+/* 0x9a */  { "DirectBitsRect", NA, DirectBitsRect,
               "PixMap, srcRect, dstRect, int copymode, PixData" },
-/* 0x9b */  { "DirectBitsRgn", NA, DirectBitsRgn, 
+/* 0x9b */  { "DirectBitsRgn", NA, DirectBitsRgn,
               "PixMap, srcRect, dstRect, int copymode, maskRgn, PixData" },
 /* 0x9c */  RESERVED_OP(WORD_LEN),
 /* 0x9d */  RESERVED_OP(WORD_LEN),
 /* 0x9e */  RESERVED_OP(WORD_LEN),
 /* 0x9f */  RESERVED_OP(WORD_LEN),
 /* 0xa0 */  { "ShortComment", 2, ShortComment, "kind (word)" },
-/* 0xa1 */  { "LongComment", NA, LongComment, 
+/* 0xa1 */  { "LongComment", NA, LongComment,
               "kind (word), size (word), data" }
 };
 
 
 
 static void
-processOpcode(Word            const opcode, 
+processOpcode(Word            const opcode,
               struct canvas * const canvasP,
               blitList *      const blitListP,
               unsigned int    const version) {
@@ -4248,7 +4248,7 @@ interpretPict(FILE * const ofP) {
 
     while((opcode = get_op(version)) != 0xff)
         processOpcode(opcode, &canvas, fullres ? &blitList : NULL, version);
-    
+
     if (fullres) {
         if (blitList.unblittableText)
             pm_message("Warning: text is omitted from the output because "
@@ -4272,7 +4272,7 @@ loadDefaultFontDir(void) {
     int rc;
 
     rc = stat("fontdir", &statbuf);
-    
+
     if (rc == 0)
         load_fontdir("fontdir");
 }
diff --git a/converter/ppm/pjtoppm.c b/converter/ppm/pjtoppm.c
index 7b694fb3..b8b94f74 100644
--- a/converter/ppm/pjtoppm.c
+++ b/converter/ppm/pjtoppm.c
@@ -11,65 +11,87 @@
 */
 
 #include "ppm.h"
+#include "pm_c_util.h"
 #include "mallocvar.h"
 
 static char usage[] =  "[paintjetfile]";
 
-static int egetc ARGS((FILE *fp));
+
+
+static unsigned int
+uintProduct(unsigned int const multiplicand,
+            unsigned int const multiplier) {
+
+    if (UINT_MAX / multiplier < multiplicand)
+        pm_error("Airthmetic overflow");
+
+    return multiplicand * multiplier;
+}
+
+
+
 static int
-egetc(fp)
-    FILE *fp;
-{
+egetc(FILE * const ifP) {
     int c;
-    if ((c = fgetc(fp)) == -1)
+
+    c = fgetc(ifP);
+
+    if (c == -1)
         pm_error("unexpected end of file");
-    return(c);
+
+    return c;
 }
 
+
+
 int
-main(argc, argv)
-    int argc;
-    char *argv[];
-{
+main(int argc, const char ** argv) {
+
     int cmd, val;
     char buffer[BUFSIZ];
     int planes = 3, rows = -1, cols = -1;
-    int r = 0, c = 0, p = 0, i;
     unsigned char **image = NULL;
     int *imlen;
-    FILE *fp = stdin;
+    FILE * ifP;
     int mode;
     int argn;
     unsigned char bf[3];
-    pixel *pixrow;
+    pixel * pixrow;
+    int c;
+    int row;
+    int plane;
 
+    pm_proginit(&argc, argv);
 
-    ppm_init(&argc, argv);
     argn = 1;
     if (argn != argc)
-        fp = pm_openr(argv[argn++]);
+        ifP = pm_openr(argv[argn++]);
     else
-        fp = stdin;
+        ifP = stdin;
 
     if (argn != argc)
         pm_usage(usage);
 
-    while ((c = fgetc(fp)) != -1) {
+    row = 0;  /* initial value */
+    plane = 0;  /* initial value */
+
+    while ((c = fgetc(ifP)) != -1) {
         if (c != '\033')
             continue;
-        switch (c = egetc(fp)) {
+        switch (c = egetc(ifP)) {
         case 'E':   /* reset */
             break;
-        case '*':
-            cmd = egetc(fp);
+        case '*': {
+            unsigned int i;
+            cmd = egetc(ifP);
             for (i = 0; i < BUFSIZ; i++) {
-                if (!isdigit(c = egetc(fp)) && c != '+' && c != '-')
+                if (!isdigit(c = egetc(ifP)) && c != '+' && c != '-')
                     break;
                 buffer[i] = c;
             }
             if (i != 0) {
                 buffer[i] = '\0';
-                if (sscanf(buffer, "%d", &val) != 1) 
+                if (sscanf(buffer, "%d", &val) != 1)
                     pm_error("bad value `%s' at <ESC>*%c%c", buffer, cmd, c);
             }
             else
@@ -100,7 +122,7 @@ main(argc, argv)
                     break;
                 case 'U':   /* planes */
                     planes = val;
-                    if (planes != 3) 
+                    if (planes != 3)
                         pm_error("can handle only 3 plane files");
                     break;
                 case 'A':   /* begin raster */
@@ -126,38 +148,33 @@ main(argc, argv)
                     break;
                 case 'V':   /* send plane */
                 case 'W':   /* send last plane */
-                    if (rows == -1 || r >= rows || image == NULL) {
-                        if (rows == -1 || r >= rows)
+                    if (rows == -1 || row >= rows || image == NULL) {
+                        if (rows == -1 || row >= rows)
                             rows += 100;
                         if (image == NULL) {
-                            MALLOCARRAY(image, rows * planes);
-                            MALLOCARRAY(imlen, rows * planes);
-                        }
-                        else {
-                            image = (unsigned char **) 
-                                realloc(image, 
-                                        rows * planes * 
-                                        sizeof(unsigned char *));
-                            imlen = (int *) 
-                                realloc(imlen, rows * planes * sizeof(int));
+                            MALLOCARRAY(image, uintProduct(rows, planes));
+                            MALLOCARRAY(imlen, uintProduct(rows, planes));
+                        } else {
+                            REALLOCARRAY(image, uintProduct(rows, planes));
+                            REALLOCARRAY(imlen, uintProduct(rows, planes));
                         }
                     }
                     if (image == NULL || imlen == NULL)
                         pm_error("out of memory");
-                    if (p == planes) 
+                    if (plane >= planes)
                         pm_error("too many planes");
-                    cols = cols > val ? cols : val;
-                    imlen[r * planes + p] = val;
-                    MALLOCARRAY(image[r * planes + p], val);
-                    if (image[r * planes + p] == NULL) 
+                    cols = MAX(cols, val);
+                    imlen[row * planes + plane] = val;
+                    MALLOCARRAY(image[row * planes + plane], val);
+                    if (image[row * planes + plane] == NULL)
                         pm_error("out of memory");
-                    if (fread(image[r * planes + p], 1, val, fp) != val) 
+                    if (fread(image[row * planes + plane], 1, val, ifP) != val)
                         pm_error("short data");
                     if (c == 'V')
-                        p++;
+                        ++plane;
                     else {
-                        p = 0;
-                        r++;
+                        plane = 0;
+                        ++row;
                     }
                     break;
                 default:
@@ -166,7 +183,7 @@ main(argc, argv)
                 }
                 break;
             case 'p': /* Position */
-                if (p != 0) 
+                if (plane != 0)
                     pm_error("changed position in the middle of "
                              "transferring planes");
                 switch (c) {
@@ -175,15 +192,15 @@ main(argc, argv)
                     break;
                 case 'Y':
                     if (buffer[0] == '+')
-                        val = r + val;
+                        val = row + val;
                     if (buffer[0] == '-')
-                        val = r - val;
-                    for (; val > r; r++) 
-                        for (p = 0; p < 3; p++) {
-                            imlen[r * planes + p] = 0;
-                            image[r * planes + p] = NULL;
+                        val = row - val;
+                    for (; val > row; ++row)
+                        for (plane = 0; plane < 3; ++plane) {
+                            imlen[row * planes + plane] = 0;
+                            image[row * planes + plane] = NULL;
                         }
-                    r = val;
+                    row = val;
                     break;
                 default:
                     pm_message("uninmplemented <ESC>*%c%d%c", cmd, val, c);
@@ -192,62 +209,80 @@ main(argc, argv)
             default:
                 pm_message("uninmplemented <ESC>*%c%d%c", cmd, val, c);
                 break;
-            }
-        }
+             }
+        } /* case */
+        } /* switch */
     }
-    pm_close(fp);
-    rows = r;
+    pm_close(ifP);
+    rows = row;
     if (mode == 1) {
-        unsigned char *buf;
-        int newcols = 0;
-        newcols = 10240; /* It could not be larger that that! */
-        cols = 0;
-        for (r = 0; r < rows; r++) {
-            if (image[r * planes] == NULL)
+        int const newcols = 10240;  /* It could not be larger that that! */
+        unsigned char * buf;
+        unsigned int row;
+
+        for (row = 0, cols = 0; row < rows; ++row) {
+            unsigned int plane;
+            if (image[row * planes] == NULL)
                 continue;
-            for (p = 0; p < planes; p++) {
+            for (plane = 0; plane < planes; ++plane) {
+                unsigned int i;
+                unsigned int col;
                 MALLOCARRAY(buf, newcols);
-                if (buf == NULL) 
+                if (buf == NULL)
                     pm_error("out of memory");
-                for (i = 0, c = 0; c < imlen[p + r * planes]; c += 2)
-                    for (cmd = image[p + r * planes][c],
-                             val = image[p + r * planes][c+1]; 
-                         cmd >= 0 && i < newcols; cmd--, i++) 
+                for (i = 0, col = 0;
+                     col < imlen[plane + row * planes];
+                     col += 2)
+                    for (cmd = image[plane + row * planes][col],
+                             val = image[plane + row * planes][col+1];
+                         cmd >= 0 && i < newcols; cmd--, i++)
                         buf[i] = val;
-                cols = cols > i ? cols : i;
-                free(image[p + r * planes]);
-                /* 
-                 * This is less than what we have so it realloc should 
+                cols = MAX(cols, i);
+                free(image[plane + row * planes]);
+                /*
+                 * This is less than what we have so it realloc should
                  * not return null. Even if it does, tough! We will
                  * lose a line, and probably die on the next line anyway
                  */
-                image[p + r * planes] = (unsigned char *) realloc(buf, i);
+                image[plane + row * planes] = realloc(buf, i);
             }
         }
         cols *= 8;
     }
-            
-       
+
     ppm_writeppminit(stdout, cols, rows, (pixval) 255, 0);
     pixrow = ppm_allocrow(cols);
-    for (r = 0; r < rows; r++) {
-        if (image[r * planes] == NULL) {
-            for (c = 0; c < cols; c++)
-                PPM_ASSIGN(pixrow[c], 0, 0, 0);
+
+    for (row = 0; row < rows; ++row) {
+        if (image[row * planes] == NULL) {
+            unsigned int col;
+            for (col = 0; col < cols; ++col)
+                PPM_ASSIGN(pixrow[col], 0, 0, 0);
             continue;
         }
-        for (cmd = 0, c = 0; c < cols; c += 8, cmd++) 
-            for (i = 0; i < 8 && c + i < cols; i++) {
-                for (p = 0; p < planes; p++) 
-                    if (mode == 0 && cmd >= imlen[r * planes + p])
-                        bf[p] = 0;
-                    else
-                        bf[p] = (image[r * planes + p][cmd] & 
-                                 (1 << (7 - i))) ? 255 : 0;
-                PPM_ASSIGN(pixrow[c + i], bf[0], bf[1], bf[2]);
+        {
+            unsigned int col;
+            unsigned int cmd;
+            for (cmd = 0, col = 0; col < cols; col += 8, ++cmd) {
+                unsigned int i;
+                for (i = 0; i < 8 && col + i < cols; ++i) {
+                    unsigned int plane;
+                    for (plane = 0; plane < planes; ++plane)
+                        if (mode == 0 && cmd >= imlen[row * planes + plane])
+                            bf[plane] = 0;
+                        else
+                            bf[plane] = (image[row * planes + plane][cmd] &
+                                     (1 << (7 - i))) ? 255 : 0;
+                    PPM_ASSIGN(pixrow[col + i], bf[0], bf[1], bf[2]);
+                }
             }
-        ppm_writeppmrow(stdout, pixrow, cols, (pixval) 255, 0);
+        }
+        ppm_writeppmrow(stdout, pixrow, cols, 255, 0);
     }
     pm_close(stdout);
-    exit(0);
+
+    return 0;
 }
+
+
+
diff --git a/converter/ppm/ppmtobmp.c b/converter/ppm/ppmtobmp.c
index a0de38e3..f89cec8d 100644
--- a/converter/ppm/ppmtobmp.c
+++ b/converter/ppm/ppmtobmp.c
@@ -94,15 +94,15 @@ parseCommandLine(int argc, const char ** argv,
     unsigned int windowsSpec, os2Spec, mapfileSpec;
 
     unsigned int option_def_index;
-    
+
     MALLOCARRAY(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENTRY */
     OPTENT3('w', "windows",   OPT_FLAG, NULL, &windowsSpec,            0);
     OPTENT3('o', "os2",       OPT_FLAG, NULL, &os2Spec,                0);
-    OPTENT3(0,   "bpp",       OPT_UINT, &cmdlineP->bpp, 
+    OPTENT3(0,   "bpp",       OPT_UINT, &cmdlineP->bpp,
             &cmdlineP->bppSpec,      0);
-    OPTENT3(0,   "mapfile",   OPT_STRING, &cmdlineP->mapfile, 
+    OPTENT3(0,   "mapfile",   OPT_STRING, &cmdlineP->mapfile,
             &mapfileSpec,             0);
 
     opt.opt_table = option_def;
@@ -111,18 +111,18 @@ parseCommandLine(int argc, const char ** argv,
 
     pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
 
-    if (windowsSpec && os2Spec) 
+    if (windowsSpec && os2Spec)
         pm_error("Can't specify both -windows and -os2 options.");
-    else if (windowsSpec) 
+    else if (windowsSpec)
         cmdlineP->class = BMP_C_WIN_V1;
     else if (os2Spec)
         cmdlineP->class = BMP_C_OS2_1x;
-    else 
+    else
         cmdlineP->class = BMP_C_WIN_V1;
 
 
     if (cmdlineP->bppSpec) {
-        if (cmdlineP->bpp != 1 && cmdlineP->bpp != 4 && 
+        if (cmdlineP->bpp != 1 && cmdlineP->bpp != 4 &&
             cmdlineP->bpp != 8 && cmdlineP->bpp != 24)
         pm_error("Invalid -bpp value specified: %u.  The only values valid "
                  "in the BMP format are 1, 4, 8, and 24 bits per pixel",
@@ -136,7 +136,7 @@ parseCommandLine(int argc, const char ** argv,
         cmdlineP->inputFilename = pm_strdup("-");  /* he wants stdin */
     else if (argc - 1 == 1)
         cmdlineP->inputFilename = pm_strdup(argv[1]);
-    else 
+    else
         pm_error("Too many arguments.  The only argument accepted "
                  "is the input file specificaton");
 
@@ -155,7 +155,7 @@ freeCommandLine(struct CmdlineInfo const cmdline) {
 
 static void
 putByte(FILE * const fp, unsigned char const v) {
-    if (putc(v, fp) == EOF) 
+    if (putc(v, fp) == EOF)
         pm_error("Write of a byte to a file failed.");
 
     /* Note:  a Solaris/SPARC user reported on 2003.09.29 that the above
@@ -170,7 +170,7 @@ putByte(FILE * const fp, unsigned char const v) {
 
 static void
 putShort(FILE * const fp, short const v) {
-    if (pm_writelittleshort(fp, v) == -1) 
+    if (pm_writelittleshort(fp, v) == -1)
         pm_error("Write of a halfword to a file failed.");
 }
 
@@ -188,7 +188,7 @@ putLong(FILE * const fp, long const v) {
 -----------------------------------------------------------------------------*/
 
 static unsigned int
-bmpWriteFileHeader(FILE *        const fp, 
+bmpWriteFileHeader(FILE *        const fp,
                    unsigned int  const cbSize,
                    unsigned int  const offBits) {
 /*----------------------------------------------------------------------------
@@ -199,28 +199,28 @@ bmpWriteFileHeader(FILE *        const fp,
 
     /* cbSize */
     putLong(fp, cbSize);
-    
+
     /* xHotSpot */
     putShort(fp, 0);
-    
+
     /* yHotSpot */
     putShort(fp, 0);
-    
+
     /* offBits */
     putLong(fp, offBits);
 
     assert(BMPlenfileheader() == 14);
-    
+
     return 14;
 }
 
 
 
 static unsigned int
-bmpWriteInfoHeader(FILE *        const fp, 
-                   enum bmpClass const class, 
-                   unsigned long const bitcount, 
-                   unsigned long const x, 
+bmpWriteInfoHeader(FILE *        const fp,
+                   enum bmpClass const class,
+                   unsigned long const bitcount,
+                   unsigned long const x,
                    unsigned long const y) {
 /*----------------------------------------------------------------------------
   Write the INFO header.
@@ -289,10 +289,10 @@ bmpWriteInfoHeader(FILE *        const fp,
 
 
 static unsigned int
-bmpWriteRgb(FILE *        const fp, 
-            enum bmpClass const class, 
-            pixval        const R, 
-            pixval        const G, 
+bmpWriteRgb(FILE *        const fp,
+            enum bmpClass const class,
+            pixval        const R,
+            pixval        const G,
             pixval        const B) {
 /*----------------------------------------------------------------------------
   Return the number of bytes written.
@@ -325,8 +325,8 @@ bmpWriteRgb(FILE *        const fp,
 
 
 static unsigned int
-bmpWriteColormap(FILE *           const ifP, 
-                 enum bmpClass    const class, 
+bmpWriteColormap(FILE *           const ifP,
+                 enum bmpClass    const class,
                  int              const bpp,
                  const ColorMap * const colorMapP) {
 /*----------------------------------------------------------------------------
@@ -373,10 +373,10 @@ lookupColor(colorhash_table const cht,
 
 
 static void
-bmpWriteRow_palette(FILE *          const fp, 
-                    const pixel *   const row, 
+bmpWriteRow_palette(FILE *          const fp,
+                    const pixel *   const row,
                     unsigned int    const cols,
-                    unsigned short  const bpp, 
+                    unsigned short  const bpp,
                     colorhash_table const cht,
                     unsigned int *  const nBytesP) {
 /*----------------------------------------------------------------------------
@@ -385,7 +385,7 @@ bmpWriteRow_palette(FILE *          const fp,
    Return the number of bytes written as *nBytesP.
 -----------------------------------------------------------------------------*/
     BITSTREAM b;
-    
+
     b = pm_bitinit(fp, "w");
     if (b == NULL)
         pm_error("Failed to initialize output file for output");
@@ -393,9 +393,9 @@ bmpWriteRow_palette(FILE *          const fp,
         int rc;
         unsigned int nbyte;
         unsigned int col;
-        
+
         nbyte = 0;      /* initial value */
-        
+
         for (col = 0; col < cols; ++col) {
             unsigned int colorIndex;
             int rc;
@@ -413,7 +413,7 @@ bmpWriteRow_palette(FILE *          const fp,
         rc = pm_bitfini(b);
 
         nbyte += rc;
-                
+
         /* Make sure we write a multiple of 4 bytes.  */
         while (nbyte % 4 != 0) {
             putByte(fp, 0);
@@ -426,13 +426,13 @@ bmpWriteRow_palette(FILE *          const fp,
 
 
 static void
-bmpWriteRow_truecolor(FILE *         const fp, 
-                      const pixel *  const row, 
+bmpWriteRow_truecolor(FILE *         const fp,
+                      const pixel *  const row,
                       unsigned long  const cols,
                       pixval         const maxval,
                       unsigned int * const nBytesP) {
 /*----------------------------------------------------------------------------
-  Write a row of a truecolor BMP image to the file 'fp'.  The row is 
+  Write a row of a truecolor BMP image to the file 'fp'.  The row is
   'row', which is 'cols' columns long.
 
 
@@ -441,14 +441,14 @@ bmpWriteRow_truecolor(FILE *         const fp,
     /* This works only for 24 bits per pixel.  To implement this for the
        general case (which is only hypothetical -- this program doesn't
        write any truecolor images except 24 bit and apparently no one
-       else does either), you would move this function into 
+       else does either), you would move this function into
        BMPwriterow_palette, which writes arbitrary bit strings.  But
        that would be a lot slower and less robust.
     */
 
     int nbyte;  /* Number of bytes we have written to file so far */
-    int col;  
-        
+    int col;
+
     nbyte = 0;  /* initial value */
     for (col = 0; col < cols; ++col) {
         /* We scale to the BMP maxval, which is always 255. */
@@ -465,19 +465,19 @@ bmpWriteRow_truecolor(FILE *         const fp,
         putByte(fp, 0);
         ++nbyte;
     }
-    
+
     *nBytesP = nbyte;
 }
 
 
 
 static unsigned int
-bmpWriteRaster(FILE *          const fp, 
-               unsigned long   const cols, 
+bmpWriteRaster(FILE *          const fp,
+               unsigned long   const cols,
                unsigned long   const rows,
                Colortype       const colortype,
-               unsigned short  const cBitCount, 
-               const pixel **  const pixels, 
+               unsigned short  const cBitCount,
+               const pixel **  const pixels,
                pixval          const maxval,
                colorhash_table const cht) {
 /*----------------------------------------------------------------------------
@@ -499,9 +499,9 @@ bmpWriteRaster(FILE *          const fp,
         unsigned int nBytesThisRow;
 
         if (colortype == PALETTE)
-            bmpWriteRow_palette(fp, pixels[row], cols, 
+            bmpWriteRow_palette(fp, pixels[row], cols,
                                 cBitCount, cht, &nBytesThisRow);
-        else 
+        else
             bmpWriteRow_truecolor(fp, pixels[row], cols, maxval,
                                   &nBytesThisRow);
 
@@ -516,13 +516,13 @@ bmpWriteRaster(FILE *          const fp,
 
 
 static void
-bmpEncode(FILE *           const ifP, 
-          enum bmpClass    const class, 
+bmpEncode(FILE *           const ifP,
+          enum bmpClass    const class,
           Colortype        const colortype,
           unsigned int     const bpp,
-          int              const x, 
-          int              const y, 
-          const pixel **   const pixels, 
+          int              const x,
+          int              const y,
+          const pixel **   const pixels,
           pixval           const maxval,
           const ColorMap * const colorMapP) {
 /*----------------------------------------------------------------------------
@@ -571,10 +571,10 @@ makeBilevelColorMap(ColorMap * const colorMapP) {
 
 
 static void
-bmpEncodePbm(FILE *           const ifP, 
-             enum bmpClass    const class, 
-             int              const cols, 
-             int              const rows, 
+bmpEncodePbm(FILE *           const ifP,
+             enum bmpClass    const class,
+             int              const cols,
+             int              const rows,
              unsigned char ** const bitrow) {
 /*----------------------------------------------------------------------------
   Write a bi-level BMP file of the given class.
@@ -591,7 +591,7 @@ bmpEncodePbm(FILE *           const ifP,
     unsigned long nbyte;
     ColorMap bilevelColorMap;
     unsigned int row;
-    
+
     /* colortype == PALETTE */
     pm_message("Writing 1 bit per pixel with a black-white palette");
 
@@ -613,7 +613,7 @@ bmpEncodePbm(FILE *           const ifP,
         if (bytesWritten != packedBytes){
             if (feof(ifP))
                 pm_error("End of file writing row %u of BMP raster.", row);
-            else 
+            else
                 pm_error("Error writing BMP raster.  Errno=%d (%s)",
                          errno, strerror(errno));
         }  else
@@ -659,7 +659,7 @@ minBmpBitsForColorCount(unsigned int const colorCount) {
        implement and other bpp's have in fact been seen to confuse
        viewers.  There is an extended BMP format that has 16 bpp
        too, but this program doesn't know how to generate that
-       (see Bmptopnm.c, though).  
+       (see Bmptopnm.c, though).
     */
     if (minbits == 1)
         return 1;
@@ -704,7 +704,7 @@ getMapFile(const char *   const mapFileName,
                  MAXCOLORS, cols * rows);
 
     count = 0; /* initial value */
-    
+
     for (row = 0; row < rows; ++row) {
         unsigned int col;
         for (col = 0; col < cols; ++col) {
@@ -732,15 +732,15 @@ getMapFile(const char *   const mapFileName,
 
 
 static void
-analyzeColors(const pixel **    const pixels, 
-              int               const cols, 
-              int               const rows, 
-              pixval            const maxval, 
+analyzeColors(const pixel **    const pixels,
+              int               const cols,
+              int               const rows,
+              pixval            const maxval,
               unsigned int *    const minimumBppP,
               ColorMap *        const colorMapP) {
 /*----------------------------------------------------------------------------
   Look at the colors in the image 'pixels' and compute values to use in
-  representing those colors in a BMP image.  
+  representing those colors in a BMP image.
 
   First of all, count the distinct colors.  Return as *minimumBppP
   the minimum number of bits per pixel it will take to represent all
@@ -762,7 +762,7 @@ analyzeColors(const pixel **    const pixels,
     int colorCount;
 
     pm_message("analyzing colors...");
-    chv = ppm_computecolorhist((pixel**)pixels, cols, rows, MAXCOLORS, 
+    chv = ppm_computecolorhist((pixel**)pixels, cols, rows, MAXCOLORS,
                                &colorCount);
     colorMapP->count = colorCount;
     if (chv == NULL) {
@@ -785,7 +785,7 @@ analyzeColors(const pixel **    const pixels,
             mapEntryP->grn = (pixval) PPM_GETG(chv[i].color) * 255 / maxval;
             mapEntryP->blu = (pixval) PPM_GETB(chv[i].color) * 255 / maxval;
         }
-    
+
         /* And make a hash table for fast lookup. */
         colorMapP->cht = ppm_colorhisttocolorhash(chv, colorMapP->count);
         ppm_freecolorhist(chv);
@@ -798,7 +798,7 @@ static void
 chooseColortypeBpp(bool             const userRequestsBpp,
                    unsigned int     const requestedBpp,
                    unsigned int     const minimumBpp,
-                   Colortype *      const colortypeP, 
+                   Colortype *      const colortypeP,
                    unsigned int *   const bitsPerPixelP) {
 /*----------------------------------------------------------------------------
    Determine whether the BMP raster should contain RGB values or palette
@@ -832,12 +832,12 @@ chooseColortypeBpp(bool             const userRequestsBpp,
             *bitsPerPixelP = requestedBpp;
     }
 
-    assert(*bitsPerPixelP == 1 || 
-           *bitsPerPixelP == 4 || 
-           *bitsPerPixelP == 8 || 
+    assert(*bitsPerPixelP == 1 ||
+           *bitsPerPixelP == 4 ||
+           *bitsPerPixelP == 8 ||
            *bitsPerPixelP == 24);
 
-    if (*bitsPerPixelP > 8) 
+    if (*bitsPerPixelP > 8)
         *colortypeP = TRUECOLOR;
     else {
         *colortypeP = PALETTE;
@@ -853,7 +853,7 @@ doPbm(FILE *        const ifP,
       int           const format,
       enum bmpClass const class,
       FILE *        const ofP) {
-    
+
     /* We read the raster directly from the input with
         pbm_readpbmrow_packed().  The raster format is almost
         identical, except that BMP specifies rows to be zero-filled to
@@ -864,7 +864,7 @@ doPbm(FILE *        const ifP,
     int const adjustedCols = (cols+31) /32 * 32;
     int const packedBytes  =  adjustedCols /8;
 
-    unsigned char ** bitrow;    
+    unsigned char ** bitrow;
     unsigned int row;
 
     bitrow = pbm_allocarray_packed(adjustedCols, rows);
@@ -877,15 +877,15 @@ doPbm(FILE *        const ifP,
         thisRow[packedBytes-2] = 0x00;
         thisRow[packedBytes-3] = 0x00;
         thisRow[packedBytes-4] = 0x00;
-        
+
         pbm_readpbmrow_packed(ifP, thisRow, cols, format);
 
         {
             unsigned int i;
-            for (i = 0; i < colChars; ++i) 
+            for (i = 0; i < colChars; ++i)
                 thisRow[i] = ~thisRow[i]; /* flip all pixels */
         }
-        /* This may seem unnecessary, because the color palette 
+        /* This may seem unnecessary, because the color palette
            (RGB[] in bmpEncodePbm) can be inverted for the same effect.
            However we take this precaution, for there is indication that
            some BMP viewers may get confused with that.
@@ -896,7 +896,7 @@ doPbm(FILE *        const ifP,
     }
 
     bmpEncodePbm(ofP, class, cols, rows, bitrow);
-}            
+}
 
 
 
@@ -920,27 +920,27 @@ doPgmPpm(FILE *        const ifP,
     unsigned int bitsPerPixel;
     Colortype colortype;
     unsigned int row;
-    
+
     pixel ** pixels;
     ColorMap colorMap;
-    
+
     pixels = ppm_allocarray(cols, rows);
-    
+
     for (row = 0; row < rows; ++row)
         ppm_readppmrow(ifP, pixels[row], cols, maxval, ppmFormat);
-    
+
     if (mapFileName)
         getMapFile(mapFileName, &minimumBpp, &colorMap);
     else
-        analyzeColors((const pixel**)pixels, cols, rows, maxval, 
+        analyzeColors((const pixel**)pixels, cols, rows, maxval,
                       &minimumBpp, &colorMap);
-    
+
     chooseColortypeBpp(userRequestsBpp, requestedBpp, minimumBpp,
                        &colortype, &bitsPerPixel);
-    
+
     bmpEncode(ofP, class, colortype, bitsPerPixel,
               cols, rows, (const pixel**)pixels, maxval, &colorMap);
-    
+
     freeColorMap(&colorMap);
 
     ppm_freearray(pixels, rows);
@@ -964,10 +964,11 @@ main(int           argc,
     parseCommandLine(argc, argv, &cmdline);
 
     ifP = pm_openr(cmdline.inputFilename);
-    
+
     ppm_readppminit(ifP, &cols, &rows, &maxval, &ppmFormat);
-    
-    if (PPM_FORMAT_TYPE(ppmFormat) == PBM_TYPE)
+
+    if ((PPM_FORMAT_TYPE(ppmFormat) == PBM_TYPE) &&
+        (!cmdline.bppSpec || cmdline.bpp == 1))
         doPbm(ifP, cols, rows, ppmFormat, cmdline.class, stdout);
     else
         doPgmPpm(ifP, cols, rows, maxval, ppmFormat,
diff --git a/converter/ppm/ppmtomitsu.c b/converter/ppm/ppmtomitsu.c
index e59f09b3..5b0b3245 100644
--- a/converter/ppm/ppmtomitsu.c
+++ b/converter/ppm/ppmtomitsu.c
@@ -274,7 +274,7 @@ static void
 doLookupTableColors(colorhist_vector const table,
                     unsigned int     const nColor,
                     hashinfo *       const colorhashtable) {
-                
+
     unsigned int colval;
     for (colval = 0; colval < nColor; ++colval) {
         struct hashinfo * const hashchain =
@@ -287,7 +287,7 @@ doLookupTableColors(colorhist_vector const table,
         datum(PPM_GETR((table[colval]).color));
         datum(PPM_GETG((table[colval]).color));
         datum(PPM_GETB((table[colval]).color));
-        
+
         hashrun = hashchain;  /* start at beginning of chain */
 
         if (hashrun->flag == -1) {
@@ -323,7 +323,7 @@ doLookupTableGrays(colorhist_vector const table,
         datum(PPM_GETB((table[colval]).color));
         datum(PPM_GETB((table[colval]).color));
         datum(PPM_GETB((table[colval]).color));
-        
+
         hashrun = hashchain;  /* start at beginning of chain */
 
         if (hashrun->flag == -1) {
@@ -410,7 +410,7 @@ writeColormapRaster(pixel **         const pixels,
             struct hashinfo * const hashchain =
                 &colorhashtable[myhash(pixrow[col])];
             struct hashinfo * p;
-                
+
             p = hashchain;
             while (!PPM_EQUAL((p->color), pixrow[col])) {
                 assert(p->next);
@@ -554,7 +554,7 @@ doTiny(FILE *           const ifP,
        int              const enlarge,
        int              const copy,
        struct mediasize const medias) {
-       
+
     pixel * pixelrow;
     unsigned char * redrow;
     unsigned char * grnrow;
@@ -653,7 +653,7 @@ main(int argc, char * argv[]) {
         tiny = TRUE;
     else
         pm_usage(usage);
-        ++argn;
+    ++argn;
     }
 
     if (argn < argc) {
@@ -690,7 +690,7 @@ main(int argc, char * argv[]) {
     }
 
     ppm_readppminit(ifP, &cols, &rows, &maxval, &format);
-    
+
     if (tiny) {
         doTiny(ifP, cols, rows, maxval, format,
                sharpness, enlarge, copy, medias);
@@ -707,7 +707,7 @@ main(int argc, char * argv[]) {
 
         /* first check wether we can use the lut transfer */
 
-        table = ppm_computecolorhist(pixels, cols, rows, MAXLUTCOL+1, 
+        table = ppm_computecolorhist(pixels, cols, rows, MAXLUTCOL+1,
                                      &nColor);
         if (table)
             useLookupTable(pixels, table, sharpness, enlarge, copy, medias,
diff --git a/converter/ppm/tgatoppm.c b/converter/ppm/tgatoppm.c
index 3660e646..662f741b 100644
--- a/converter/ppm/tgatoppm.c
+++ b/converter/ppm/tgatoppm.c
@@ -30,7 +30,6 @@ static int mapped, rlencoded;
 
 static pixel ColorMap[MAXCOLORS];
 static gray AlphaMap[MAXCOLORS];
-static int RLE_count = 0, RLE_flag = 0;
 
 struct cmdlineInfo {
     /* All the information the user supplied in the command line,
@@ -79,14 +78,14 @@ parseCommandLine(int argc, char ** argv,
         cmdlineP->input_filename = "-";  /* he wants stdin */
     else if (argc - 1 == 1)
         cmdlineP->input_filename = strdup(argv[1]);
-    else 
+    else
         pm_error("Too many arguments.  The only argument accepted "
                  "is the input file specification");
 
     if (alpha_spec &&
         streq(cmdlineP->alpha_filename, "-"))
         cmdlineP->alpha_stdout = 1;
-    else 
+    else
         cmdlineP->alpha_stdout = 0;
 
     if (!alpha_spec)
@@ -103,89 +102,111 @@ getbyte(FILE * const ifP) {
 
     if ( fread( (char*) &c, 1, 1, ifP ) != 1 )
         pm_error( "EOF / read error" );
-    
+
     return c;
 }
 
 
 
+static int RLE_count = 0, RLE_flag = 0;
+
+
+
 static void
-get_pixel(FILE * const ifP, pixel * dest, int Size, gray *alpha_p) {
+handleRun(FILE * const ifP,
+          bool * const repeatP) {
+
+    if (rlencoded) {
+        if (RLE_count == 0) {
+            /* Have to restart run. */
+            unsigned char i;
+            i = getbyte(ifP);
+            RLE_flag = (i & 0x80);
+            if (RLE_flag == 0) {
+                /* Stream of unencoded pixels. */
+                RLE_count = i + 1;
+            } else {
+                /* Single pixel replicated. */
+                RLE_count = i - 127;
+            }
+            /* Decrement count & get pixel. */
+            --RLE_count;
+            *repeatP = false;
+        } else {
+            /* Have already read count & (at least) first pixel. */
+            --RLE_count;
+            if (RLE_flag != 0) {
+                /* Replicated pixels. */
+                *repeatP = true;
+            } else
+                *repeatP = false;
+        }
+    } else
+        *repeatP = false;
+}
 
-    static pixval Red, Grn, Blu;
-    static pixval Alpha;
-    unsigned char j, k;
+
+
+static void
+getPixel(FILE *  const ifP,
+         pixel * const dest,
+         int     const size,
+         gray *  const alphaP) {
+
+    static pixval red, grn, blu;
+    static pixval alpha;
     static unsigned int l;
+    unsigned char j, k;
+    bool repeat;
+        /* Next pixel is just a repeat (from an encoded run) */
 
-    /* Check if run length encoded. */
-    if ( rlencoded )
-	{
-	if ( RLE_count == 0 )
-	    { /* Have to restart run. */
-	    unsigned char i;
-	    i = getbyte( ifP );
-	    RLE_flag = ( i & 0x80 );
-	    if ( RLE_flag == 0 )
-		/* Stream of unencoded pixels. */
-		RLE_count = i + 1;
-	    else
-		/* Single pixel replicated. */
-		RLE_count = i - 127;
-	    /* Decrement count & get pixel. */
-	    --RLE_count;
-	    }
-	else
-	    { /* Have already read count & (at least) first pixel. */
-	    --RLE_count;
-	    if ( RLE_flag != 0 )
-		/* Replicated pixels. */
-		goto PixEncode;
-	    }
-	}
-    /* Read appropriate number of bytes, break into RGB. */
-    switch ( Size )
-	{
-	case 8:				/* Grayscale, read and triplicate. */
-	Red = Grn = Blu = l = getbyte( ifP );
-    Alpha = 0;
-	break;
-
-	case 16:			/* 5 bits each of red green and blue. */
-	case 15:			/* Watch byte order. */
-	j = getbyte( ifP );
-	k = getbyte( ifP );
-	l = ( (unsigned int) k << 8 ) + j;
-	Red = ( k & 0x7C ) >> 2;
-	Grn = ( ( k & 0x03 ) << 3 ) + ( ( j & 0xE0 ) >> 5 );
-	Blu = j & 0x1F;
-    Alpha = 0;
-	break;
-
-	case 32:            /* 8 bits each of blue, green, red, and alpha */
-	case 24:			/* 8 bits each of blue, green, and red. */
-	Blu = getbyte( ifP );
-	Grn = getbyte( ifP );
-	Red = getbyte( ifP );
-	if ( Size == 32 )
-	    Alpha = getbyte( ifP );
-    else
-        Alpha = 0;
-	l = 0;
-	break;
+    handleRun(ifP, &repeat);
 
-	default:
-	pm_error( "unknown pixel size (#2) - %d", Size );
-	}
+    if (repeat) {
+        /* Use red, grn, blu, alpha, and l from prior call to getPixel */
+    } else {
+        /* Read appropriate number of bytes, break into RGB. */
+        switch (size) {
+        case 8:             /* Grayscale, read and triplicate. */
+            red = grn = blu = l = getbyte(ifP);
+            alpha = 0;
+            break;
 
-PixEncode:
-    if ( mapped ) {
+        case 16:            /* 5 bits each of red green and blue. */
+        case 15:            /* Watch byte order. */
+            j = getbyte(ifP);
+            k = getbyte(ifP);
+            l = ((unsigned int)k << 8) + j;
+            red = (k & 0x7C) >> 2;
+            grn = ((k & 0x03) << 3) + ((j & 0xE0) >> 5);
+            blu = j & 0x1F;
+            alpha = 0;
+            break;
+
+        case 32:            /* 8 bits each of blue, green, red, and alpha */
+        case 24:            /* 8 bits each of blue, green, and red. */
+            blu = getbyte(ifP);
+            grn = getbyte(ifP);
+            red = getbyte(ifP);
+            if (size == 32)
+                alpha = getbyte(ifP);
+            else
+                alpha = 0;
+            l = 0;
+            break;
+
+        default:
+            pm_error("unknown pixel size (#2) - %d", size);
+        }
+    }
+    if (mapped) {
         *dest = ColorMap[l];
-        *alpha_p = AlphaMap[l];
+        *alphaP = AlphaMap[l];
     } else {
-        PPM_ASSIGN( *dest, Red, Grn, Blu );
-        *alpha_p = Alpha;
-    }
+        PPM_ASSIGN(*dest, red, grn, blu);
+        *alphaP = alpha;
     }
+}
 
 
 
@@ -217,7 +238,7 @@ readtga(FILE * const ifP, struct ImageHeader * tgaP) {
     tgaP->Rsrvd = ( flags & 0x10 ) >> 4;
     tgaP->OrgBit = ( flags & 0x20 ) >> 5;
     tgaP->IntrLve = ( flags & 0xc0 ) >> 6;
-    
+
     if ( tgaP->IdLength != 0 )
         fread( junk, 1, (int) tgaP->IdLength, ifP );
 }
@@ -231,14 +252,14 @@ get_map_entry(FILE * const ifP, pixel * Value, int Size, gray * Alpha) {
 
     /* Read appropriate number of bytes, break into rgb & put in map. */
     switch ( Size )
-	{
-	case 8:				/* Grayscale, read and triplicate. */
+    {
+    case 8:             /* Grayscale, read and triplicate. */
         r = g = b = getbyte( ifP );
         a = 0;
         break;
-        
-	case 16:			/* 5 bits each of red green and blue. */
-	case 15:			/* Watch for byte order. */
+
+    case 16:            /* 5 bits each of red green and blue. */
+    case 15:            /* Watch for byte order. */
         j = getbyte( ifP );
         k = getbyte( ifP );
         r = ( k & 0x7C ) >> 2;
@@ -246,21 +267,21 @@ get_map_entry(FILE * const ifP, pixel * Value, int Size, gray * Alpha) {
         b = j & 0x1F;
         a = 0;
         break;
-        
-	case 32:            /* 8 bits each of blue, green, red, and alpha */
-	case 24:			/* 8 bits each of blue green and red. */
+
+    case 32:            /* 8 bits each of blue, green, red, and alpha */
+    case 24:            /* 8 bits each of blue green and red. */
         b = getbyte( ifP );
         g = getbyte( ifP );
         r = getbyte( ifP );
         if ( Size == 32 )
             a = getbyte( ifP );
-        else 
+        else
             a = 0;
         break;
-        
-	default:
+
+    default:
         pm_error( "unknown colormap pixel size (#2) - %d", Size );
-	}
+    }
     PPM_ASSIGN( *Value, r, g, b );
     *Alpha = a;
 }
@@ -326,84 +347,89 @@ main(int argc, char * argv[]) {
 
     if (cmdline.alpha_stdout)
         alpha_file = stdout;
-    else if (cmdline.alpha_filename == NULL) 
+    else if (cmdline.alpha_filename == NULL)
         alpha_file = NULL;
     else
         alpha_file = pm_openw(cmdline.alpha_filename);
-    
-    if (cmdline.alpha_stdout) 
+
+    if (cmdline.alpha_stdout)
         imageout_file = NULL;
     else
         imageout_file = stdout;
-    
+
     /* Read the Targa file header. */
     readtga(ifP, &tga_head);
 
-    if (cmdline.headerdump) 
+    if (cmdline.headerdump)
         dumpHeader(tga_head);
 
     rows = ((int) tga_head.Height_lo) + ((int) tga_head.Height_hi) * 256;
     cols = ((int) tga_head.Width_lo)  + ((int) tga_head.Width_hi)  * 256;
 
     switch (tga_head.ImgType) {
-	case TGA_Map:
-	case TGA_RGB:
-	case TGA_Mono:
-	case TGA_RLEMap:
-	case TGA_RLERGB:
-	case TGA_RLEMono:
+    case TGA_Map:
+    case TGA_RGB:
+    case TGA_Mono:
+    case TGA_RLEMap:
+    case TGA_RLERGB:
+    case TGA_RLEMono:
+        break;
+    case TGA_CompMap:
+    case TGA_CompMap4:
+        pm_error("Targa image type %d (compressed color-mapped data). "
+                 "Cannot handle this format.", tga_head.ImgType);
         break;
-	default:
+    default:
         pm_error("unknown Targa image type %d", tga_head.ImgType);
-	}
-    
+    }
+
     if (tga_head.ImgType == TGA_Map ||
         tga_head.ImgType == TGA_RLEMap ||
         tga_head.ImgType == TGA_CompMap ||
         tga_head.ImgType == TGA_CompMap4)
-	{ /* Color-mapped image */
+    { /* Color-mapped image */
         if (tga_head.CoMapType != 1)
-            pm_error( 
+            pm_error(
                 "mapped image (type %d) with color map type != 1",
                 tga_head.ImgType );
         mapped = true;
         /* Figure maxval from CoSize. */
         switch (tga_head.CoSize) {
-	    case 8:
-	    case 24:
-	    case 32:
+        case 8:
+        case 24:
+        case 32:
             maxval = 255;
             break;
 
-	    case 15:
-	    case 16:
+        case 15:
+        case 16:
             maxval = 31;
             break;
 
-	    default:
-	    pm_error(
-		"unknown colormap pixel size - %d", tga_head.CoSize );
-	    }
-	} else { 
+        default:
+        pm_error(
+        "unknown colormap pixel size - %d", tga_head.CoSize );
+        }
+    } else {
         /* Not colormap, so figure maxval from PixelSize. */
         mapped = false;
         switch ( tga_head.PixelSize ) {
-	    case 8:
-	    case 24:
-	    case 32:
+        case 8:
+        case 24:
+        case 32:
             maxval = 255;
             break;
-            
-	    case 15:
-	    case 16:
+
+        case 15:
+        case 16:
             maxval = 31;
             break;
-            
-	    default:
+
+        default:
             pm_error("unknown pixel size - %d", tga_head.PixelSize);
-	    }
-	}
-    
+        }
+    }
+
     /* If required, read the color map information. */
     if ( tga_head.CoMapType != 0 ) {
         unsigned int i;
@@ -416,7 +442,7 @@ main(int argc, char * argv[]) {
         for (i = temp1; i < (temp1 + temp2); ++i)
             get_map_entry(ifP, &ColorMap[i], (int) tga_head.CoSize,
                           &AlphaMap[i]);
-	}
+    }
 
     /* Check run-length encoding. */
     if (tga_head.ImgType == TGA_RLEMap ||
@@ -425,7 +451,7 @@ main(int argc, char * argv[]) {
         rlencoded = 1;
     else
         rlencoded = 0;
-    
+
     /* Read the Targa file body and convert to portable format. */
     pixels = ppm_allocarray( cols, rows );
     alpha = pgm_allocarray( cols, rows );
@@ -437,10 +463,10 @@ main(int argc, char * argv[]) {
         realrow = truerow;
         if (tga_head.OrgBit == 0)
             realrow = rows - realrow - 1;
-        
+
         for (col = 0; col < cols; ++col)
-            get_pixel(ifP, &(pixels[realrow][col]), (int) tga_head.PixelSize,
-                      &(alpha[realrow][col]));
+            getPixel(ifP, &(pixels[realrow][col]), (int) tga_head.PixelSize,
+                     &(alpha[realrow][col]));
         if (tga_head.IntrLve == TGA_IL_Four)
             truerow += 4;
         else if (tga_head.IntrLve == TGA_IL_Two)
@@ -449,17 +475,20 @@ main(int argc, char * argv[]) {
             ++truerow;
         if (truerow >= rows)
             truerow = ++baserow;
-	}
+    }
     pm_close(ifP);
-    
-    if (imageout_file) 
+
+    if (imageout_file)
         ppm_writeppm(imageout_file, pixels, cols, rows, (pixval) maxval, 0);
     if (alpha_file)
         pgm_writepgm(alpha_file, alpha, cols, rows, (pixval) maxval, 0);
-    if (imageout_file) 
+    if (imageout_file)
         pm_close(imageout_file);
     if (alpha_file)
         pm_close(alpha_file);
 
     return 0;
 }
+
+
+
diff --git a/converter/ppm/xpmtoppm.c b/converter/ppm/xpmtoppm.c
index 9471ec7c..46101a09 100644
--- a/converter/ppm/xpmtoppm.c
+++ b/converter/ppm/xpmtoppm.c
@@ -82,14 +82,14 @@ parseCommandLine(int argc, char ** argv,
         cmdlineP->input_filespec = NULL;  /* he wants stdin */
     else if (argc - 1 == 1)
         cmdlineP->input_filespec = strdup(argv[1]);
-    else 
+    else
         pm_error("Too many arguments.  The only argument accepted\n"
                  "is the input file specification");
 
-    if (cmdlineP->alpha_filename && 
+    if (cmdlineP->alpha_filename &&
         streq(cmdlineP->alpha_filename, "-"))
         cmdlineP->alpha_stdout = TRUE;
-    else 
+    else
         cmdlineP->alpha_stdout = FALSE;
 
 }
@@ -224,7 +224,7 @@ entryMatch(struct ColorNameHashTableEntry const entry,
 
     {
         unsigned int i;
-        
+
         for (i = 0; i < size; ++i) {
             if (name[i] != entry.colorName[i])
                 return false;
@@ -272,7 +272,7 @@ hash_find(const ColorNameHash *             const hashP,
     for (i = initialIndex;
          !entryMatch(hashP->table[i], name, hashP->nameSize);
          bumpIndex(&i, hashP->size, initialIndex));
-         
+
     *entryPP = &hashP->table[i];
 }
 
@@ -358,7 +358,7 @@ getLine(char * const line,
 
    If 'backup' is true, the "next line" is the previously read line, i.e.
    the one in that one-line buffer.  Otherwise, the "next line" is the next
-   line from the real file.  After reading the backed up line, we reset 
+   line from the real file.  After reading the backed up line, we reset
    'backup' to false.
 
    Return the line as a null terminated string in *line, which is an
@@ -371,7 +371,7 @@ getLine(char * const line,
                  "which is out of bounds");
 
     if (backup) {
-        strncpy(line, lastInputLine, size); 
+        strncpy(line, lastInputLine, size);
         backup = FALSE;
     } else {
         if (fgets(line, size, stream) == NULL)
@@ -398,7 +398,7 @@ getword(char * const output, char ** const cursorP) {
         strncpy(output, t1, t2 - t1);
     output[t2 - t1] = '\0';
     *cursorP = t2;
-}    
+}
 
 
 
@@ -438,7 +438,7 @@ validateColorName(const char * const name,
 
 static void
 interpretXpm3ColorTableLine(char               const line[],
-                            unsigned int       const seqNum, 
+                            unsigned int       const seqNum,
                             unsigned int       const charsPerPixel,
                             ColorNameHash *    const hashP) {
 /*----------------------------------------------------------------------------
@@ -458,22 +458,22 @@ interpretXpm3ColorTableLine(char               const line[],
 -----------------------------------------------------------------------------*/
     /* Note: this code seems to allow for multi-word color specifications,
        but I'm not aware that such are legal.  Ultimately, ppm_parsecolor()
-       interprets the name, and I believe it takes only single word 
+       interprets the name, and I believe it takes only single word
        color specifications.  -Bryan 2001.05.06.
     */
-    char str2[MAX_LINE+1];    
+    char str2[MAX_LINE+1];
     char * t1;
     char * t2;
     int endOfEntry;   /* boolean */
-    
+
     unsigned int curkey, key, highkey;  /* current color key */
-    bool lastwaskey;    
+    bool lastwaskey;
         /* The last token we processes was a key, and we have processed
            at least one token.
         */
     char curbuf[BUFSIZ];        /* current buffer */
     bool isTransparent;
-    
+
     const char * colorName;
         /* The 0-3 character name this color map line gives the color
            (i.e. the name that the raster uses).  This is NOT NUL-terminated.
@@ -485,20 +485,20 @@ interpretXpm3ColorTableLine(char               const line[],
     if (t1 == NULL)
         pm_error("A line that is supposed to be an entry in the color "
                  "table does not start with a quote.  The line is '%s'.  "
-                 "It is the %uth entry in the color table.", 
+                 "It is the %uth entry in the color table.",
                  line, seqNum);
     else
         ++t1;  /* Points now to first color number character */
-    
+
     validateColorName(t1, charsPerPixel);
     colorName = t1;
 
     t1 += charsPerPixel;
 
     /*
-     * read color keys and values 
+     * read color keys and values
      */
-    curkey = 0; 
+    curkey = 0;
     highkey = 1;
     lastwaskey = FALSE;
     t2 = t1;
@@ -512,8 +512,8 @@ interpretXpm3ColorTableLine(char               const line[],
             /* See if the word we got is a valid key (and get its key
                number if so)
             */
-            for (key = 1; 
-                 key <= NKEYS && !streq(xpmColorKeys[key - 1], str2); 
+            for (key = 1;
+                 key <= NKEYS && !streq(xpmColorKeys[key - 1], str2);
                  key++);
             isKey = (key <= NKEYS);
 
@@ -521,21 +521,21 @@ interpretXpm3ColorTableLine(char               const line[],
                 /* This word is a color specification (or "none" for
                    transparent).
                 */
-                if (!curkey) 
+                if (!curkey)
                     pm_error("Missing color key token in color table line "
                              "'%s' before '%s'.", line, str2);
-                if (!lastwaskey) 
+                if (!lastwaskey)
                     strcat(curbuf, " ");        /* append space */
-                if ( (strneq(str2, "None", 4)) 
+                if ( (strneq(str2, "None", 4))
                      || (strneq(str2, "none", 4)) ) {
                     /* This entry identifies the transparent color number */
                     strcat(curbuf, "#000000");  /* Make it black */
                     isTransparent = TRUE;
-                } else 
+                } else
                     strcat(curbuf, str2);       /* append buf */
                 lastwaskey = FALSE;
-            } else { 
-                /* This word is a key.  So we've seen the last of the 
+            } else {
+                /* This word is a key.  So we've seen the last of the
                    info for the previous key, and we must either put it
                    in the color map or ignore it if we already have a higher
                    color form in the colormap for this colormap entry.
@@ -561,7 +561,7 @@ interpretXpm3ColorTableLine(char               const line[],
         addToColorMap(hashP, colorName, curbuf, isTransparent);
         highkey = curkey;
     }
-    if (highkey == 1) 
+    if (highkey == 1)
         pm_error("C error scanning color table");
 }
 
@@ -588,10 +588,10 @@ readV3ColorTable(FILE *             const ifP,
         /* skip the comment line if any */
         if (strneq(line, "/*", 2))
             getLine(line, sizeof(line), ifP);
-            
+
         interpretXpm3ColorTableLine(line, seqNum, charsPerPixel,
                                     colorNameHashP);
-                                    
+
     }
     *colorNameHashPP = colorNameHashP;
 }
@@ -601,7 +601,7 @@ readV3ColorTable(FILE *             const ifP,
 static void
 readXpm3Header(FILE *             const ifP,
                unsigned int *     const widthP,
-               unsigned int *     const heightP, 
+               unsigned int *     const heightP,
                unsigned int *     const charsPerPixelP,
                ColorNameHash **   const colorNameHashPP) {
 /*----------------------------------------------------------------------------
@@ -620,14 +620,14 @@ readXpm3Header(FILE *             const ifP,
 -----------------------------------------------------------------------------*/
     char line[MAX_LINE+1];
     const char * xpm3_signature = "/* XPM */";
-    
+
     unsigned int width, height;
     unsigned int nColors;
     unsigned int charsPerPixel;
 
     /* Read the XPM signature comment */
     getLine(line, sizeof(line), ifP);
-    if (!strneq(line, xpm3_signature, strlen(xpm3_signature))) 
+    if (!strneq(line, xpm3_signature, strlen(xpm3_signature)))
         pm_error("Apparent XPM 3 file does not start with '/* XPM */'.  "
                  "First line is '%s'", xpm3_signature);
 
@@ -716,7 +716,7 @@ readV1ColorTable(FILE *           const ifP,
 static void
 readXpm1Header(FILE *           const ifP,
                unsigned int *   const widthP,
-               unsigned int *   const heightP, 
+               unsigned int *   const heightP,
                unsigned int *   const charsPerPixelP,
                ColorNameHash ** const colorNameHashPP) {
 /*----------------------------------------------------------------------------
@@ -724,11 +724,11 @@ readXpm1Header(FILE *           const ifP,
   getLine() stream is presently positioned to the beginning of the
   file and it is a Version 1 XPM file.  Leave the stream positioned
   after the header.
-  
+
   Return the information from the header the same as for readXpm3Header.
 -----------------------------------------------------------------------------*/
     int format, v;
-    bool processedStaticChar;  
+    bool processedStaticChar;
         /* We have read up to and interpreted the "static char..." line */
     char * t1;
     unsigned int nColors;
@@ -876,7 +876,7 @@ convertRow(char                  const line[],
                    "'%s'.  Ignoring this line.", line);
     } else {
         unsigned int col;
-    
+
         ++lineCursor; /* Skip to first character after quote */
 
         /* Handle pixels until a close quote, eol, or we've returned all
@@ -890,7 +890,7 @@ convertRow(char                  const line[],
 
             alpharow[col] = hash_isTransparent(colorNameHashP, lineCursor) ?
                 PBM_BLACK : PBM_WHITE;
-            
+
             lineCursor += charsPerPixel;
         }
         if (*lineCursor != '"')
@@ -903,7 +903,7 @@ convertRow(char                  const line[],
 static void
 convertRaster(FILE *                const ifP,
               unsigned int          const cols,
-              unsigned int          const rows, 
+              unsigned int          const rows,
               unsigned int          const charsPerPixel,
               const ColorNameHash * const colorNameHashP,
               FILE *                const imageOutFileP,
@@ -928,7 +928,7 @@ convertRaster(FILE *                const ifP,
         bool haveLine;
 
         for (haveLine = false; !haveLine; ) {
-            getLine(line, sizeof(line), ifP); 
+            getLine(line, sizeof(line), ifP);
 
             if (strneq(line, "/*", 2)) {
                 /* It's a comment.  Ignore it. */
@@ -939,22 +939,22 @@ convertRaster(FILE *                const ifP,
                    pixrow, alpharow);
 
         if (imageOutFileP)
-            ppm_writeppmrow(imageOutFileP, 
+            ppm_writeppmrow(imageOutFileP,
                             pixrow, cols, PPM_MAXMAXVAL, 0);
-            if (alphaOutFileP)
-                pbm_writepbmrow(alphaOutFileP, alpharow, cols, 0);
+        if (alphaOutFileP)
+            pbm_writepbmrow(alphaOutFileP, alpharow, cols, 0);
     }
 
     pbm_freerow(alpharow);
     ppm_freerow(pixrow);
 }
- 
+
 
 
 static void
 readXpmHeader(FILE *           const ifP,
               unsigned int *   const widthP,
-              unsigned int *   const heightP, 
+              unsigned int *   const heightP,
               unsigned int *   const charsPerPixelP,
               ColorNameHash ** const colorNameHashPP) {
 /*----------------------------------------------------------------------------
@@ -974,7 +974,7 @@ readXpmHeader(FILE *           const ifP,
     /* Read the header line */
     getLine(line, sizeof(line), ifP);
     backup = TRUE;  /* back up so next read reads this line again */
-    
+
     rc = sscanf(line, "/* %s */", str1);
     if (rc == 1 && strneq(str1, "XPM", 3)) {
         /* It's an XPM version 3 file */
@@ -987,7 +987,7 @@ readXpmHeader(FILE *           const ifP,
     *heightP        = height;
     *charsPerPixelP = charsPerPixel;
 }
- 
+
 
 
 int
@@ -1008,20 +1008,20 @@ main(int argc, char *argv[]) {
 
     verbose = cmdline.verbose;
 
-    if ( cmdline.input_filespec != NULL ) 
+    if ( cmdline.input_filespec != NULL )
         ifP = pm_openr( cmdline.input_filespec);
     else
         ifP = stdin;
 
     if (cmdline.alpha_stdout)
         alphaOutFileP = stdout;
-    else if (cmdline.alpha_filename == NULL) 
+    else if (cmdline.alpha_filename == NULL)
         alphaOutFileP = NULL;
     else {
         alphaOutFileP = pm_openw(cmdline.alpha_filename);
     }
 
-    if (cmdline.alpha_stdout) 
+    if (cmdline.alpha_stdout)
         imageOutFileP = NULL;
     else
         imageOutFileP = stdout;
@@ -1036,7 +1036,7 @@ main(int argc, char *argv[]) {
 
     convertRaster(ifP, cols, rows, charsPerPixel, colorNameHashP,
                   imageOutFileP, alphaOutFileP);
-    
+
     pm_close(ifP);
     if (imageOutFileP)
         pm_close(imageOutFileP);
@@ -1044,7 +1044,7 @@ main(int argc, char *argv[]) {
         pm_close(alphaOutFileP);
 
     hash_destroy(colorNameHashP);
-    
+
     return 0;
 }
 
@@ -1066,17 +1066,17 @@ main(int argc, char *argv[]) {
 **   Tue Apr 9 1991
 **
 ** Rainer Sinkwitz sinkwitz@ifi.unizh.ch - 21 Nov 91:
-**  - Bug fix, no advance of read ptr, would not read 
-**    colors like "ac c black" because it would find 
+**  - Bug fix, no advance of read ptr, would not read
+**    colors like "ac c black" because it would find
 **    the "c" of "ac" and then had problems with "c"
 **    as color.
-**    
+**
 **  - Now understands multiword X11 color names
-**  
+**
 **  - Now reads multiple color keys. Takes the color
 **    of the hightest available key. Lines no longer need
 **    to begin with key 'c'.
-**    
+**
 **  - expanded line buffer to from 500 to 2048 for bigger files
 */
 
diff --git a/converter/ppm/xvminitoppm.c b/converter/ppm/xvminitoppm.c
index d76bea87..ad207ae9 100644
--- a/converter/ppm/xvminitoppm.c
+++ b/converter/ppm/xvminitoppm.c
@@ -13,12 +13,13 @@
 #include <assert.h>
 #include <string.h>
 #include <errno.h>
+#include <stdbool.h>
 
 #include "pm_c_util.h"
 #include "nstring.h"
+#include "pm.h"
 #include "ppm.h"
 
-#define BUFSIZE 256
 
 
 typedef struct xvPalette {
@@ -53,25 +54,6 @@ parseCommandLine(int const argc,
 
 
 static void
-getLine(FILE * const ifP,
-        char * const buf,
-        size_t const size) {
-
-    char * rc;
-
-    rc = fgets(buf, size, ifP);
-    if (rc == NULL) {
-        if (ferror(ifP))
-            pm_error("read error.  fgets() failed, errno=%d (%s)",
-                     errno, strerror(errno));
-        else
-            pm_error("unexpected EOF");
-    }
-}
-
-
-
-static void
 makeXvPalette(xvPalette * const xvPaletteP) {
 
     unsigned int paletteIndex;
@@ -101,37 +83,53 @@ readXvHeader(FILE *         const ifP,
              unsigned int * const colsP,
              unsigned int * const rowsP,
              unsigned int * const maxvalP) {
-           
-    char buf[256];
+
+    char * buf;
+    size_t bufferSz;
+    int eof;
+    size_t lineLen;
     unsigned int cols, rows, maxval;
     int rc;
     bool endOfComments;
-    
-    getLine(ifP, buf, sizeof(buf));
 
-    if (!strneq(buf, "P7 332", 6))
+    buf = NULL;   /* initial value */
+    bufferSz = 0; /* initial value */
+
+    pm_getline(ifP, &buf, &bufferSz, &eof, &lineLen);
+
+    if (eof || !strneq(buf, "P7 332", 6))
         pm_error("Input is not a XV thumbnail picture.  It does not "
                  "begin with the characters 'P7 332'.");
 
-    endOfComments = FALSE;
-    while (!endOfComments) {
-        getLine(ifP, buf, sizeof(buf));
+    for (endOfComments = false; !endOfComments; ) {
+        int eof;
+        size_t lineLen;
+        pm_getline(ifP, &buf, &bufferSz, &eof, &lineLen);
+        if (eof)
+            pm_error("EOF before #END_OF_COMMENTS line");
         if (strneq(buf, "#END_OF_COMMENTS", 16))
-            endOfComments = TRUE;
+            endOfComments = true;
         else if (strneq(buf, "#BUILTIN", 8))
             pm_error("This program does not know how to "
                      "convert builtin XV thumbnail pictures");
     }
-    getLine(ifP, buf, sizeof(buf));
+    pm_getline(ifP, &buf, &bufferSz, &eof, &lineLen);
+    if (eof)
+        pm_error("EOF where cols/rows/maxval line expected");
+
     rc = sscanf(buf, "%u %u %u", &cols, &rows, &maxval);
     if (rc != 3)
         pm_error("error parsing dimension info '%s'.  "
                  "It does not consist of 3 decimal numbers.", buf);
     if (maxval != 255)
         pm_error("bogus XV thumbnail maxval %u.  Should be 255", maxval);
+
     *colsP = cols;
     *rowsP = rows;
     *maxvalP = maxval;
+
+    if (buf)
+        free(buf);
 }
 
 
@@ -166,7 +164,7 @@ writePpm(FILE *             const ifP,
             else {
                 unsigned int const paletteIndex = byte;
                 assert(byte >= 0);
-                
+
                 PPM_ASSIGN(pixrow[col],
                            xvPaletteP->red[paletteIndex],
                            xvPaletteP->grn[paletteIndex],
@@ -181,7 +179,7 @@ writePpm(FILE *             const ifP,
 
 
 
-int 
+int
 main(int    argc,
      char * argv[]) {
 
@@ -190,7 +188,7 @@ main(int    argc,
     unsigned int cols, rows;
     pixval maxval;
     xvPalette xvPalette;
- 
+
     ppm_init(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
diff --git a/converter/tga.h b/converter/tga.h
index fdbe4047..1a65663d 100644
--- a/converter/tga.h
+++ b/converter/tga.h
@@ -44,3 +44,16 @@ typedef char ImageIDField[IMAGEIDFIELDMAXSIZE];
 #define TGA_IL_Four 2
 
 enum TGAbaseImageType {TGA_MAP_TYPE, TGA_MONO_TYPE, TGA_RGB_TYPE};
+
+enum TGAmapType {
+    /* A type of Targa color map */
+    TGA_MAPTYPE_SHORT,
+        /* Each entry in the color map is 2 bytes: 5 bits each of
+           red, green, and blue, and one optional alpha bit.
+        */
+    TGA_MAPTYPE_LONG
+        /* Each entry in the color map is 3 bytes: red, green, and blue,
+           plus one optional alpha byte
+        */
+};
+
diff --git a/doc/HISTORY b/doc/HISTORY
index 1023e61b..f0dc1084 100644
--- a/doc/HISTORY
+++ b/doc/HISTORY
@@ -4,38 +4,51 @@ Netpbm.
 CHANGE HISTORY 
 --------------
 
-18.12.17 BJH  Release 10.84.05
+18.12.29 BJH  Release 10.85.00
 
-              bmptopnm: Fix wrong output for non-colormapped OS2 BMP.  Broken
-              in Netpbm 10.18 (September 2003).
+              pnmpaste: Add -nand, -nor, and -nxor.
 
-18.11.05 BJH  Release 10.84.04
+              pamcut: add -cropleft, -cropright, -croptop, -cropbottom.
 
-              bmptopnm: Fix array bounds violation when index value in raster
-              is too big.  Broken after Netpbm 10.10 (October 2002) but before
-              10.19 (November 2003).
+              ppmtobmp: respect -bpp with PBM input.
 
-18.11.11 BJH  Release 10.84.03
+              bmptopnm: allow single color colormap with bpp 1.
+
+              bmptopnm: validate plane count = 1.
+
+              bmptopnm: Add RLE4 compression decoding.  This was ostensibly
+              added in Netpbm 10.32 (February 2006), but never worked.
+              
+              Add pammixmulti.  Thanks Scott Pakin (scott+pbm@pakin.org).
+
+              pamtotga: Add -cmap16 .
+    
+              pamtris: Add -rgb, -grayscale.  Add w parameter to vertex
+              instructions.  Fix perspective correctness.  Thanks Lucas Brunno
+              Luna <lucaslunar32@hotmail.com>.
 
               picttoppm: accept rectangle specifications in input that have
               the corners in any order, not just upper left, then lower right.
 
-              Merge build: fix so legacy program names 'pnmtopnm', 'ppmnorm',
-              and 'ppmtotga' work again.
+              pamtotga: identify compressed colormapped format in error
+              message saying the program doesn't know how to interpret it.
 
-              Merge build: fix duplicate symbol 'prefabCode' in g3topbm,
-              pbmtog3.  Introduced in Netpbm 10.79 (June 2017).
+              pamtotga: Ignore extra planes in black and white or grayscale
+              input instead of generating junk output.
 
-18.10.07 BJH  Release 10.84.02
+              Merge build: make old names for JPEG, TIFF, and PNG converter
+              programs work (function previously omitted by design because it
+              was too hard).
 
-              libnetpbm: Fix invalid memory reference in color name processing
-              when trivial memory allocation fails.
-
-              Build: fix reference to nonexistent getline on Mac OS X 10.6.
+              bmptopnm: Fix wrong output for non-colormapped OS2 BMP.  Broken
+              in Netpbm 10.18 (September 2003).
 
-              Build: fix reference to nonexistent strndup on Mac OS X 10.6.
+              bmptopnm: Fix array bounds violation when index value in raster
+              is too big.  Broken after Netpbm 10.11 (October 2002) but before
+              10.19 (November 2003).
 
-18.10.02 BJH  Release 10.84.01
+              libnetpbm: Fix invalid memory reference in color name processing
+              when trivial memory allocation fails.
 
               pamtojpeg2k: fix incorrect interpretation of -ilyrrates option
               when it contains multiple delimiter characters in a row.  Always
@@ -44,8 +57,17 @@ CHANGE HISTORY
               pnmtojbig: fix incorrect handling of -x option.  Always broken
               (pnmtojbig was new in Netpbm 9.2 (May 2000)).
 
+              pjtoppm, pbmtoppa: fix arithmetic overflow.
+
+              Build: fix parallel make.
+
+              Build: fix reference to nonexistent getline on Mac OS X 10.6.
+
               Build: fix reference to nonexistent strndup on Mac OS X 10.6.
 
+              Merge build: fix duplicate symbol 'prefabCode' in g3topbm,
+              pbmtog3.  Introduced in Netpbm 10.79 (June 2017).
+
 18.09.29 BJH  Release 10.84.00
 
               Add pamaltsat.  Thanks Anton Shepelev <anton.txt@gmail.com>.
@@ -95,6 +117,10 @@ CHANGE HISTORY
               pbmmask: Fix invalid memory reference with zero-dimension
               input image.  Broken in primordial Netpbm, ca 1989.
 
+              pamtojpeg2k: Fix incorrect metadata in output with GRAYSCALE PAM
+              input.  Always broken (pamtojpeg2k was new in Netpbm 10.12
+              (November 2002)).
+
               libnetpbm: Add pnm_colorspec_rgb_integer,
               pnm_colorspec_rgb_norm, pnm_colorspec_rgb_x11,
               pnm_colorspec_dict, pnm_colorspec_dict_close.
@@ -608,10 +634,10 @@ CHANGE HISTORY
               pamstereogram: Add -xbegin.  Change default to render from
               center outwards intead of from right to left, thus making the
               center of the image the crispest part.  Thanks Scott Pakin
-              (scott@pakin.org).
+              (scott+pbm@pakin.org).
 
               pamstereogram: Allow -xshift and -yshift to be negative.  Thanks
-              Scott Pakin (scott@pakin.org).
+              Scott Pakin (scott+pbm@pakin.org).
 
               pnmpsnr: Add -rgb.
 
@@ -1247,7 +1273,7 @@ CHANGE HISTORY
               get down to a compression ratio of 1.
 
               pamstereogram: -smoothing smooths images even without -texfile.
-              Thanks Scott Pakin (scott@pakin.org).
+              Thanks Scott Pakin (scott+pbm@pakin.org).
 
               pnmcat: set don't care bits in packed PBM output to zero so
               they are predictable.
@@ -1339,10 +1365,10 @@ CHANGE HISTORY
               Elijah Griffin <eli@panix.com>.
 
               pamstereogram: Add -planes .  Thanks Scott Pakin
-              (scott@pakin.org).
+              (scott+pbm@pakin.org).
 
               pamstereogram: improve verbose output.  Thanks Scott Pakin
-              (scott@pakin.org).
+              (scott+pbm@pakin.org).
 
               pamstereogram: fix crash introduced in Netpbm 10.54 (March 2011).
 
@@ -2349,7 +2375,7 @@ CHANGE HISTORY
 
 07.06.26 BJH  Release 10.39.00
 
-              Add pamtooctave.  Thanks Scott Pakin (scott@pakin.org).
+              Add pamtooctave.  Thanks Scott Pakin (scott+pbm@pakin.org).
 
               Add pamundice.
 
@@ -2862,7 +2888,7 @@ CHANGE HISTORY
               arguments; fix crash.
 
               pamstereogram: Fix crippling bugs.  Thanks Scott Pakin
-              <scott@pakin.org>.
+              <scott+pbm@pakin.org>.
 
               giftopnm: Handle case of a clear code at the end of a block.
 
@@ -3654,12 +3680,12 @@ CHANGE HISTORY
               Add pamperspective.  Thanks Mark Weyer
               <Mark.Weyer@math.uni-freiburg.de>.
 
-              Add pamstereogram.  Thanks Scott Pakin <scott@pakin.org>.
+              Add pamstereogram.  Thanks Scott Pakin <scott+pbm@pakin.org>.
 
               Add pc1toppm.  Thanks Roine Gustafsson
               <roine@users.sourceforge.net>.
 
-              Add pbmtodjvurle.  Thanks Scott Pakin <scott@pakin.org>.
+              Add pbmtodjvurle.  Thanks Scott Pakin <scott+pbm@pakin.org>.
 
               Add infotopam.  Thanks Rich Griswold <griswold@acm.org>.
 
@@ -3716,7 +3742,7 @@ CHANGE HISTORY
 
               Add pamsharpness, pamsharpmap.
 
-              Add ppmtodjvurle.  Thanks Scott Pakin <scott@pakin.org>.
+              Add ppmtodjvurle.  Thanks Scott Pakin <scott+pbm@pakin.org>.
 
               pstopnm: add -dpi option.
 
diff --git a/editor/Makefile b/editor/Makefile
index 159f8ea7..de5ae666 100644
--- a/editor/Makefile
+++ b/editor/Makefile
@@ -19,7 +19,7 @@ SUBDIRS = pamflip specialty
 PORTBINARIES = pamaddnoise pamaltsat pambackground pamcomp pamcut \
 	       pamdice pamditherbw pamedge \
 	       pamenlarge \
-	       pamfunc pamlevels pammasksharpen \
+	       pamfunc pamlevels pammasksharpen pammixmulti \
 	       pamperspective pamrecolor pamrubber \
 	       pamscale pamsistoaglyph pamstretch pamthreshold pamundice \
 	       pamwipeout \
@@ -51,12 +51,14 @@ OBJECTS = $(BINARIES:%=%.o)
 
 MERGE_OBJECTS = $(MERGEBINARIES:%=%.o2)
 
+HAVE_MERGE_COMPAT=YES
+
 .PHONY: all
 all: $(BINARIES) $(SUBDIRS:%=%/all)
 
 include $(SRCDIR)/common.mk
 
-install.bin: install.bin.local
+install.bin install.merge: install.bin.local
 
 .PHONY: install.bin.local
 install.bin.local: $(PKGDIR)/bin
@@ -98,3 +100,15 @@ install.bin.local: $(PKGDIR)/bin
 	cd $(PKGDIR)/bin ; \
 	rm -f pnmcomp$(EXE) ; \
 	$(SYMLINK) pamcomp$(EXE) pnmcomp$(EXE)
+
+mergecomptrylist:
+	cat /dev/null >$@
+	echo "TRY(\"pnminterp\",  main_pamstretch);" >>$@
+	echo "TRY(\"pgmnorm\",    main_pnmnorm);"    >>$@
+	echo "TRY(\"ppmnorm\",    main_pnmnorm);"    >>$@
+	echo "TRY(\"pgmedge\",    main_pamedge);"    >>$@
+	echo "TRY(\"pnmenlarge\", main_pamenlarge);" >>$@
+	echo "TRY(\"pnmcut\",     main_pamcut);"     >>$@
+	echo "TRY(\"pnmscale\",   main_pamscale);"   >>$@
+	echo "TRY(\"pnmcomp\",    main_pamcomp);"    >>$@
+
diff --git a/editor/pamcomp.c b/editor/pamcomp.c
index 0732b92f..3e27731f 100644
--- a/editor/pamcomp.c
+++ b/editor/pamcomp.c
@@ -64,7 +64,7 @@ enum alphaMix {AM_KEEPUNDER, AM_OVERLAY};
        its contribution to the composition.
     */
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -86,7 +86,7 @@ struct cmdlineInfo {
 static void
 parseCommandLine(int                        argc,
                  const char **              argv,
-                 struct cmdlineInfo * const cmdlineP ) {
+                 struct CmdlineInfo * const cmdlineP ) {
 /*----------------------------------------------------------------------------
    Parse program command line described in Unix standard form by argc
    and argv.  Return the information in the options as *cmdlineP.
@@ -385,7 +385,7 @@ computeOverlayPosition(int                const underCols,
                        int                const underRows,
                        int                const overCols,
                        int                const overRows,
-                       struct cmdlineInfo const cmdline,
+                       struct CmdlineInfo const cmdline,
                        int *              const originLeftP,
                        int *              const originTopP) {
 /*----------------------------------------------------------------------------
@@ -899,7 +899,7 @@ composite(int          const originleft,
 
 
 static void
-initAlphaFile(struct cmdlineInfo const cmdline,
+initAlphaFile(struct CmdlineInfo const cmdline,
               struct pam *       const overlayPamP,
               FILE **            const filePP,
               struct pam *       const pamP) {
@@ -925,7 +925,7 @@ initAlphaFile(struct cmdlineInfo const cmdline,
 int
 main(int argc, const char *argv[]) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     FILE * underlayFileP;
     FILE * overlayFileP;
     FILE * alphaFileP;
diff --git a/editor/pamcut.c b/editor/pamcut.c
index 7c41af38..db5b5b3d 100644
--- a/editor/pamcut.c
+++ b/editor/pamcut.c
@@ -1,9 +1,9 @@
-/*============================================================================ 
+/*============================================================================
                                 pamcut
 ==============================================================================
   Cut a rectangle out of a Netpbm image
 
-  This is inspired by and intended as a replacement for Pnmcut by 
+  This is inspired by and intended as a replacement for Pnmcut by
   Jef Poskanzer, 1989.
 
   By Bryan Henderson, San Jose CA.  Contributed to the public domain
@@ -24,27 +24,55 @@
        but we hope not.
        */
 
+typedef struct {
+/*----------------------------------------------------------------------------
+   A location in one dimension (row or column) in the image.
+-----------------------------------------------------------------------------*/
+    enum { LOCTYPE_NONE, LOCTYPE_FROMNEAR, LOCTYPE_FROMFAR } locType;
+
+    unsigned int n;
+        /* Row or column count.
+
+           If LOCTYPE_NONE: Meaningless
+
+           If LOCTYPE_FROMFAR: Number of colums from the far edge of the image
+           (right or bottom).  Last column/row is 1.
+
+           If LOCTYPE_FROMNEAR: Number of colums from the near edge of the
+           image (left or top).  First column/row is 0.
+        */
+} Location;
+
+
+
 struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
     const char * inputFileName;  /* File name of input file */
 
-    /* The following describe the rectangle the user wants to cut out. 
+    /* The following describe the rectangle the user wants to cut out.
        the value UNSPEC for any of them indicates that value was not
        specified.  A negative value means relative to the far edge.
-       'width' and 'height' are not negative.  These specifications 
+       'width' and 'height' are not negative.  These specifications
        do not necessarily describe a valid rectangle; they are just
        what the user said.
-       */
-    int left;
-    int right;
-    int top;
-    int bottom;
-    int width;
-    int height;
-    unsigned int pad;
 
+       These do not follow the Netpbm convention of having members of this
+       structure that are identical to the name of an option class being
+       the value of that option.  'left', for example, is not the value of
+       the -left option; it could reflect the value of a -cropleft option
+       instead.
+    */
+    Location leftLoc;
+    Location rghtLoc;
+    Location topLoc;
+    Location botLoc;
+    unsigned int widthSpec;
+    unsigned int width;
+    unsigned int heightSpec;
+    unsigned int height;
+    unsigned int pad;
     unsigned int verbose;
 };
 
@@ -63,26 +91,34 @@ parseCommandLine(int argc, const char ** const argv,
     optStruct3 opt;
     unsigned int option_def_index;
 
+    int left, right, top, bottom;
+    unsigned int cropleftSpec, croprightSpec, croptopSpec, cropbottomSpec;
+    unsigned int cropleft, cropright, croptop, cropbottom;
+    unsigned int leftSpec, rightSpec, topSpec, bottomSpec;
+
+    bool haveLegacyLocationArgs;
+        /* The user specified location with top, left, height, and width
+           arguments like in original Pnmcut instead of with named options.
+        */
+
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0,   "left",       OPT_INT,    &cmdlineP->left,     NULL,      0);
-    OPTENT3(0,   "right",      OPT_INT,    &cmdlineP->right,    NULL,      0);
-    OPTENT3(0,   "top",        OPT_INT,    &cmdlineP->top,      NULL,      0);
-    OPTENT3(0,   "bottom",     OPT_INT,    &cmdlineP->bottom,   NULL,      0);
-    OPTENT3(0,   "width",      OPT_INT,    &cmdlineP->width,    NULL,      0);
-    OPTENT3(0,   "height",     OPT_INT,    &cmdlineP->height,   NULL,      0);
+    OPTENT3(0,   "left",       OPT_INT,    &left,       &leftSpec,          0);
+    OPTENT3(0,   "right",      OPT_INT,    &right,      &rightSpec,         0);
+    OPTENT3(0,   "top",        OPT_INT,    &top,        &topSpec,           0);
+    OPTENT3(0,   "bottom",     OPT_INT,    &bottom,     &bottomSpec,        0);
+    OPTENT3(0,   "cropleft",   OPT_UINT,   &cropleft,   &cropleftSpec,      0);
+    OPTENT3(0,   "cropright",  OPT_UINT,   &cropright,  &croprightSpec,     0);
+    OPTENT3(0,   "croptop",    OPT_UINT,   &croptop,    &croptopSpec,       0);
+    OPTENT3(0,   "cropbottom", OPT_UINT,   &cropbottom, &cropbottomSpec,    0);
+    OPTENT3(0,   "width",      OPT_UINT,   &cmdlineP->width,
+            &cmdlineP->widthSpec,       0);
+    OPTENT3(0,   "height",     OPT_UINT,   &cmdlineP->height,
+            &cmdlineP->heightSpec,      0);
     OPTENT3(0,   "pad",        OPT_FLAG,   NULL, &cmdlineP->pad,           0);
     OPTENT3(0,   "verbose",    OPT_FLAG,   NULL, &cmdlineP->verbose,       0);
 
-    /* Set the defaults */
-    cmdlineP->left = UNSPEC;
-    cmdlineP->right = UNSPEC;
-    cmdlineP->top = UNSPEC;
-    cmdlineP->bottom = UNSPEC;
-    cmdlineP->width = UNSPEC;
-    cmdlineP->height = UNSPEC;
-
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = TRUE;  /* We may have parms that are negative numbers */
@@ -90,10 +126,10 @@ 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. */
 
-    if (cmdlineP->width < 0)
-        pm_error("-width may not be negative.");
-    if (cmdlineP->height < 0)
-        pm_error("-height may not be negative.");
+    if (cmdlineP->widthSpec && cmdlineP->width == 0)
+        pm_error("-width may not be zero.");
+    if (cmdlineP->heightSpec && cmdlineP->height == 0)
+        pm_error("-height may not be zero.");
 
     if ((argc-1) != 0 && (argc-1) != 1 && (argc-1) != 4 && (argc-1) != 5)
         pm_error("Wrong number of arguments: %u.  The only argument in "
@@ -104,170 +140,250 @@ parseCommandLine(int argc, const char ** const argv,
     switch (argc-1) {
     case 0:
         cmdlineP->inputFileName = "-";
+        haveLegacyLocationArgs = false;
         break;
     case 1:
         cmdlineP->inputFileName = argv[1];
+        haveLegacyLocationArgs = false;
         break;
     case 4:
-    case 5: {
-        int warg, harg;  /* The "width" and "height" command line arguments */
+        cmdlineP->inputFileName = "-";
+        haveLegacyLocationArgs = true;
+        break;
+    case 5:
+        cmdlineP->inputFileName = argv[5];
+        haveLegacyLocationArgs = true;
+        break;
+    }
 
-        if (sscanf(argv[1], "%d", &cmdlineP->left) != 1)
+    if (haveLegacyLocationArgs) {
+        int leftArg, topArg, widthArg, heightArg;
+
+        if (sscanf(argv[1], "%d", &leftArg) != 1)
             pm_error("Invalid number for left column argument");
-        if (sscanf(argv[2], "%d", &cmdlineP->top) != 1)
+        if (sscanf(argv[2], "%d", &topArg) != 1)
             pm_error("Invalid number for right column argument");
-        if (sscanf(argv[3], "%d", &warg) != 1)
+        if (sscanf(argv[3], "%d", &widthArg) != 1)
             pm_error("Invalid number for width argument");
-        if (sscanf(argv[4], "%d", &harg) != 1)
+        if (sscanf(argv[4], "%d", &heightArg) != 1)
             pm_error("Invalid number for height argument");
 
-        if (warg > 0) {
-            cmdlineP->width = warg;
-            cmdlineP->right = UNSPEC;
+        if (leftArg < 0) {
+            cmdlineP->leftLoc.locType = LOCTYPE_FROMFAR;
+            cmdlineP->leftLoc.n       = -leftArg;
         } else {
-            cmdlineP->width = UNSPEC;
-            cmdlineP->right = warg -1;
+            cmdlineP->leftLoc.locType = LOCTYPE_FROMNEAR;
+            cmdlineP->leftLoc.n       = leftArg;
         }
-        if (harg > 0) {
-            cmdlineP->height = harg;
-            cmdlineP->bottom = UNSPEC;
+        if (topArg < 0) {
+            cmdlineP->topLoc.locType = LOCTYPE_FROMFAR;
+            cmdlineP->topLoc.n       = -topArg;
         } else {
-            cmdlineP->height = UNSPEC;
-            cmdlineP->bottom = harg - 1;
+            cmdlineP->topLoc.locType = LOCTYPE_FROMNEAR;
+            cmdlineP->topLoc.n       = topArg;
         }
-
-        if (argc-1 == 4)
-            cmdlineP->inputFileName = "-";
-        else
-            cmdlineP->inputFileName = argv[5];
-        break;
-    }
+        if (widthArg > 0) {
+            cmdlineP->width = widthArg;
+            cmdlineP->widthSpec = 1;
+            cmdlineP->rghtLoc.locType = LOCTYPE_NONE;
+        } else {
+            cmdlineP->widthSpec = 0;
+            cmdlineP->rghtLoc.locType = LOCTYPE_FROMFAR;
+            cmdlineP->rghtLoc.n = -(widthArg - 1);
+        }
+        if (heightArg > 0) {
+            cmdlineP->height = heightArg;
+            cmdlineP->heightSpec = 1;
+            cmdlineP->botLoc.locType = LOCTYPE_NONE;
+        } else {
+            cmdlineP->heightSpec = 0;
+            cmdlineP->botLoc.locType = LOCTYPE_FROMFAR;
+            cmdlineP->botLoc.n = -(heightArg - 1);
+        }
+    } else {
+        if (leftSpec && cropleftSpec)
+            pm_error("You cannot specify both -left and -cropleft");
+        if (leftSpec) {
+            if (left >= 0) {
+                cmdlineP->leftLoc.locType = LOCTYPE_FROMNEAR;
+                cmdlineP->leftLoc.n       = left;
+            } else {
+                cmdlineP->leftLoc.locType = LOCTYPE_FROMFAR;
+                cmdlineP->leftLoc.n       = -left;
+            }
+        } else if (cropleftSpec) {
+            cmdlineP->leftLoc.locType = LOCTYPE_FROMNEAR;
+            cmdlineP->leftLoc.n       = cropleft;
+        } else
+            cmdlineP->leftLoc.locType = LOCTYPE_NONE;
+
+        if (rightSpec && croprightSpec)
+            pm_error("You cannot specify both -right and -cropright");
+        if (rightSpec) {
+            if (right >= 0) {
+                cmdlineP->rghtLoc.locType = LOCTYPE_FROMNEAR;
+                cmdlineP->rghtLoc.n       = right;
+            } else {
+                cmdlineP->rghtLoc.locType = LOCTYPE_FROMFAR;
+                cmdlineP->rghtLoc.n       = -right;
+            }
+        } else if (croprightSpec) {
+            cmdlineP->rghtLoc.locType = LOCTYPE_FROMFAR;
+            cmdlineP->rghtLoc.n       = 1 + cropright;
+        } else
+            cmdlineP->rghtLoc.locType = LOCTYPE_NONE;
+
+        if (topSpec && croptopSpec)
+            pm_error("You cannot specify both -top and -croptop");
+        if (topSpec) {
+            if (top >= 0) {
+                cmdlineP->topLoc.locType = LOCTYPE_FROMNEAR;
+                cmdlineP->topLoc.n       = top;
+            } else {
+                cmdlineP->topLoc.locType = LOCTYPE_FROMFAR;
+                cmdlineP->topLoc.n       = -top;
+            }
+        } else if (croptopSpec) {
+            cmdlineP->topLoc.locType = LOCTYPE_FROMNEAR;
+            cmdlineP->topLoc.n       = croptop;
+        } else
+            cmdlineP->topLoc.locType = LOCTYPE_NONE;
+
+        if (bottomSpec && cropbottomSpec)
+            pm_error("You cannot specify both -bottom and -cropbottom");
+        if (bottomSpec) {
+            if (bottom >= 0) {
+                cmdlineP->botLoc.locType = LOCTYPE_FROMNEAR;
+                cmdlineP->botLoc.n       = bottom;
+            } else {
+                cmdlineP->botLoc.locType = LOCTYPE_FROMFAR;
+                cmdlineP->botLoc.n       = -bottom;
+            }
+        } else if (cropbottomSpec) {
+            cmdlineP->botLoc.locType = LOCTYPE_FROMFAR;
+            cmdlineP->botLoc.n       = 1 + cropbottom;
+        } else
+            cmdlineP->botLoc.locType = LOCTYPE_NONE;
     }
 }
 
 
+static int
+near(Location     const loc,
+     unsigned int const edge) {
 
-static void
-computeCutBounds(const int cols, const int rows,
-                 const int leftarg, const int rightarg, 
-                 const int toparg, const int bottomarg,
-                 const int widtharg, const int heightarg,
-                 int * const leftcolP, int * const rightcolP,
-                 int * const toprowP, int * const bottomrowP) {
-/*----------------------------------------------------------------------------
-   From the values given on the command line 'leftarg', 'rightarg',
-   'toparg', 'bottomarg', 'widtharg', and 'heightarg', determine what
-   rectangle the user wants cut out.
-
-   Any of these arguments may be UNSPEC to indicate "not specified".
-   Any except 'widtharg' and 'heightarg' may be negative to indicate
-   relative to the far edge.  'widtharg' and 'heightarg' are positive.
+    int retval;
 
-   Return the location of the rectangle as *leftcolP, *rightcolP,
-   *toprowP, and *bottomrowP.  
------------------------------------------------------------------------------*/
-
-    int leftcol, rightcol, toprow, bottomrow;
-        /* The left and right column numbers and top and bottom row numbers
-           specified by the user, except with negative values translated
-           into the actual values.
+    switch (loc.locType) {
+    case LOCTYPE_NONE:
+        assert(false);
+        retval = 0;
+        break;
+    case LOCTYPE_FROMNEAR:
+        retval = loc.n;
+        break;
+    case LOCTYPE_FROMFAR:
+        retval = (int)edge - (int)loc.n;
+    }
 
-           Note that these may very well be negative themselves, such
-           as when the user says "column -10" and there are only 5 columns
-           in the image.
-           */
+    return retval;
+}
 
-    /* Translate negative column and row into real column and row */
-    /* Exploit the fact that UNSPEC is a positive number */
 
-    if (leftarg >= 0)
-        leftcol = leftarg;
-    else
-        leftcol = cols + leftarg;
-    if (rightarg >= 0)
-        rightcol = rightarg;
-    else
-        rightcol = cols + rightarg;
-    if (toparg >= 0)
-        toprow = toparg;
-    else
-        toprow = rows + toparg;
-    if (bottomarg >= 0)
-        bottomrow = bottomarg;
-    else
-        bottomrow = rows + bottomarg;
 
-    /* Sort out left, right, and width specifications */
+static void
+computeCutBounds(unsigned int const cols,
+                 unsigned int const rows,
+                 Location     const leftArg,
+                 Location     const rghtArg,
+                 Location     const topArg,
+                 Location     const botArg,
+                 bool         const widthSpec,
+                 unsigned int const widthArg,
+                 bool         const heightSpec,
+                 unsigned int const heightArg,
+                 int *        const leftColP,
+                 int *        const rghtColP,
+                 int *        const topRowP,
+                 int *        const botRowP) {
+/*----------------------------------------------------------------------------
+   From the values given on the command line 'leftArg', 'rghtArg', 'topArg',
+   'botArg', 'widthArg', and 'heightArg', determine what rectangle the user
+   wants cut out.
 
-    if (leftcol == UNSPEC && rightcol == UNSPEC && widtharg == UNSPEC) {
-        *leftcolP = 0;
-        *rightcolP = cols - 1;
-    }
-    if (leftcol == UNSPEC && rightcol == UNSPEC && widtharg != UNSPEC) {
-        *leftcolP = 0;
-        *rightcolP = 0 + widtharg - 1;
-    }
-    if (leftcol == UNSPEC && rightcol != UNSPEC && widtharg == UNSPEC) {
-        *leftcolP = 0;
-        *rightcolP = rightcol;
-    }
-    if (leftcol == UNSPEC && rightcol != UNSPEC && widtharg != UNSPEC) {
-        *leftcolP = rightcol - widtharg + 1;
-        *rightcolP = rightcol;
-    }
-    if (leftcol != UNSPEC && rightcol == UNSPEC && widtharg == UNSPEC) {
-        *leftcolP = leftcol;
-        *rightcolP = cols - 1;
-    }
-    if (leftcol != UNSPEC && rightcol == UNSPEC && widtharg != UNSPEC) {
-        *leftcolP = leftcol;
-        *rightcolP = leftcol + widtharg - 1;
-    }
-    if (leftcol != UNSPEC && rightcol != UNSPEC && widtharg == UNSPEC) {
-        *leftcolP = leftcol;
-        *rightcolP = rightcol;
-    }
-    if (leftcol != UNSPEC && rightcol != UNSPEC && widtharg != UNSPEC) {
-        pm_error("You may not specify left, right, and width.\n"
-                 "Choose at most two of these.");
+   Return the location of the rectangle as *leftcolP, *rghtcolP, *toprowP, and
+   *botrowP.  Any of these can be outside the image, including by being
+   negative.
+-----------------------------------------------------------------------------*/
+    /* Find left and right bounds */
+
+    if (widthSpec)
+        assert(widthArg > 0);
+
+    if (leftArg.locType == LOCTYPE_NONE) {
+        if (rghtArg.locType == LOCTYPE_NONE) {
+            *leftColP = 0;
+            if (widthSpec)
+                *rghtColP = 0 + (int)widthArg - 1;
+            else
+                *rghtColP = (int)cols - 1;
+        } else {
+            *rghtColP = near(rghtArg, cols);
+            if (widthSpec)
+                *leftColP = near(rghtArg, cols) - (int)widthArg + 1;
+            else
+                *leftColP = 0;
+        }
+    } else {
+        *leftColP = near(leftArg, cols);
+        if (rghtArg.locType == LOCTYPE_NONE) {
+            if (widthSpec)
+                *rghtColP = near(leftArg, cols) + (int)widthArg - 1;
+            else
+                *rghtColP = (int)cols - 1;
+        } else {
+            if (widthSpec) {
+                pm_error("You may not specify left, right, and width.  "
+                         "Choose at most two of these.");
+            } else
+                *rghtColP = near(rghtArg, cols);
+        }
     }
 
+    /* Find top and bottom bounds */
 
-    /* Sort out top, bottom, and height specifications */
+    if (heightSpec)
+        assert(heightArg > 0);
 
-    if (toprow == UNSPEC && bottomrow == UNSPEC && heightarg == UNSPEC) {
-        *toprowP = 0;
-        *bottomrowP = rows - 1;
-    }
-    if (toprow == UNSPEC && bottomrow == UNSPEC && heightarg != UNSPEC) {
-        *toprowP = 0;
-        *bottomrowP = 0 + heightarg - 1;
-    }
-    if (toprow == UNSPEC && bottomrow != UNSPEC && heightarg == UNSPEC) {
-        *toprowP = 0;
-        *bottomrowP = bottomrow;
-    }
-    if (toprow == UNSPEC && bottomrow != UNSPEC && heightarg != UNSPEC) {
-        *toprowP = bottomrow - heightarg + 1;
-        *bottomrowP = bottomrow;
-    }
-    if (toprow != UNSPEC && bottomrow == UNSPEC && heightarg == UNSPEC) {
-        *toprowP = toprow;
-        *bottomrowP = rows - 1;
-    }
-    if (toprow != UNSPEC && bottomrow == UNSPEC && heightarg != UNSPEC) {
-        *toprowP = toprow;
-        *bottomrowP = toprow + heightarg - 1;
-    }
-    if (toprow != UNSPEC && bottomrow != UNSPEC && heightarg == UNSPEC) {
-        *toprowP = toprow;
-        *bottomrowP = bottomrow;
-    }
-    if (toprow != UNSPEC && bottomrow != UNSPEC && heightarg != UNSPEC) {
-        pm_error("You may not specify top, bottom, and height.\n"
-                 "Choose at most two of these.");
+    if (topArg.locType == LOCTYPE_NONE) {
+        if (botArg.locType == LOCTYPE_NONE) {
+            *topRowP = 0;
+            if (heightSpec)
+                *botRowP = 0 + (int)heightArg - 1;
+            else
+                *botRowP = (int)rows - 1;
+        } else {
+            *botRowP = near(botArg, rows);
+            if (heightSpec)
+                *topRowP = near(botArg, rows) - (int)heightArg + 1;
+            else
+                *topRowP = 0;
+        }
+    } else {
+        *topRowP = near(topArg, rows);
+        if (botArg.locType == LOCTYPE_NONE) {
+            if (heightSpec)
+                *botRowP = near(topArg, rows) + (int)heightArg - 1;
+            else
+                *botRowP = (int)rows - 1;
+        } else {
+            if (heightSpec) {
+                pm_error("You may not specify top, bottom, and height.  "
+                         "Choose at most two of these.");
+            } else
+                *botRowP = near(botArg, rows);
+        }
     }
-
 }
 
 
@@ -324,7 +440,7 @@ rejectOutOfBounds(unsigned int const cols,
 
 
 static void
-writeBlackRows(const struct pam * const outpamP, 
+writeBlackRows(const struct pam * const outpamP,
                int                const rows) {
 /*----------------------------------------------------------------------------
    Write out 'rows' rows of black tuples of the image described by *outpamP.
@@ -336,11 +452,11 @@ writeBlackRows(const struct pam * const outpamP,
     tuple blackTuple;
     tuple * blackRow;
     int col;
-    
+
     pnm_createBlackTuple(outpamP, &blackTuple);
 
     MALLOCARRAY_NOFAIL(blackRow, outpamP->width);
-    
+
     for (col = 0; col < outpamP->width; ++col)
         blackRow[col] = blackTuple;
 
@@ -360,14 +476,14 @@ struct rowCutter {
    pnm_readpamrow() and one pnm_writepamrow().  It works like this:
 
    The array inputPointers[] contains an element for each pixel in an input
-   row.  If it's a pixel that gets discarded in the cutting process, 
+   row.  If it's a pixel that gets discarded in the cutting process,
    inputPointers[] points to a special "discard" tuple.  All thrown away
    pixels have the same discard tuple to save CPU cache space.  If it's
    a pixel that gets copied to the output, inputPointers[] points to some
    tuple to which outputPointers[] also points.
 
    The array outputPointers[] contains an element for each pixel in an
-   output row.  If the pixel is one that gets copied from the input, 
+   output row.  If the pixel is one that gets copied from the input,
    outputPointers[] points to some tuple to which inputPointers[] also
    points.  If it's a pixel that gets padded with black, outputPointers[]
    points to a constant black tuple.  All padded pixels have the same
@@ -489,7 +605,7 @@ destroyRowCutter(struct rowCutter * const rowCutterP) {
     pnm_freepamtuple(rowCutterP->discardTuple);
     free(rowCutterP->inputPointers);
     free(rowCutterP->outputPointers);
-    
+
     free(rowCutterP);
 }
 
@@ -519,7 +635,7 @@ extractRowsGen(const struct pam * const inpamP,
             pnm_writepamrow(outpamP, rowCutterP->outputPointers);
         } else  /* row < toprow || row > bottomrow */
             pnm_readpamrow(inpamP, NULL);
-        
+
         /* Note that we may be tempted just to quit after reaching the bottom
            of the extracted image, but that would cause a broken pipe problem
            for the process that's feeding us the image.
@@ -527,7 +643,7 @@ extractRowsGen(const struct pam * const inpamP,
     }
 
     destroyRowCutter(rowCutterP);
-    
+
     /* Write out bottom padding */
     if ((bottomrow - (inpamP->height-1)) > 0)
         writeBlackRows(outpamP, bottomrow - (inpamP->height-1));
@@ -574,7 +690,7 @@ extractRowsPBM(const struct pam * const inpamP,
             /* Prevent overflows in pbm_allocrow_packed() */
             pm_error("Specified right edge is too far "
                      "from the right end of input image");
-        
+
         readOffset  = 0;
         writeOffset = leftcol;
     } else {
@@ -582,7 +698,7 @@ extractRowsPBM(const struct pam * const inpamP,
         if (totalWidth > INT_MAX)
             pm_error("Specified left/right edge is too far "
                      "from the left/right end of input image");
-        
+
         readOffset = -leftcol;
         writeOffset = 0;
     }
@@ -606,7 +722,7 @@ extractRowsPBM(const struct pam * const inpamP,
 
             pbm_writepbmrow_bitoffset(outpamP->file, bitrow, outpamP->width,
                                       0, writeOffset);
-  
+
             if (rightcol >= inpamP->width)
                 /* repair right padding */
                 bitrow[writeOffset/8 + pbm_packed_bytes(outpamP->width) - 1] =
@@ -632,18 +748,20 @@ cutOneImage(FILE *             const ifP,
             FILE *             const ofP) {
 
     int leftcol, rightcol, toprow, bottomrow;
+        /* Could be out of bounds, even negative */
     struct pam inpam;   /* Input PAM image */
     struct pam outpam;  /* Output PAM image */
 
     pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
-    
-    computeCutBounds(inpam.width, inpam.height, 
-                     cmdline.left, cmdline.right, 
-                     cmdline.top, cmdline.bottom, 
-                     cmdline.width, cmdline.height, 
+
+    computeCutBounds(inpam.width, inpam.height,
+                     cmdline.leftLoc, cmdline.rghtLoc,
+                     cmdline.topLoc, cmdline.botLoc,
+                     cmdline.widthSpec, cmdline.width,
+                     cmdline.heightSpec, cmdline.height,
                      &leftcol, &rightcol, &toprow, &bottomrow);
 
-    rejectOutOfBounds(inpam.width, inpam.height, leftcol, rightcol, 
+    rejectOutOfBounds(inpam.width, inpam.height, leftcol, rightcol,
                       toprow, bottomrow, cmdline.pad);
 
     if (cmdline.verbose) {
@@ -691,6 +809,6 @@ main(int argc, const char *argv[]) {
 
     pm_close(ifP);
     pm_close(ofP);
-    
+
     return 0;
 }
diff --git a/editor/pammixmulti.c b/editor/pammixmulti.c
new file mode 100644
index 00000000..d063d96c
--- /dev/null
+++ b/editor/pammixmulti.c
@@ -0,0 +1,543 @@
+/*************************************************
+ * Blend multiple Netpbm files into a single one *
+ *                                               *
+ * By Scott Pakin <scott+pbm@pakin.org>          *
+ *************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <float.h>
+#include <math.h>
+#include "pam.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "nstring.h"
+
+typedef enum {
+    BLEND_AVERAGE,   /* Take the average color of all pixels */
+    BLEND_RANDOM,    /* Take each pixel color from a randomly selected image */
+    BLEND_MASK   /* Take each pixel color from the image indicated by a mask */
+} BlendType;
+
+static unsigned int const randSamples = 1024;
+    /* Random samples to draw per file */
+
+struct ProgramState {
+    unsigned int     inFileCt;      /* Number of input files */
+    struct pam *     inPam;         /* List of input-file PAM structures */
+    tuple **         inTupleRows;   /* Current row from each input file */
+    struct pam       outPam;        /* Output-file PAM structure */
+    tuple *          outTupleRow;   /* Row to write to the output file */
+    const char *     maskFileName;  /* Name of the image-mask file */
+    struct pam       maskPam;       /* PAM structure for the image mask */
+    tuple *          maskTupleRow;  /* Row to read from the mask file */
+    double           sigma;
+        /* Standard deviation when selecting images via a mask */
+    unsigned long ** imageWeights;
+        /* Per-image weights as a function of grayscale level */
+};
+
+
+
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    BlendType        blend;
+    const char *     maskfile;
+    float            stdev;
+    unsigned int     randomseed;
+    unsigned int     randomseedSpec;
+    unsigned int     inFileNameCt;  /* Number of input files */
+    const char **    inFileName;    /* Name of each input file */
+};
+
+
+
+static void
+freeCmdline(struct CmdlineInfo * const cmdlineP) {
+
+    free(cmdlineP->inFileName);
+}
+
+
+
+static void
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo * const cmdlineP) {
+
+    optStruct3 opt;
+    unsigned int option_def_index = 0;
+    optEntry * option_def;
+    unsigned int blendSpec, maskfileSpec, stdevSpec;
+    const char * blendOpt;
+
+    /* Define the allowed command-line options. */
+    MALLOCARRAY(option_def, 100);
+    OPTENT3(0, "blend",     OPT_STRING,     &blendOpt,
+            &blendSpec,     0);
+    OPTENT3(0, "maskfile",  OPT_STRING,     &cmdlineP->maskfile,
+            &maskfileSpec,  0);
+    OPTENT3(0, "stdev",      OPT_FLOAT,     &cmdlineP->stdev,
+            &stdevSpec,     0);
+    OPTENT3(0, "randomseed", OPT_UINT,      &cmdlineP->randomseed,
+            &cmdlineP->randomseedSpec,     0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = 0;
+    opt.allowNegNum = 0;
+
+    pm_optParseOptions3(&argc, (char **) argv, opt, sizeof(opt), 0);
+    if (blendSpec) {
+        if (streq(blendOpt, "average"))
+            cmdlineP->blend = BLEND_AVERAGE;
+        else if (streq(blendOpt, "random"))
+            cmdlineP->blend = BLEND_RANDOM;
+        else if (streq(blendOpt, "mask"))
+            cmdlineP->blend = BLEND_MASK;
+        else
+            pm_error("Unrecognized -blend value '%s'.  "
+                     "We recognize 'average', 'random', and 'mask'", blendOpt);
+    } else
+        cmdlineP->blend = BLEND_AVERAGE;
+
+    if (cmdlineP->blend == BLEND_MASK) {
+        if (!maskfileSpec)
+            pm_error("Because you specified -blend=mask, "
+                     "you must also specify -maskfile");
+    } else {
+        if (maskfileSpec)
+            pm_message("Ignoring -maskfile because -blend=mask "
+                       "is not specified");
+        if (stdevSpec)
+            pm_message("Ignoring -stdev because -blend=mask "
+                       "is not specified");
+    }
+    if (!stdevSpec)
+        cmdlineP->stdev = 0.25;
+
+    if (argc-1 < 1)
+        pm_error("You must specify the names of the files to blend together "
+                 "as arguments");
+
+    cmdlineP->inFileNameCt = argc-1;
+    MALLOCARRAY(cmdlineP->inFileName, argc-1);
+    if (!cmdlineP->inFileName)
+        pm_error("Unable to allocate space for %u file names", argc-1);
+    {
+        unsigned int i;
+        for (i = 0; i < argc-1; ++i)
+            cmdlineP->inFileName[i] = argv[1+i];
+    }
+    free(option_def);
+}
+
+static void
+openInputFiles(unsigned int          const inFileCt,
+               const char **         const inFileName,
+               struct ProgramState * const stateP) {
+/*----------------------------------------------------------------------------
+  Open all of the input files.
+
+  Abort if the input files don't all have the same size and format.
+-----------------------------------------------------------------------------*/
+    struct pam * inPam;
+    unsigned int i;
+
+    MALLOCARRAY(inPam, inFileCt);
+    if (!inPam)
+        pm_error("Failed to allocated memory for PAM structures for %u "
+                 "input files", inFileCt);
+    MALLOCARRAY(stateP->inTupleRows, inFileCt);
+    if (!stateP->inTupleRows)
+        pm_error("Failed to allocated memory for PAM structures for %u "
+                 "input rasters", inFileCt);
+
+    for (i = 0; i < inFileCt; ++i) {
+        FILE * const ifP = pm_openr(inFileName[i]);
+        pnm_readpaminit(ifP, &inPam[i], PAM_STRUCT_SIZE(tuple_type));
+        if (inPam[i].width != inPam[0].width ||
+            inPam[i].height != inPam[0].height)
+            pm_error("Input image %u has different dimensions from "
+                     "earlier input images", i);
+        if (inPam[i].depth != inPam[0].depth)
+            pm_error("Input image %u has different depth from "
+                     "earlier input images", i);
+        if (inPam[i].maxval != inPam[0].maxval)
+            pm_error("Input image %u has different maxval from "
+                     "earlier input images", i);
+        if (!streq(inPam[i].tuple_type, inPam[0].tuple_type))
+            pm_error("Input image %u has different tuple type from "
+                     "earlier input images", i);
+    }
+
+    for (i = 0; i < inFileCt; ++i)
+        stateP->inTupleRows[i] = pnm_allocpamrow(&inPam[i]);
+
+    stateP->inPam    = inPam;
+    stateP->inFileCt = inFileCt;
+}
+
+
+static void
+initMask(const char *          const maskFileName,
+         struct ProgramState * const stateP) {
+
+    struct pam * const maskPamP = &stateP->maskPam;
+
+    FILE * const mfP = pm_openr(maskFileName);
+
+    pnm_readpaminit(mfP, maskPamP, PAM_STRUCT_SIZE(tuple_type));
+
+    if (maskPamP->width != stateP->inPam[0].width ||
+        maskPamP->height != stateP->inPam[0].height) {
+
+        pm_error("The mask image does not have have the same dimensions "
+                 "as the input images");
+    }
+    if (maskPamP->depth > 1)
+        pm_message("Ignoring all but the first channel of the mask image");
+
+    stateP->maskTupleRow = pnm_allocpamrow(maskPamP);
+}
+
+
+
+static void
+termMask(struct ProgramState * const stateP) {
+
+    unsigned int i;
+
+    for (i = 0; i <= stateP->maskPam.maxval; ++i)
+        free(stateP->imageWeights[i]);
+
+    free(stateP->imageWeights);
+
+    pnm_freepamrow(stateP->maskTupleRow);
+
+    pm_close(stateP->maskPam.file);
+}
+
+
+
+static void
+initOutput(FILE *                const ofP,
+           struct ProgramState * const stateP) {
+
+    stateP->outPam      = stateP->inPam[0];
+    stateP->outPam.file = ofP;
+    stateP->outTupleRow = pnm_allocpamrow(&stateP->outPam);
+
+    pnm_writepaminit(&stateP->outPam);
+}
+
+
+
+static void
+blendTuplesRandom(struct ProgramState * const stateP,
+                  unsigned int          const col,
+                  sample *              const outSamps) {
+/*----------------------------------------------------------------------------
+  Blend one tuple of the input images into a new tuple by selecting a tuple
+  from a random input image.
+-----------------------------------------------------------------------------*/
+    unsigned int const depth = stateP->inPam[0].depth;
+    unsigned int const img = (unsigned int) (random() % stateP->inFileCt);
+
+    unsigned int samp;
+
+    for (samp = 0; samp < depth; ++samp)
+        outSamps[samp] = ((sample *)stateP->inTupleRows[img][col])[samp];
+}
+
+
+
+static void
+blendTuplesAverage(struct ProgramState * const stateP,
+                   unsigned int          const col,
+                   sample *              const outSamps) {
+/*----------------------------------------------------------------------------
+  Blend one tuple of the input images into a new tuple by averaging all input
+  tuples.
+-----------------------------------------------------------------------------*/
+    unsigned int const depth = stateP->inPam[0].depth;
+
+    unsigned int samp;
+
+    for (samp = 0; samp < depth; ++samp) {
+        unsigned int img;
+
+        for (img = 0, outSamps[samp] = 0; img < stateP->inFileCt; ++img)
+            outSamps[samp] += ((sample *)stateP->inTupleRows[img][col])[samp];
+        outSamps[samp] /= stateP->inFileCt;
+    }
+}
+
+
+
+static void
+randomNormal2(double * const r1P,
+              double * const r2P) {
+/*----------------------------------------------------------------------------
+  Return two normally distributed random numbers.
+-----------------------------------------------------------------------------*/
+    double u1, u2;
+
+    do {
+        u1 = drand48();
+        u2 = drand48();
+    }
+    while (u1 <= DBL_EPSILON);
+
+    *r1P = sqrt(-2.0*log(u1)) * cos(2.0*M_PI*u2);
+    *r2P = sqrt(-2.0*log(u1)) * sin(2.0*M_PI*u2);
+}
+
+
+
+static void
+precomputeImageWeights(struct ProgramState * const stateP,
+                       double                const sigma) {
+/*----------------------------------------------------------------------------
+  Precompute the weight to give to each image as a function of grayscale
+  level.
+-----------------------------------------------------------------------------*/
+    unsigned int const maxGray = (unsigned int) stateP->maskPam.maxval;
+
+    unsigned int i;
+
+    MALLOCARRAY(stateP->imageWeights, maxGray + 1);
+    if (!stateP->imageWeights)
+        pm_error("Unable to allocate memory for image weights for %u "
+                 "gray levels", maxGray);
+
+    for (i = 0; i <= maxGray; ++i) {
+        unsigned int j;
+        MALLOCARRAY(stateP->imageWeights[i], stateP->inFileCt);
+        if (!stateP->imageWeights[i])
+            pm_error("Unable to allocate memory for image weights for %u "
+                     "images for gray level %u", stateP->inFileCt, i);
+        for (j = 0; j < stateP->inFileCt; ++j)
+            stateP->imageWeights[i][j] = 0;
+    }
+
+    /* Populate the image-weight arrays. */
+    for (i = 0; i <= maxGray; ++i) {
+        double const pctGray = i / (double)maxGray;
+
+        unsigned int j;
+
+        for (j = 0; j < stateP->inFileCt * randSamples; ) {
+            double r[2];
+            unsigned int k;
+
+            randomNormal2(&r[0], &r[1]);
+            for (k = 0; k < 2; ++k) {
+                int const img =
+                    r[k] * sigma + pctGray * stateP->inFileCt * 0.999999;
+                    /* Scale [0, 1] to [0, 1) (sort of). */
+                if (img >= 0 && img < (int)stateP->inFileCt) {
+                    ++stateP->imageWeights[i][img];
+                    ++j;
+                }
+            }
+        }
+    }
+}
+
+
+
+static void
+blendTuplesMask(struct ProgramState * const stateP,
+                unsigned int          const col,
+                sample *              const outSamps) {
+/*----------------------------------------------------------------------------
+  Blend one tuple of the input images into a new tuple according to the gray
+  levels specified in a mask file.
+-----------------------------------------------------------------------------*/
+    unsigned int const depth = stateP->inPam[0].depth;
+    sample const grayLevel = ((sample *)stateP->maskTupleRow[col])[0];
+
+    unsigned int img;
+
+    /* Initialize outSamps[] to zeroes */
+    {
+        unsigned int samp;
+
+        for (samp = 0; samp < depth; ++samp)
+            outSamps[samp] = 0;
+    }
+
+    /* Accumulate to outSamps[] */
+    for (img = 0; img < stateP->inFileCt; ++img) {
+        unsigned long weight = stateP->imageWeights[grayLevel][img];
+
+        if (weight != 0) {
+            unsigned int samp;
+
+            for (samp = 0; samp < depth; ++samp)
+                outSamps[samp] +=
+                    ((sample *)stateP->inTupleRows[img][col])[samp] * weight;
+        }
+    }
+    /* Scale all outSamps[] */
+    {
+        unsigned int samp;
+
+        for (samp = 0; samp < depth; ++samp)
+            outSamps[samp] /= randSamples * stateP->inFileCt;
+    }
+}
+
+
+
+static void
+blendImageRow(BlendType             const blend,
+              struct ProgramState * const stateP) {
+/*----------------------------------------------------------------------------
+  Blend one row of input images into a new row.
+-----------------------------------------------------------------------------*/
+    unsigned int const width = stateP->inPam[0].width;
+
+    unsigned int col;
+
+    for (col = 0; col < width; ++col) {
+        sample * const outSamps = stateP->outTupleRow[col];
+
+        switch (blend) {
+        case BLEND_RANDOM:
+            /* Take each pixel from a different, randomly selected image. */
+            blendTuplesRandom(stateP, col, outSamps);
+            break;
+
+        case BLEND_AVERAGE:
+            /* Average each sample across all the images. */
+            blendTuplesAverage(stateP, col, outSamps);
+            break;
+
+        case BLEND_MASK:
+            /* Take each pixel from the image specified by the mask image. */
+            blendTuplesMask(stateP, col, outSamps);
+            break;
+        }
+    }
+}
+
+
+
+static void
+blendImages(BlendType             const blend,
+            struct ProgramState * const stateP) {
+/*----------------------------------------------------------------------------
+  Blend the images row-by-row into a new image.
+-----------------------------------------------------------------------------*/
+    unsigned int const nRows = stateP->inPam[0].height;
+
+    unsigned int row;
+
+    for (row = 0; row < nRows; ++row) {
+        unsigned int img;
+
+        for (img = 0; img < stateP->inFileCt; ++img)
+            pnm_readpamrow(&stateP->inPam[img], stateP->inTupleRows[img]);
+
+        if (blend == BLEND_MASK)
+            pnm_readpamrow(&stateP->maskPam, stateP->maskTupleRow);
+
+        blendImageRow(blend, stateP);
+
+        pnm_writepamrow(&stateP->outPam, stateP->outTupleRow);
+    }
+}
+
+
+
+static void
+termState(struct ProgramState * const stateP) {
+/*----------------------------------------------------------------------------
+  Deallocate all of the resources we allocated.
+-----------------------------------------------------------------------------*/
+    unsigned int i;
+
+    for (i = 0; i < stateP->inFileCt; ++i) {
+        pnm_freepamrow(stateP->inTupleRows[i]);
+        pm_close(stateP->inPam[i].file);
+    }
+
+    free(stateP->outTupleRow);
+    free(stateP->inTupleRows);
+    free(stateP->inPam);
+    pm_close(stateP->outPam.file);
+}
+
+
+
+int
+main(int argc, const char * argv[]) {
+
+    struct CmdlineInfo cmdline;
+    struct ProgramState state;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    srand(cmdline.randomseedSpec ? cmdline.randomseed : pm_randseed());
+
+    openInputFiles(cmdline.inFileNameCt, cmdline.inFileName, &state);
+
+    if (cmdline.blend == BLEND_MASK)
+        initMask(cmdline.maskfile, &state);
+
+    initOutput(stdout, &state);
+
+    if (cmdline.blend == BLEND_MASK)
+        precomputeImageWeights(&state, cmdline.stdev);
+
+    blendImages(cmdline.blend, &state);
+
+    if (cmdline.blend == BLEND_MASK)
+        termMask(&state);
+
+    termState(&state);
+
+    freeCmdline(&cmdline);
+
+    return 0;
+}
+
+
+/*  COPYRIGHT LICENSE and WARRANTY DISCLAIMER
+
+Copyright (c) 2018 Scott Pakin
+All rights reserved
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted (subject to the limitations in the disclaimer
+below) provided that the following conditions are met:
+
+  Redistributions of source code must retain the above copyright notice,
+  this list of conditions and the following disclaimer.
+
+  Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+  Neither the names of the oopyright owners nor the names of its contributors
+  may be used to endorse or promote products derived from this software
+  without specific prior written permission.
+
+  NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
+  THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
+  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
diff --git a/editor/pnmconvol.c b/editor/pnmconvol.c
index 98ec3a6b..b1d8e025 100644
--- a/editor/pnmconvol.c
+++ b/editor/pnmconvol.c
@@ -733,7 +733,7 @@ parsePlaneFileLine(const char *   const line,
                          "-matrix value is not a valid floating point "
                          "number", colCt, line);
 
-                ++colCt;
+            ++colCt;
         }
         pm_strfree(token);
     }
diff --git a/editor/pnmhisteq.c b/editor/pnmhisteq.c
index 8af42019..76fd6d2a 100644
--- a/editor/pnmhisteq.c
+++ b/editor/pnmhisteq.c
@@ -51,9 +51,9 @@ parseCommandLine(int argc, char ** argv,
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0, "rmap",     OPT_STRING, &cmdlineP->rmap, 
+    OPTENT3(0, "rmap",     OPT_STRING, &cmdlineP->rmap,
             &rmapSpec,          0);
-    OPTENT3(0, "wmap",     OPT_STRING, &cmdlineP->wmap, 
+    OPTENT3(0, "wmap",     OPT_STRING, &cmdlineP->wmap,
             &wmapSpec,          0);
     OPTENT3(0, "gray",     OPT_FLAG,   NULL,
             &cmdlineP->gray,    0);
@@ -175,27 +175,27 @@ readMapFile(const char * const rmapFileName,
             xelval       const maxval,
             gray *       const lumamap) {
 
-    int rmcols, rmrows; 
+    int rmcols, rmrows;
     gray rmmaxv;
     int rmformat;
     FILE * rmapfP;
-        
+
     rmapfP = pm_openr(rmapFileName);
     pgm_readpgminit(rmapfP, &rmcols, &rmrows, &rmmaxv, &rmformat);
-    
+
     if (rmmaxv != maxval)
         pm_error("maxval in map file (%u) different from input (%u)",
                  rmmaxv, maxval);
-    
+
     if (rmrows != 1)
         pm_error("Map must have 1 row.  Yours has %u", rmrows);
-    
+
     if (rmcols != maxval + 1)
         pm_error("Map must have maxval + 1 (%u) columns.  Yours has %u",
                  maxval + 1, rmcols);
-    
+
     pgm_readpgmrow(rmapfP, lumamap, maxval+1, rmmaxv, rmformat);
-    
+
     pm_close(rmapfP);
 }
 
@@ -245,7 +245,7 @@ equalize(const unsigned int * const lumahist,
         maxLumaPresent(lumahist, darkestRemap, brightestRemap);
 
     unsigned int const range = brightestRemap - darkestRemap;
-    
+
     {
         xelval origLum;
         unsigned int pixsum;
@@ -253,7 +253,7 @@ equalize(const unsigned int * const lumahist,
         for (origLum = darkestRemap, pixsum = 0;
              origLum <= brightestRemap;
              ++origLum) {
-            
+
             /* With 16 bit grays, the following calculation can overflow a 32
                bit long.  So, we do it in floating point.
             */
@@ -261,7 +261,7 @@ equalize(const unsigned int * const lumahist,
             lumamap[origLum] =
                 darkestRemap +
                 ROUNDU((((double) pixsum * range)) / remapPixelCount);
-            
+
             pixsum += lumahist[origLum];
         }
 
@@ -277,7 +277,7 @@ equalize(const unsigned int * const lumahist,
 
         for (origLum = darkestRemap; origLum <= brightestRemap; ++origLum)
             lumamap[origLum] =
-                MIN(brightestRemap, 
+                MIN(brightestRemap,
                     darkestRemap + ROUNDU(lumamap[origLum] * lscale));
     }
 }
@@ -301,7 +301,7 @@ computeMap(const unsigned int * const lumahist,
 
   'pixelCount' is the number of pixels in the image, which is redundant
   with 'lumahist' but provided for computational convenience.
-   
+
   'noblack' means don't include the black pixels in the equalization and
   make the black pixels in the output the same ones as in the input.
 
@@ -407,7 +407,7 @@ scaleXel(xel    const thisXel,
                ((xelval)(PNM_GETR(thisXel) * scaler + 0.5)),
                ((xelval)(PNM_GETG(thisXel) * scaler + 0.5)),
                ((xelval)(PNM_GETB(thisXel) * scaler + 0.5)));
-    
+
     return retval;
 }
 
@@ -429,7 +429,7 @@ remapRgbValue(xel          const thisXel,
         MIN(maxval, ROUNDU(hsv.v * maxval));
     xelval const newValue =
         lumamap[oldValue];
-    
+
     return scaleXel(thisXel, (double)newValue/oldValue);
 }
 
diff --git a/editor/pnmpaste.c b/editor/pnmpaste.c
index c27e288c..3baaec7d 100644
--- a/editor/pnmpaste.c
+++ b/editor/pnmpaste.c
@@ -19,7 +19,7 @@
 #include "pnm.h"
 
 
-enum boolOp {REPLACE, AND, OR, XOR /*, NAND, NOR, NXOR */ };
+enum boolOp {REPLACE, AND, OR, XOR, NAND, NOR, NXOR};
 
 struct CmdlineInfo {
     /* All the information the user supplied in the command line,
@@ -47,7 +47,7 @@ parseCommandLine(int argc, const char ** argv,
     optStruct3 opt;
 
     unsigned int option_def_index;
-    unsigned int replaceOpt, andOpt, orOpt, xorOpt;
+    unsigned int replaceOpt, andOpt, orOpt, xorOpt, nandOpt, norOpt, nxorOpt;
 
     MALLOCARRAY_NOFAIL(option_def, 100);
 
@@ -60,6 +60,12 @@ parseCommandLine(int argc, const char ** argv,
             &orOpt,                0);
     OPTENT3(0,   "xor",         OPT_FLAG,    NULL,
             &xorOpt,               0);
+    OPTENT3(0,   "nand",        OPT_FLAG,    NULL,
+            &nandOpt,              0);
+    OPTENT3(0,   "nor",         OPT_FLAG,    NULL,
+            &norOpt,               0);
+    OPTENT3(0,   "nxor",        OPT_FLAG,    NULL,
+            &nxorOpt,              0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
@@ -68,16 +74,20 @@ parseCommandLine(int argc, const char ** argv,
     pm_optParseOptions3(&argc, (char **)argv, opt, sizeof opt, 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
-    if (replaceOpt + andOpt + orOpt + xorOpt > 1)
-        pm_error("You may specify only one of -replace, -and, -or, and -xor");
+    if (replaceOpt + andOpt + orOpt + xorOpt + nandOpt + norOpt + nxorOpt > 1)
+        pm_error("You may specify only one of -replace, -and, -or, "
+                 "-xor, -nand, -nor and -nxor");
 
     cmdlineP->operation =
         replaceOpt ? REPLACE :
         andOpt     ? AND     :
         orOpt      ? OR      :
         xorOpt     ? XOR     :
+        nandOpt    ? NAND    :
+        norOpt     ? NOR     :
+        nxorOpt    ? NXOR    :
         replaceOpt;
-        
+
 
     if (argc-1 >= 3) {
         cmdlineP->insetFilename = argv[1];
@@ -168,11 +178,9 @@ insertDirect(FILE *          const ifP,
             case AND: destrow[i] |= buffer[i]; break;
             case OR : destrow[i] &= buffer[i]; break;
             case XOR: destrow[i]  = ~( destrow[i] ^ buffer[i] ) ; break;
-            /*
             case NAND: destrow[i] = ~( destrow[i] | buffer[i] ) ; break;
             case NOR : destrow[i] = ~( destrow[i] & buffer[i] ) ; break;
             case NXOR: destrow[i] ^= buffer[i]  ; break;
-            */
             case REPLACE: assert(false); break;
             }
         }
@@ -229,11 +237,9 @@ insertShift(FILE *          const ifP,
         case AND:     destrow[i] |= t; break;
         case OR :     destrow[i] &= t; break;
         case XOR:     destrow[i] = ~ (destrow[i] ^ t); break;
-        /*
         case NAND:    destrow[i] = ~ (destrow[i] | t); break;
         case NOR :    destrow[i] = ~ (destrow[i] & t); break;
         case NXOR:    destrow[i] ^= t; break;
-        */
         }
     }
 
@@ -244,7 +250,7 @@ insertShift(FILE *          const ifP,
 
     destrow[0] = leftBits(origLeft, offset) |
         rightBits(destrow[0], 8-offset);
-   
+
     if (padOffset % 8 > 0)
         destrow[last] = leftBits(destrow[last], padOffset) |
             rightBits(origRight , 8-padOffset);
@@ -279,7 +285,7 @@ pastePbm(FILE *       const fpInset,
 
     for (row = 0; row < baseRows; ++row) {
         pbm_readpbmrow_packed(fpBase, baserow, baseCols, baseFormat);
-        
+
         if (row >= insertRow && row < insertRow + insetRows) {
             if (shiftOffset == 0)
                 insertDirect(fpInset, &baserow[shiftByteCt], insetCols,
@@ -316,7 +322,7 @@ pasteNonPbm(FILE *       const fpInset,
             unsigned int const insertCol,
             unsigned int const insertRow) {
 
-    /* Logic works for PBM, but cannot do bitwise operations */             
+    /* Logic works for PBM, but cannot do bitwise operations */
 
     xelval const newmaxval = MAX(maxvalInset, maxvalBase);
 
@@ -344,7 +350,7 @@ pasteNonPbm(FILE *       const fpInset,
         }
         pnm_writepnmrow(stdout, xelrowBase, colsBase, newmaxval, newformat, 0);
     }
-    
+
     pnm_freerow(xelrowBase);
     pnm_freerow(xelrowInset);
 }
diff --git a/editor/specialty/Makefile b/editor/specialty/Makefile
index 427c2c8f..8d9ca044 100644
--- a/editor/specialty/Makefile
+++ b/editor/specialty/Makefile
@@ -41,12 +41,14 @@ OBJECTS = $(BINARIES:%=%.o)
 
 MERGE_OBJECTS = $(MERGEBINARIES:%=%.o2)
 
+HAVE_MERGE_COMPAT=YES
+
 .PHONY: all
 all: $(BINARIES)
 
 include $(SRCDIR)/common.mk
 
-install.bin: install.bin.local
+install.bin install.merge: install.bin.local
 
 .PHONY: install.bin.local
 install.bin.local: $(PKGDIR)/bin
@@ -55,3 +57,7 @@ install.bin.local: $(PKGDIR)/bin
 	cd $(PKGDIR)/bin ; \
 	rm -f pgmoil$(EXE) ; \
 	$(SYMLINK) pamoil$(EXE) pgmoil$(EXE)
+
+mergecomptrylist:
+	cat /dev/null >$@
+	echo "TRY(\"pgmoil\", main_pamoil);" >>$@
diff --git a/generator/pamtris/boundaries.c b/generator/pamtris/boundaries.c
index 8ea28682..7045cbc7 100644
--- a/generator/pamtris/boundaries.c
+++ b/generator/pamtris/boundaries.c
@@ -3,11 +3,11 @@
 ===============================================================================
    Boundary buffer functions
 
-   New triangles are drawn one scanline at a time, and for every such scanline
-   we have left and right boundary columns within the frame buffer such that
-   the fraction of the triangle's area within that scanline is enclosed
-   between those two points (inclusive). Those coordinates may correspond to
-   columns outside the frame buffer's actual limits, in which case proper
+   New triangles are drawn one row at a time, and for every such row we have
+   left and right boundary columns within the frame buffer such that the
+   fraction of the triangle's area within that scanline is enclosed between
+   those two points (inclusive). Those coordinates may correspond to columns
+   outside the frame buffer's actual limits, in which case proper
    post-processing should be made wherever such coordinates are used to
    actually plot anything into the frame buffer.
 =============================================================================*/
@@ -17,38 +17,24 @@
 #include <netpbm/mallocvar.h>
 #include <netpbm/pm.h>
 
+#include "varying.h"
 #include "utils.h"
-#include "fract.h"
 
 
 #include "boundaries.h"
 
 
 
-static fract
-make_pos_fract(int32_t const quotient,
-               int32_t const remainder) {
-
-    fract retval;
-
-    retval.q = quotient;
-    retval.r = remainder;
-    retval.negative_flag = 0;
-
-    return retval;
-}
-
-
-
 void
 init_boundary_buffer(boundary_info * const bi,
                      int16_t         const height) {
 
     MALLOCARRAY(bi->buffer, height * 2);
 
-    if (!bi->buffer)
-        pm_error("Unable to get memory for %u-row high boundary buffer",
+    if (!bi->buffer) {
+        pm_error("unable to get memory for %u-row high boundary buffer.",
                  height);
+    }
 }
 
 
@@ -68,39 +54,30 @@ gen_triangle_boundaries(Xy              const xy,
 /*----------------------------------------------------------------------------
   Generate an entry in the boundary buffer for the boundaries of every
   VISIBLE row of a particular triangle. In case there is no such row,
-  start_row is accordingly set to -1. The argument is a 3-element array
-  of pairs of int16_t's representing the coordinates of the vertices of
+  start_scanline is accordingly set to -1. "xy" is a 3-element array
+  of pairs of integers representing the coordinates of the vertices of
   a triangle. Those vertices MUST be already sorted in order from the
   uppermost to the lowermost vertex (which is what draw_triangle, the
   only function which uses this one, does with the help of sort3).
 
-  The return value indicates whether the middle vertex is to the left of the
-  line connecting the top vertex to the bottom vertex or not.
+  The return value indicates whether the middle vertex is to the left of
+  the line connecting the top vertex to the bottom vertex or not.
 -----------------------------------------------------------------------------*/
     int16_t leftmost_x;
     int16_t rightmost_x;
     int mid_is_to_the_left;
-    fract left_x;
-    fract right_x;
-    bool no_upper_part;
-    int32_t top2mid_delta;
-    int32_t top2bot_delta;
-    int32_t mid2bot_delta;
-    fract top2mid_step;
-    fract top2bot_step;
-    fract mid2bot_step;
-    fract* upper_left_step;
-    fract* lower_left_step;
-    fract* upper_right_step;
-    fract* lower_right_step;
-    int32_t upper_left_delta;
-    int32_t lower_left_delta;
-    int32_t upper_right_delta;
-    int32_t lower_right_delta;
-    fract* left_step[2];
-    fract* right_step[2];
-    int32_t left_delta[2];
-    int32_t right_delta[2];
+    varying top_x;
+    varying mid_x;
+    varying bot_x;
+    varying top2mid;
+    varying top2bot;
+    varying mid2bot;
+    varying* upper_left;
+    varying* lower_left;
+    varying* upper_right;
+    varying* lower_right;
+    varying* left[2];
+    varying* right[2];
     int16_t* num_rows_ptr[2];
     int32_t y;
     int32_t i;
@@ -114,8 +91,8 @@ gen_triangle_boundaries(Xy              const xy,
     bi->num_lower_rows = 0;
 
     if (xy._[2][1] < 0 || xy._[0][1] >= height) {
-        /* Triangle is either completely above the topmost scanline or
-           completely below the bottom scanline.
+        /* Triangle is either completely above the uppermost scanline or
+           completely below the lowermost scanline.
         */
 
         return false; /* Actual value doesn't matter. */
@@ -154,106 +131,57 @@ gen_triangle_boundaries(Xy              const xy,
 
     mid_is_to_the_left = 2;
 
-    left_x  = make_pos_fract(xy._[0][0], 0);
-    right_x = make_pos_fract(xy._[0][0], 0);
+    int32_to_varying_array(&xy._[0][0], &top_x, 1);
+    int32_to_varying_array(&xy._[1][0], &mid_x, 1);
+    int32_to_varying_array(&xy._[2][0], &bot_x, 1);
 
     if (xy._[0][1] == xy._[1][1]) {
         /* Triangle has only a lower part. */
+        k = 1;
 
         mid_is_to_the_left = 0;
+    } else {
+        k = 0;
 
-        right_x.q = xy._[1][0];
-    } else if (xy._[1][1] == xy._[2][1]) {
-        /* Triangle has only an upper part (plus the row of the middle
-           vertex).
-        */
-
-        mid_is_to_the_left = 1;
+        if (xy._[1][1] == xy._[2][1]) {
+            /* Triangle has only an upper part (plus the row of the middle
+               vertex).
+            */
+            mid_is_to_the_left = 1;
+        }
     }
 
-    no_upper_part = (xy._[1][1] == xy._[0][1]);
-
-    top2mid_delta = xy._[1][1] - xy._[0][1] + !no_upper_part;
-    top2bot_delta = xy._[2][1] - xy._[0][1] + 1;
-    mid2bot_delta = xy._[2][1] - xy._[1][1] + no_upper_part;
-
-    gen_steps(&xy._[0][0], &xy._[1][0], &top2mid_step, 1, top2mid_delta);
-    gen_steps(&xy._[0][0], &xy._[2][0], &top2bot_step, 1, top2bot_delta);
-    gen_steps(&xy._[1][0], &xy._[2][0], &mid2bot_step, 1, mid2bot_delta);
+    prepare_for_interpolation(&top_x, &mid_x, &top2mid, xy._[1][1] - xy._[0][1], 1);
+    prepare_for_interpolation(&top_x, &bot_x, &top2bot, xy._[2][1] - xy._[0][1], 1);
+    prepare_for_interpolation(&mid_x, &bot_x, &mid2bot, xy._[2][1] - xy._[1][1], 1);
 
     if (mid_is_to_the_left == 2) {
-        if (top2bot_step.negative_flag) {
-            if (top2mid_step.negative_flag) {
-                if (top2mid_step.q == top2bot_step.q) {
-                    mid_is_to_the_left =
-                        top2mid_step.r * top2bot_delta >
-                        top2bot_step.r * top2mid_delta;
-                } else {
-                    mid_is_to_the_left = top2mid_step.q < top2bot_step.q;
-                }
-            } else {
-                mid_is_to_the_left = 0;
-            }
-        } else {
-            if (!top2mid_step.negative_flag) {
-                if (top2mid_step.q == top2bot_step.q) {
-                    mid_is_to_the_left =
-                        top2mid_step.r * top2bot_delta <
-                        top2bot_step.r * top2mid_delta;
-                } else {
-                    mid_is_to_the_left = top2mid_step.q < top2bot_step.q;
-                }
-            } else {
-                mid_is_to_the_left = 1;
-            }
-        }
+        mid_is_to_the_left = top2mid.s < top2bot.s;
     }
+
     if (mid_is_to_the_left) {
-        upper_left_step     = &top2mid_step;
-        lower_left_step     = &mid2bot_step;
-        upper_right_step    = &top2bot_step;
-        lower_right_step    = upper_right_step;
-
-        upper_left_delta    = top2mid_delta;
-        lower_left_delta    = mid2bot_delta;
-        upper_right_delta   = top2bot_delta;
-        lower_right_delta   = upper_right_delta;
+        upper_left     = &top2mid;
+        lower_left     = &mid2bot;
+        upper_right    = &top2bot;
+        lower_right    = upper_right;
     } else {
-        upper_right_step    = &top2mid_step;
-        lower_right_step    = &mid2bot_step;
-        upper_left_step     = &top2bot_step;
-        lower_left_step     = upper_left_step;
-
-        upper_right_delta   = top2mid_delta;
-        lower_right_delta   = mid2bot_delta;
-        upper_left_delta    = top2bot_delta;
-        lower_left_delta    = upper_left_delta;
+        upper_right    = &top2mid;
+        lower_right    = &mid2bot;
+        upper_left     = &top2bot;
+        lower_left     = upper_left;
     }
 
-    left_step[0] = upper_left_step;
-    left_step[1] = lower_left_step;
-    right_step[0] = upper_right_step;
-    right_step[1] = lower_right_step;
-    left_delta[0] = upper_left_delta;
-    left_delta[1] = lower_left_delta;
-    right_delta[0] = upper_right_delta;
-    right_delta[1] = lower_right_delta;
+    left[0] = upper_left;
+    left[1] = lower_left;
+    right[0] = upper_right;
+    right[1] = lower_right;
+
     num_rows_ptr[0] = &bi->num_upper_rows;
     num_rows_ptr[1] = &bi->num_lower_rows;
 
     y = xy._[0][1];
 
     i = 0;
-    k = 0;
-
-    if (no_upper_part) {
-        k = 1;
-
-        right_x.q = xy._[1][0];
-    }
-
-    step_up(&left_x, left_step[k], 1, left_delta[k]);
-    step_up(&right_x, right_step[k], 1, right_delta[k]);
 
     while (k < 2) {
         int32_t end;
@@ -271,8 +199,8 @@ gen_triangle_boundaries(Xy              const xy,
 
             y += delta;
 
-            multi_step_up(&left_x, left_step[k], 1, delta, left_delta[k]);
-            multi_step_up(&right_x, right_step[k], 1, delta, right_delta[k]);
+            multi_step_up(left[k], delta, 1);
+            multi_step_up(right[k], delta, 1);
 
             if (y < 0) {
                 k++;
@@ -287,7 +215,7 @@ gen_triangle_boundaries(Xy              const xy,
         }
 
         while (y < end) {
-            if (left_x.q >= width || right_x.q < 0) {
+            if (round_varying(*left[k]) >= width || round_varying(*right[k]) < 0) {
                 if (bi->start_scanline > -1) {
                     return mid_is_to_the_left;
                 }
@@ -296,14 +224,14 @@ gen_triangle_boundaries(Xy              const xy,
                     bi->start_scanline = y;
                 }
 
-                bi->buffer[i++] = left_x.q;
-                bi->buffer[i++] = right_x.q;
+                bi->buffer[i++] = round_varying(*left[k]);
+                bi->buffer[i++] = round_varying(*right[k]);
 
                 (*(num_rows_ptr[k]))++;
             }
 
-            step_up(&left_x, left_step[k], 1, left_delta[k]);
-            step_up(&right_x, right_step[k], 1, right_delta[k]);
+            step_up(left[k], 1);
+            step_up(right[k], 1);
 
             y++;
         }
diff --git a/generator/pamtris/boundaries.h b/generator/pamtris/boundaries.h
index d41719cb..70f7f90d 100644
--- a/generator/pamtris/boundaries.h
+++ b/generator/pamtris/boundaries.h
@@ -1,6 +1,7 @@
 #ifndef BOUNDARIES_H_INCLUDED
 #define BOUNDARIES_H_INCLUDED
 
+#include <stdbool.h>
 #include <stdint.h>
 
 #include "triangle.h"
diff --git a/generator/pamtris/fract.h b/generator/pamtris/fract.h
deleted file mode 100644
index ff3c4402..00000000
--- a/generator/pamtris/fract.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef FRACT_H_INCLUDED
-#define FRACT_H_INCLUDED
-
-#include <stdbool.h>
-#include <stdint.h>
-
-
-typedef struct {
-/*----------------------------------------------------------------------------
-    This struct and the functions that manipulate variables of this type act
-    as a substitute for floating point computations. Here, whenever we need a
-    value with a fractional component, we represent it using two parts: 1. An
-    integer part, called the "quotient", and 2. A fractional part, which is
-    itself composed of a "remainder" (or "numerator") and a "divisor" (or
-    "denominator"). The fract struct provides storage for the quotient and the
-    remainder, but the divisor must be given separately (because it often
-    happens in this program that whenever we are dealing with one variable of
-    type fract, we are dealing with more of them at the same time, and they
-    all have the same divisor).
-
-    To be more precise, the way we actually use variables of this type works
-    like this: We read integer values through standard input; When drawing
-    triangles, we need need to calculate differences between some pairs of
-    these input values and divide such differences by some other integer,
-    which is the above mentioned divisor. That result is then used to compute
-    successive interpolations between the two values for which we had
-    originally calculated the difference, and is therefore called the
-    "interpolation step". The values between which we wish to take successive
-    interpolations are called the "initial value" and the "final value". The
-    interpolation procedure works like this: First, we transform the initial
-    value into a fract variable by equating the quotient of that variable to
-    the initial value and assigning 0 to its remainder. Then, we successivelly
-    apply the interpolation step to that variable through successive calls to
-    step_up and/or multi_step_up until the quotient of the variable equals the
-    final value. Each application of step_up or multi_step_up yields a
-    particular linear interpolation between the initial and final values.
-
-    If and only if a particular fract variable represents an interpolation
-    step, the "negative_flag" field indicates whether the step is negative
-    (i. e. negative_flag == true) or not (negative_flag == false). This is
-    necessary in order to make sure that variables are "stepped up" in the
-    appropriate direction, so to speak, as the field which stores the
-    remainder in any fract variable, "r", is always equal to or above 0, and
-    the quotient of a step may be 0, so the actual sign of the step value is
-    not always discoverable through a simple examination of the sign of the
-    quotient. On the other hand, if the variable does not represent an
-    interpolation step, the negative_flag is meaningless.
------------------------------------------------------------------------------*/
-    int32_t q;     /* Quotient */
-    int32_t r: 31; /* Remainder */
-    bool    negative_flag: 1;
-} fract;
-
-#endif
diff --git a/generator/pamtris/framebuffer.c b/generator/pamtris/framebuffer.c
index 03cd720c..93263c91 100644
--- a/generator/pamtris/framebuffer.c
+++ b/generator/pamtris/framebuffer.c
@@ -37,9 +37,10 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+#include <math.h>
 
 #include "utils.h"
-#include "fract.h"
+#include "varying.h"
 #include "limits_pamtris.h"
 
 #include "framebuffer.h"
@@ -60,8 +61,6 @@ set_tupletype(const char * const str,
 -----------------------------------------------------------------------------*/
     if (str == NULL) {
         memset(tupletype, 0, 256);
-
-        return 1;
     } else {
         size_t len;
 
@@ -80,9 +79,9 @@ set_tupletype(const char * const str,
         while(len > 0 && isspace(tupletype[len])) {
             tupletype[len--] = '\0';
         }
-
-        return 1;
     }
+
+    return 1;
 }
 
 
@@ -279,9 +278,7 @@ clear_framebuffer(bool               const clear_image_buffer,
 void
 draw_span(uint32_t           const base,
           uint16_t           const length,
-          fract *            const attribs_start,
-          const fract *      const attribs_steps,
-          int32_t            const div,
+          varying *          const attribs,
           framebuffer_info * const fbi) {
 /*----------------------------------------------------------------------------
   Draw a horizontal span of "length" pixels into the frame buffer, performing
@@ -291,42 +288,50 @@ draw_span(uint32_t           const base,
 
   This function does not perform any kind of bounds checking.
 -----------------------------------------------------------------------------*/
-    uint8_t const num_planes = fbi->num_attribs + 1;
+    static double const depth_range = MAX_Z;
+
+    uint16_t const maxval = fbi->maxval;
+    uint8_t  const z      = fbi->num_attribs;
+    uint8_t  const w      = z + 1;
+    uint8_t  const n      = w + 1;
+
+    uint8_t  const num_planes = w;
 
     unsigned int i;
 
     /* Process each pixel in the span: */
 
     for (i = 0; i < length; i++) {
-        int32_t  const z        = MAX_Z - attribs_start[fbi->num_attribs].q;
-        uint32_t const z_mask   = -(~(z - fbi->z.buffer[base + i]) >> 31);
-        uint32_t const n_z_mask = ~z_mask;
+        int32_t  const d      = round(depth_range * attribs[z].v);
+        uint32_t const d_mask = geq_mask64(d, fbi->z.buffer[base + i]);
 
         uint32_t const j = base + i;
         uint32_t const k = j * num_planes;
 
+        varying const inverse_w = inverse_varying(attribs[w]);
+
         unsigned int l;
 
         /* The following statements will only have any effect if the depth
            test, performed above, has suceeded. I. e. if the depth test fails,
-           no changes will be made on the framebuffer; otherwise, the
-           framebuffer will be updated with the new values.
+           no changes will be made on the frame buffer; otherwise, the
+           frame buffer will be updated with the new values.
         */
-        fbi->z.buffer[j] = (fbi->z.buffer[j] & n_z_mask) | (z & z_mask);
+        fbi->z.buffer[j] = (fbi->z.buffer[j] & ~d_mask) | (d & d_mask);
+
+        for (l = 0; l < z; l++) {
+	    varying const newval = multiply_varyings(attribs[l], inverse_w);
 
-        for (l = 0; l < fbi->num_attribs; l++) {
             fbi->img.buffer[k + l] =
-                (fbi->img.buffer[k + l] & n_z_mask) |
-                (attribs_start[l].q & z_mask);
+                (fbi->img.buffer[k + l] & ~d_mask) |
+                (round_varying(newval) &  d_mask);
         }
 
-        fbi->img.buffer[k + fbi->num_attribs] =
-            (fbi->img.buffer[k + fbi->num_attribs] & n_z_mask) |
-            (fbi->maxval & z_mask);
+        fbi->img.buffer[k + z] |= (maxval & d_mask);
 
         /* Compute the attribute values for the next pixel: */
 
-        step_up(attribs_start, attribs_steps, num_planes, div);
+        step_up(attribs, n);
     }
 }
 
diff --git a/generator/pamtris/framebuffer.h b/generator/pamtris/framebuffer.h
index 73ec96be..b3d4f7a3 100644
--- a/generator/pamtris/framebuffer.h
+++ b/generator/pamtris/framebuffer.h
@@ -3,7 +3,8 @@
 
 #include <stdint.h>
 #include <stdbool.h>
-#include "fract.h"
+
+#include "varying.h"
 #include "netpbm/pam.h"
 
 typedef struct framebuffer_info {
@@ -12,7 +13,8 @@ typedef struct framebuffer_info {
 -----------------------------------------------------------------------------*/
     /* These fields are initialized once by reading the command line
        arguments. "maxval" and "num_attribs" may be modified later
-       through "realloc_image_buffer".
+       through "realloc_image_buffer"; "correct" may also be modified
+       if the eponymous command is given.
     */
     int32_t width;
     int32_t height;
@@ -67,9 +69,7 @@ realloc_image_buffer(int32_t            const new_maxval,
 void
 draw_span(uint32_t           const base,
           uint16_t           const length,
-          fract *            const attribs_start,
-          const fract *      const attribs_steps,
-          int32_t            const divisor,
+          varying *          const attribs,
           framebuffer_info * const fbi);
 
 #endif
diff --git a/generator/pamtris/input.c b/generator/pamtris/input.c
index 4b7ff305..2ea35734 100644
--- a/generator/pamtris/input.c
+++ b/generator/pamtris/input.c
@@ -11,6 +11,7 @@
 
 #include "netpbm/mallocvar.h"
 #include "netpbm/pm.h"
+#include "netpbm/nstring.h"
 
 #include "limits_pamtris.h"
 #include "framebuffer.h"
@@ -18,26 +19,23 @@
 
 #include "input.h"
 
-#define MAX_COORD       32767
-#define MIN_COORD       -MAX_COORD
-
 #define DRAW_MODE_TRIANGLES 1
 #define DRAW_MODE_STRIP     2
 #define DRAW_MODE_FAN       3
 
 #define CMD_SET_MODE        "mode"
 #define CMD_SET_ATTRIBS     "attribs"
-#define CMD_VERTEX      "vertex"
-#define CMD_PRINT       "print"
-#define CMD_CLEAR       "clear"
-#define CMD_RESET       "reset"
-#define CMD_QUIT        "quit"
+#define CMD_VERTEX          "vertex"
+#define CMD_PRINT           "print"
+#define CMD_CLEAR           "clear"
+#define CMD_RESET           "reset"
+#define CMD_QUIT            "quit"
 
 #define ARG_TRIANGLES       "triangles"
-#define ARG_STRIP       "strip"
-#define ARG_FAN         "fan"
-#define ARG_IMAGE       "image"
-#define ARG_DEPTH       "depth"
+#define ARG_STRIP           "strip"
+#define ARG_FAN             "fan"
+#define ARG_IMAGE           "image"
+#define ARG_DEPTH           "depth"
 
 #define WARNING_EXCESS_ARGS "warning: ignoring excess arguments: line %lu."
 #define SYNTAX_ERROR        "syntax error: line %lu."
@@ -45,10 +43,8 @@
 typedef struct {
     Xy v_xy;
         /* X- and Y-coordinates of the vertices for the current triangle.
-           int32_t v_attribs[3][MAX_NUM_ATTRIBS + 1]; // Vertex attributes for
-           the current triangle. Includes the Z-coordinates.
         */
-	Attribs v_attribs;
+    Attribs v_attribs;
         /* Vertex attributes for the current triangle. Includes the
            Z-coordinates.
         */
@@ -70,13 +66,13 @@ typedef struct {
 
 
 static void
-clear_attribs(state_info * const si,
-              int32_t      const maxval,
-              int16_t      const num_attribs) {
+clearAttribs(state_info * const si,
+             int32_t      const maxval,
+             int16_t      const num_attribs) {
 
     unsigned int i;
 
-    for (i = 0; i < num_attribs; i++) {
+    for (i = 0; i < num_attribs; ++i) {
         si->curr_attribs[i] = maxval;
     }
 }
@@ -84,20 +80,20 @@ clear_attribs(state_info * const si,
 
 
 void
-init_input_processor(input_info * const ii) {
+input_init(Input * const inputP) {
 
-    ii->buffer = NULL;
-    ii->length = 0;
-    ii->number = 1;
+    inputP->buffer = NULL;
+    inputP->length = 0;
+    inputP->number = 1;
 }
 
 
 
 void
-free_input_processor(input_info * const ii) {
+input_term(Input * const inputP) {
 
-    if (ii->buffer)
-        free(ii->buffer);
+    if (inputP->buffer)
+        free(inputP->buffer);
 }
 
 
@@ -109,14 +105,14 @@ typedef struct {
 -----------------------------------------------------------------------------*/
     char * begin;
     char * end;
-} token;
+} Token;
 
 
 
-static token
-next_token(char * const startPos) {
+static Token
+nextToken(char * const startPos) {
 
-    token retval;
+    Token retval;
     char * p;
 
     for (p = startPos; *p && isspace(*p); ++p);
@@ -133,9 +129,9 @@ next_token(char * const startPos) {
 
 
 static bool
-string_is_valid(const char * const target,
-                const char * const srcBegin,
-                const char * const srcEnd) {
+stringIsValid(const char * const target,
+              const char * const srcBegin,
+              const char * const srcEnd) {
 
     unsigned int charsMatched;
     const char * p;
@@ -155,17 +151,17 @@ string_is_valid(const char * const target,
 
 
 static void
-init_state(state_info * const si) {
+initState(state_info * const siP) {
 
-    si->next = 0;
-    si->draw = false;
-    si->mode = DRAW_MODE_TRIANGLES;
+    siP->next = 0;
+    siP->draw = false;
+    siP->mode = DRAW_MODE_TRIANGLES;
 }
 
 
 
 static void
-make_lowercase(token const t) {
+makeLowercase(Token const t) {
 
     char * p;
 
@@ -176,7 +172,7 @@ make_lowercase(token const t) {
 
 
 static void
-remove_comments(char * const str) {
+removeComments(char * const str) {
 
     char * p;
 
@@ -191,459 +187,510 @@ remove_comments(char * const str) {
 
 
 
-int
-process_next_command(input_info           * const line,
-                     struct boundary_info * const bi,
-                     framebuffer_info     * const fbi) {
-/*----------------------------------------------------------------------------
-  Doesn't necessarily process a command, just the next line of input, which
-  may be empty. Always returns 1, except when it cannot read any more lines of
-  input, an image buffer reallocation fails, or a "q" command is found in the
-  input -- in such cases it returns 0.
------------------------------------------------------------------------------*/
-    static state_info state;
-
-    token nt;
-
-    long int i_args[MAX_NUM_ATTRIBS];
-        /* For storing potential integer arguments. */
-    char * strtol_end;
-        /* To compare against nt.end when checking for errors with strtol */
-    bool unrecognized_cmd;
-        /* To print out an error message in case an unrecognized command was
-           given.
-        */
-    bool unrecognized_arg;
-        /* To print out an error message in case an unrecognized argument was
-           given.
-        */
-    bool must_break_out;
-        /* To break out of the below switch statement when an invalid argument
-           is found.
-        */
-    bool ok;
-        /* Indicates whether the input line was OK so that we can print out a
-           warning in case of excess arguments.
-        */
-
-    /* initial values */
-    strtol_end = NULL;
-    unrecognized_cmd = false;
-    unrecognized_arg = false;
-    must_break_out = false;
-    ok = false;
-
-    if (!state.initialized) {
-        init_state(&state);
-        clear_attribs(&state, fbi->maxval, fbi->num_attribs);
-
-        state.initialized = true;
+static void
+processM(Token *       const ntP,
+         state_info *  const stateP,
+         bool *        const unrecognizedCmdP,
+         const char ** const errorP) {
+
+    if (!stringIsValid(CMD_SET_MODE, ntP->begin, ntP->end)) {
+        *unrecognizedCmdP = true;
+    } else {
+        *ntP = nextToken(ntP->end);
+
+        *unrecognizedCmdP = false;
+
+        if (*ntP->begin == '\0')
+            pm_asprintf(errorP, "syntax error");
+        else {
+            makeLowercase(*ntP);
+
+            switch (*ntP->begin) {
+            case 't':
+                if (!stringIsValid(ARG_TRIANGLES, ntP->begin, ntP->end))
+                    pm_asprintf(errorP, "unrecognized drawing mode");
+                else {
+                    stateP->mode = DRAW_MODE_TRIANGLES;
+                    stateP->draw = false;
+                    stateP->next = 0;
+
+                    *errorP = NULL;
+                }
+                break;
+            case 's':
+                if (!stringIsValid(ARG_STRIP, ntP->begin, ntP->end))
+                    pm_asprintf(errorP, "unrecognized drawing mode");
+                else {
+                    stateP->mode = DRAW_MODE_STRIP;
+                    stateP->draw = false;
+                    stateP->next = 0;
+
+                    *errorP = NULL;
+                }
+                break;
+            case 'f':
+                if (!stringIsValid(ARG_FAN, ntP->begin, ntP->end))
+                    pm_asprintf(errorP, "unrecognized drawing mode");
+                else {
+                    stateP->mode = DRAW_MODE_FAN;
+                    stateP->draw = false;
+                    stateP->next = 0;
+
+                    *errorP = NULL;
+                }
+                break;
+            default:
+                pm_asprintf(errorP, "unrecognized drawing mode");
+            }
+        }
     }
+}
 
-    {
-        int eof;
-        size_t lineLen;
-
-        pm_getline(stdin, &line->buffer, &line->length, &eof, &lineLen);
 
-        if (eof)
-            return 0;
-    }
 
-    remove_comments(line->buffer);
-
-    nt = next_token(line->buffer);
+static void
+processA(Token *            const ntP,
+         state_info *       const stateP,
+         framebuffer_info * const fbiP,
+         bool *             const unrecognizedCmdP,
+         long int *         const iArgs,
+         const char **      const errorP) {
 
-    make_lowercase(nt);
+    if (!stringIsValid(CMD_SET_ATTRIBS, ntP->begin, ntP->end)) {
+        *unrecognizedCmdP = true;
+    } else {
+        unsigned int i;
 
-    switch (*nt.begin) {
-    case 'm':
-        if (!string_is_valid(CMD_SET_MODE, nt.begin, nt.end)) {
-            unrecognized_cmd = true;
+        *unrecognizedCmdP = false;
 
-            break;
-        }
+        for (i = 0, *errorP = NULL; i < fbiP->num_attribs && !*errorP; ++i) {
+            char * strtolEnd;
 
-        nt = next_token(nt.end);
+            *ntP = nextToken(ntP->end);
 
-        if (*nt.begin == '\0') {
-            pm_errormsg(SYNTAX_ERROR, line->number);
+            iArgs[i] = strtol(ntP->begin, &strtolEnd, 10);
 
-            break;
+            if (*ntP->begin == '\0' || strtolEnd != ntP->end)
+                pm_asprintf(errorP, "syntax error");
+            else {
+                if (iArgs[i] < 0 || iArgs[i] > fbiP->maxval)
+                    pm_asprintf(errorP, "argument(s) out of bounds");
+            }
         }
 
-        make_lowercase(nt);
+        if (!*errorP) {
+            unsigned int i;
 
-        switch(*nt.begin) {
-        case 't':
-            if (!string_is_valid(ARG_TRIANGLES, nt.begin, nt.end)) {
-                unrecognized_arg = true;
+            for (i = 0; i < fbiP->num_attribs; ++i)
+                stateP->curr_attribs[i] = iArgs[i];
+        }
+    }
+}
 
-                break;
-            }
 
-            state.mode = DRAW_MODE_TRIANGLES;
-            state.draw = false;
-            state.next = 0;
 
-            ok = true;
+static void
+processV(Token *                const ntP,
+         state_info *           const stateP,
+         struct boundary_info * const biP,
+         framebuffer_info *     const fbiP,
+         bool *                 const unrecognizedCmdP,
+         long int *             const iArgs,
+         const char **          const errorP) {
 
-            break;
-        case 's':
-            if (!string_is_valid(ARG_STRIP, nt.begin, nt.end)) {
-                unrecognized_arg = true;
+    if (!stringIsValid(CMD_VERTEX, ntP->begin, ntP->end))
+        *unrecognizedCmdP = true;
+    else {
+        unsigned int i;
 
-                break;
-            }
+        *unrecognizedCmdP = false;
 
-            state.mode = DRAW_MODE_STRIP;
-            state.draw = false;
-            state.next = 0;
+        for (i = 0, *errorP = NULL; i < 4 && !*errorP; ++i) {
+            char * strtolEnd;
 
-            ok = true;
+            *ntP = nextToken(ntP->end);
 
-            break;
-        case 'f':
-            if (!string_is_valid(ARG_FAN, nt.begin, nt.end)) {
-                unrecognized_arg = true;
+            iArgs[i] = strtol(ntP->begin, &strtolEnd, 10);
 
-                break;
+            if (*ntP->begin == '\0') {
+                if (i != 3)
+                    pm_asprintf(errorP, "syntax error");
+                else
+                    iArgs[i] = 1;
+            } else {
+                if (strtolEnd != ntP->end)
+                    pm_asprintf(errorP, "syntax error");
             }
 
-            state.mode = DRAW_MODE_FAN;
-            state.draw = false;
-            state.next = 0;
-
-            ok = true;
-
-            break;
-        default:
-            unrecognized_arg = true;
-        }
-
-        if (unrecognized_arg) {
-            pm_errormsg("error: unrecognized drawing mode in line %lu.",
-                        line->number);
+            if (!*errorP) {
+                if (i < 3) {
+                    if (iArgs[i] < MIN_COORD || iArgs[i] > MAX_COORD)
+                        pm_asprintf(errorP, "coordinates out of bounds");
+                } else {
+                    if (iArgs[i] < MIN_INPUT_W || iArgs[i] > MAX_INPUT_W)
+                        pm_asprintf(errorP,
+                                    "perspective correction factor (w) "
+                                    "out of bounds");
+                }
+            }
         }
 
-        break;
-    case 'a': {
-        uint8_t i;
-        if (!string_is_valid(CMD_SET_ATTRIBS, nt.begin, nt.end)) {
-            unrecognized_cmd = true;
-
-            break;
-        }
+        if (!*errorP) {
+            unsigned int i;
 
-        for (i = 0; i < fbi->num_attribs; i++) {
-            nt = next_token(nt.end);
+            for (i = 0; i < fbiP->num_attribs; ++i) {
+                stateP->v_attribs._[stateP->next][i] = stateP->curr_attribs[i];
+            }
 
-            i_args[i] = strtol(nt.begin, &strtol_end, 10);
+            stateP->v_attribs._[stateP->next][fbiP->num_attribs + 0] =
+                iArgs[2];
+            stateP->v_attribs._[stateP->next][fbiP->num_attribs + 1] =
+                iArgs[3];
 
-            if (*nt.begin == '\0' || strtol_end != nt.end) {
-                pm_errormsg(SYNTAX_ERROR, line->number);
+            stateP->v_xy._[stateP->next][0] = iArgs[0];
+            stateP->v_xy._[stateP->next][1] = iArgs[1];
 
-                must_break_out = true;
+            ++stateP->next;
 
-                break;
+            if (!stateP->draw) {
+                if (stateP->next == 3)
+                    stateP->draw = true;
             }
 
-            if (i_args[i] < 0 || i_args[i] > fbi->maxval) {
-                pm_errormsg("error: argument(s) out of bounds: line %lu.",
-                            line->number);
-
-                must_break_out = true;
+            if (stateP->draw)
+                draw_triangle(stateP->v_xy, stateP->v_attribs, biP, fbiP);
 
-                break;
+            if (stateP->next == 3) {
+                switch(stateP->mode) {
+                case DRAW_MODE_FAN:
+                    stateP->next = 1;
+                    break;
+                case DRAW_MODE_TRIANGLES:
+                    stateP->draw = false;
+                    stateP->next = 0;
+                    break;
+                case DRAW_MODE_STRIP:
+                    stateP->next = 0;
+                    break;
+                default:
+                    stateP->next = 0;
+                }
             }
         }
+    }
+}
 
-        if (must_break_out)
-        {
-            break;
-        }
 
-        for (i = 0; i < fbi->num_attribs; i++) {
-            state.curr_attribs[i] = i_args[i];
-        }
 
-        ok = true;
+static void
+processP(Token *            const ntP,
+         framebuffer_info * const fbiP,
+         bool *             const unrecognizedCmdP,
+         const char **      const errorP) {
 
-    } break;
-    case 'v': {
-        uint8_t i;
+    if (!stringIsValid(CMD_PRINT, ntP->begin, ntP->end))
+        *unrecognizedCmdP = true;
+    else {
+        *unrecognizedCmdP = false;
 
-        if (!string_is_valid(CMD_VERTEX, nt.begin, nt.end)) {
-            unrecognized_cmd = true;
+        print_framebuffer(fbiP);
 
-            break;
-        }
+        *errorP = NULL;
+    }
+}
 
-        for (i = 0; i < 3; i++) {
-            nt = next_token(nt.end);
 
-            i_args[i] = strtol(nt.begin, &strtol_end, 10);
 
-            if (*nt.begin == '\0' || strtol_end != nt.end) {
-                pm_errormsg(SYNTAX_ERROR, line->number);
 
-                must_break_out = true;
+static void
+processExcl(Token *            const ntP,
+            framebuffer_info * const fbiP,
+            bool *             const unrecognizedCmdP,
+            const char **      const errorP) {
 
-                break;
-            }
+    if (ntP->end - ntP->begin > 1)
+        *unrecognizedCmdP = true;
+    else {
+        *unrecognizedCmdP = false;
 
-            if (i < 2) {
-                if (i_args[i] < MIN_COORD || i_args[i] > MAX_COORD) {
-                    pm_errormsg(
-                        "error: coordinates out of bounds: line %lu.",
-                        line->number);
+        print_framebuffer(fbiP);
 
-                    must_break_out = true;
+        *errorP = NULL;
+    }
+}
 
-                    break;
-                }
-            } else {
-                if (i_args[i] < 0 || i_args[i] > MAX_Z) {
-                    pm_errormsg(
-                        "error: Z component out of bounds: line %lu.",
-                        line->number);
 
-                    must_break_out = true;
 
-                    break;
-                }
+static void
+clear(Token *            const ntP,
+      framebuffer_info * const fbiP,
+      const char **      const errorP) {
+
+    *ntP = nextToken(ntP->end);
+
+    if (*ntP->begin != '\0') {
+        makeLowercase(*ntP);
+
+        switch(*ntP->begin) {
+        case 'i':
+            if (!stringIsValid("image", ntP->begin, ntP->end))
+                pm_asprintf(errorP, "unrecognized argument");
+            else {
+                clear_framebuffer(true, false, fbiP);
+                *errorP = NULL;
             }
-        }
-
-        if (must_break_out)
-        {
             break;
-        }
-
-        for (i = 0; i < fbi->num_attribs; i++) {
-            state.v_attribs._[state.next][i] = state.curr_attribs[i];
-        }
-
-        state.v_attribs._[state.next][fbi->num_attribs] = i_args[2];
-
-        state.v_xy._[state.next][0] = i_args[0];
-        state.v_xy._[state.next][1] = i_args[1];
-
-        state.next++;
-
-        if (!state.draw) {
-            if (state.next == 3) {
-                state.draw = true;
+        case 'd':
+            if (!stringIsValid("depth", ntP->begin, ntP->end))
+                pm_asprintf(errorP, "unrecognized argument");
+            else {
+                clear_framebuffer(false, true, fbiP);
+                *errorP = NULL;
             }
-        }
-
-        if (state.draw) {
-            draw_triangle(state.v_xy, state.v_attribs, bi, fbi);
-        }
-
-        if (state.next == 3) {
-            switch(state.mode) {
-            case DRAW_MODE_FAN:
-                state.next = 1;
-                break;
-            case DRAW_MODE_TRIANGLES:
-                state.draw = false;
-            case DRAW_MODE_STRIP:
-            default:
-                state.next = 0;
+            break;
+        case 'z':
+            if (ntP->end - ntP->begin > 1)
+                pm_asprintf(errorP, "unrecognized argument");
+            else {
+                clear_framebuffer(false, true, fbiP);
+                *errorP = NULL;
             }
+            break;
+        default:
+            pm_asprintf(errorP, "unrecognized argument");
         }
+    } else {
+        clear_framebuffer(true, true, fbiP);
+        *errorP = NULL;
+    }
+}
 
-        ok = true;
 
-    } break;
-    case 'p':
-        if (!string_is_valid(CMD_PRINT, nt.begin, nt.end)) {
-            unrecognized_cmd = true;
 
-            break;
-        }
-    case '!':
-        if (*nt.begin == '!') {
-            if (nt.end - nt.begin > 1) {
-                unrecognized_cmd = true;
+static void
+processC(Token *            const ntP,
+         framebuffer_info * const fbiP,
+         bool *             const unrecognizedCmdP,
+         const char **      const errorP) {
 
-                break;
-            }
-        }
+    if (!stringIsValid(CMD_CLEAR, ntP->begin, ntP->end))
+        *unrecognizedCmdP = true;
+    else {
+        *unrecognizedCmdP = false;
 
-        print_framebuffer(fbi);
+        clear(ntP, fbiP, errorP);
+    }
+}
 
-        ok = true;
 
-        break;
-    case 'c':
-        if (!string_is_valid(CMD_CLEAR, nt.begin, nt.end)) {
-            unrecognized_cmd = true;
 
-            break;
-        }
-    case '*':
-        if (*nt.begin == '*') {
-            if(nt.end - nt.begin > 1) {
-                unrecognized_cmd = true;
+static void
+processAsterisk(Token *            const ntP,
+                framebuffer_info * const fbiP,
+                bool *             const unrecognizedCmdP,
+                const char **      const errorP) {
 
-                break;
-            }
-        }
+    if (ntP->end - ntP->begin > 1)
+        *unrecognizedCmdP = true;
+    else {
+        *unrecognizedCmdP = false;
 
-        nt = next_token(nt.end);
+        clear(ntP, fbiP, errorP);
+    }
+}
 
-        if (*nt.begin != '\0') {
-            make_lowercase(nt);
 
-            switch(*nt.begin) {
-            case 'i':
-                if (!string_is_valid("image", nt.begin, nt.end)) {
-                    unrecognized_arg = true;
 
-                    break;
-                }
+static void
+processR(Token *                const ntP,
+         state_info *           const stateP,
+         framebuffer_info *     const fbiP,
+         bool *                 const unrecognizedCmdP,
+         long int *             const iArgs,
+         const char **          const errorP) {
 
-                clear_framebuffer(true, false, fbi);
+    if (!stringIsValid(CMD_RESET, ntP->begin, ntP->end))
+        *unrecognizedCmdP = true;
+    else {
+        unsigned int i;
 
-                break;
-            case 'd':
-                if (!string_is_valid("depth", nt.begin, nt.end)) {
-                    unrecognized_arg = true;
+        *unrecognizedCmdP = false;
 
-                    break;
-                }
-            case 'z':
-                if (*nt.begin == 'z') {
-                    if (nt.end - nt.begin > 1) {
-                        unrecognized_arg = true;
+        for (i = 0, *errorP = NULL; i < 2 && !*errorP; ++i) {
+            char * strtolEnd;
 
-                        break;
-                    }
-                }
+            *ntP = nextToken(ntP->end);
 
-                clear_framebuffer(false, true, fbi);
+            iArgs[i] = strtol(ntP->begin, &strtolEnd, 10);
 
-                break;
-            default:
-                unrecognized_arg = true;
-            }
+            if (*ntP->begin == '\0' || ntP->end != strtolEnd)
+                pm_asprintf(errorP, "syntax error");
+        }
 
-            if (unrecognized_arg) {
-                pm_errormsg("error: unrecognized argument: line %lu.",
-                            line->number);
+        if (!*errorP) {
+            if (iArgs[0] < 1 || iArgs[0] > PAM_OVERALL_MAXVAL)
+                pm_asprintf(errorP, "invalid new maxval");
+            else {
+                if (iArgs[1] < 1 || iArgs[1] > MAX_NUM_ATTRIBS)
+                    pm_asprintf(errorP, "invalid new number of generic vertex "
+                                "attributes");
+                else {
+                    *ntP = nextToken(ntP->end);
+
+                    if (*ntP->begin != '\0') {
+                        if (!set_tupletype(ntP->begin,
+                                           fbiP->outpam.tuple_type)) {
+                            pm_message(
+                                "warning: could not set new tuple type; "
+                                "using a null string");
+                            set_tupletype(NULL, fbiP->outpam.tuple_type);
+                        }
+                    } else
+                        set_tupletype(NULL, fbiP->outpam.tuple_type);
+
+                    if (!realloc_image_buffer(iArgs[0], iArgs[1], fbiP)) {
+                        pm_error("Unable to allocate memory for "
+                                 "image buffer");
+                    }
 
-                break;
+                    stateP->next = 0;
+                    stateP->draw = false;
+
+                    clearAttribs(stateP, fbiP->maxval, fbiP->num_attribs);
+                }
             }
-        } else {
-            clear_framebuffer(true, true, fbi);
         }
+    }
+}
 
-        ok = true;
 
-        break;
-    case 'r': {
-        uint8_t i;
 
-        if (!string_is_valid(CMD_RESET, nt.begin, nt.end)) {
-            unrecognized_cmd = true;
+static void
+processQ(Token *                const ntP,
+         bool *                 const unrecognizedCmdP,
+         bool *                 const noMoreCommandsP,
+         const char **          const errorP) {
 
-            break;
-        }
+    if (!stringIsValid(CMD_QUIT, ntP->begin, ntP->end))
+        *unrecognizedCmdP = true;
+    else {
+        *unrecognizedCmdP = false;
 
-        for (i = 0; i < 2; i++) {
-            nt = next_token(nt.end);
+        *noMoreCommandsP = true;
 
-            i_args[i] = strtol(nt.begin, &strtol_end, 10);
+        *errorP = NULL;
+    }
+}
 
-            if (*nt.begin == '\0' || nt.end != strtol_end) {
-                pm_errormsg(SYNTAX_ERROR, line->number);
 
-                must_break_out = true;
 
-                break;
-            }
-        }
+void
+input_process_next_command(Input *                const inputP,
+                           struct boundary_info * const biP,
+                           framebuffer_info *     const fbiP,
+                           bool *                 const noMoreCommandsP) {
+/*----------------------------------------------------------------------------
+  Doesn't necessarily process a command, just the next line of input, which
+  may be empty.
 
-        if (must_break_out) {
-            break;
-        }
+  Return *noMoreCommandsP true iff the next command is a quit command of
+  there is no next command.
+-----------------------------------------------------------------------------*/
+    static state_info state;
 
-        if (i_args[0] < 1 || i_args[0] > PAM_OVERALL_MAXVAL) {
-            pm_errormsg("error: invalid new maxval: line %lu.",
-                        line->number);
+    Token nt;
 
-            break;
-        }
+    long int iArgs[MAX_NUM_ATTRIBS];
+        /* For storing potential integer arguments. */
+    bool unrecognizedCmd;
+        /* Unrecognized command detected */
+    bool noMoreCommands;
+    const char * error;
+        /* Description of problem with the command; NULL if no problem.
+           Meaningful only when 'unrecognizedCmd' is false.
+        */
 
-        if (i_args[1] < 1 || i_args[1] > MAX_NUM_ATTRIBS) {
-            pm_errormsg("error: invalid new number of generic vertex "
-                        "attributes: line %lu.", line->number);
+    if (!state.initialized) {
+        initState(&state);
+        clearAttribs(&state, fbiP->maxval, fbiP->num_attribs);
 
-            break;
-        }
+        state.initialized = true;
+    }
 
-        nt = next_token(nt.end);
+    {
+        int eof;
+        size_t lineLen;
 
-        if (*nt.begin != '\0') {
-            if (!set_tupletype(nt.begin, fbi->outpam.tuple_type)) {
-                pm_message("warning: could not set new tuple type; "
-                           "using a null string: line %lu.",
-                           line->number);
+        pm_getline(stdin, &inputP->buffer, &inputP->length, &eof, &lineLen);
 
-                set_tupletype(NULL, fbi->outpam.tuple_type);
-            }
-        } else {
-            set_tupletype(NULL, fbi->outpam.tuple_type);
+        if (eof) {
+            *noMoreCommandsP = true;
+            return;
         }
+    }
 
-        if (!realloc_image_buffer(i_args[0], i_args[1], fbi)) {
-            pm_errormsg
-                (
-                    "fatal error upon reading line %lu: "
-                    "could not reallocate image buffer -- "
-                    "terminating pamtris.",
-                    line->number
-                    );
+    removeComments(inputP->buffer);
 
-            return 0;
-        }
+    nt = nextToken(inputP->buffer);
 
-        state.next = 0;
-        state.draw = false;
+    makeLowercase(nt);
 
-        clear_attribs(&state, fbi->maxval, fbi->num_attribs);
+    noMoreCommands = false;  /* initial assumption */
 
-    } break;
+    pm_message("command '%s'", nt.begin);
+    switch (nt.begin[0]) {
+    case 'm':
+        processM(&nt, &state, &unrecognizedCmd, &error);
+        break;
+    case 'a':
+        processA(&nt, &state, fbiP, &unrecognizedCmd, iArgs, &error);
+        break;
+    case 'v':
+        processV(&nt, &state, biP, fbiP, &unrecognizedCmd, iArgs, &error);
+        break;
+    case 'p':
+        processP(&nt, fbiP, &unrecognizedCmd, &error);
+        break;
+    case '!':
+        processExcl(&nt, fbiP, &unrecognizedCmd, &error);
+        break;
+    case 'c':
+        processC(&nt, fbiP, &unrecognizedCmd, &error);
+        break;
+    case '*':
+        processAsterisk(&nt, fbiP, &unrecognizedCmd, &error);
+        break;
+    case 'r':
+        processR(&nt, &state, fbiP, &unrecognizedCmd, iArgs, &error);
+        break;
     case 'q':
-        if (!string_is_valid(CMD_QUIT, nt.begin, nt.end)) {
-            unrecognized_cmd = true;
-
-            break;
-        }
-
-        return 0;
+        processQ(&nt, &unrecognizedCmd, &noMoreCommands, &error);
+        break;
     case '\0':
         break;
     default:
-        unrecognized_cmd = true;
+        unrecognizedCmd = true;
     }
 
-    {
-        char const next = *next_token(nt.end).begin;
+    if (!noMoreCommands) {
+        char const next = *nextToken(nt.end).begin;
 
-        if (unrecognized_cmd) {
+        if (unrecognizedCmd) {
             pm_errormsg("error: unrecognized command: line %lu.",
-                        line->number);
-        }
-        else if (ok && next != '\0') {
-            pm_message(WARNING_EXCESS_ARGS, line->number);
+                        inputP->number);
+        } else {
+            if (error) {
+                pm_errormsg("Error in line %lu: %s", inputP->number, error);
+                pm_strfree(error);
+            } else {
+                if (next != '\0')
+                    pm_message(WARNING_EXCESS_ARGS, inputP->number);
+            }
         }
     }
-    line->number++;
+    ++inputP->number;
 
-    return 1;
+    *noMoreCommandsP = noMoreCommands;
 }
 
 
diff --git a/generator/pamtris/input.h b/generator/pamtris/input.h
index 66969bb2..d34de3a1 100644
--- a/generator/pamtris/input.h
+++ b/generator/pamtris/input.h
@@ -6,26 +6,22 @@
 struct boundary_info;
 struct framebuffer_info;
 
-typedef struct input_info {
-/*----------------------------------------------------------------------------
-  Information necessary for the "process_next_command" function.  It must be
-  initialized through "init_input_processor" and freed by
-  "free_input_processor".
------------------------------------------------------------------------------*/
+typedef struct {
     char *   buffer;
     size_t   length;
     uint64_t number;
-} input_info;
+} Input;
 
 void
-init_input_processor(input_info * const ii);
+input_init(Input * const inputP);
 
 void
-free_input_processor(input_info * const ii);
+input_term(Input * const inputP);
 
-int
-process_next_command(input_info *              const ii,
-                     struct boundary_info *    const bdi,
-                     struct framebuffer_info * const fbi);
+void
+input_process_next_command(Input *                   const inputP,
+                           struct boundary_info *    const bdiP,
+                           struct framebuffer_info * const fbiP,
+                           bool *                    const noMoreCommandsP);
 
 #endif
diff --git a/generator/pamtris/limits_pamtris.h b/generator/pamtris/limits_pamtris.h
index dcf1f1e6..a7ed503f 100644
--- a/generator/pamtris/limits_pamtris.h
+++ b/generator/pamtris/limits_pamtris.h
@@ -1,7 +1,11 @@
 #ifndef LIMITS_H_INCLUDED
 #define LIMITS_H_INCLUDED
 
-#define MAX_NUM_ATTRIBS     20
-#define MAX_Z           ((1 << 30) - 1)
+#define MAX_NUM_ATTRIBS 20
+#define MAX_COORD       32767
+#define MIN_COORD       (-MAX_COORD)
+#define MAX_INPUT_W     1048575
+#define MIN_INPUT_W     1
+#define MAX_Z           0x3FFFFFFF
 
 #endif
diff --git a/generator/pamtris/pamtris.c b/generator/pamtris/pamtris.c
index 74663531..e0becf7a 100644
--- a/generator/pamtris/pamtris.c
+++ b/generator/pamtris/pamtris.c
@@ -29,19 +29,21 @@ parse_command_line(int *         const argc_ptr,
         /* Instructions to pm_optParseOptions3 on how to parse our options */
     unsigned int option_def_index;
 
-    char * tupletype_ptr;
+    char * tupletype_tmp;
 
-    unsigned int width_spec, height_spec, maxval_spec, attribs_spec;
-    unsigned int tupletype_spec;
+    unsigned int width_spec, height_spec, attribs_spec, tupletype_spec;
+    unsigned int rgb_spec, grayscale_spec, maxval_spec;
 
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;  /* incremented by OPTENT3 */
     OPTENT3(0, "width",       OPT_INT,    width,          &width_spec,      0);
     OPTENT3(0, "height",      OPT_INT,    height,         &height_spec,     0);
-    OPTENT3(0, "maxval",      OPT_INT,    maxval,         &maxval_spec,     0);
     OPTENT3(0, "num_attribs", OPT_INT,    num_attribs,    &attribs_spec,    0);
-    OPTENT3(0, "tupletype",   OPT_STRING, &tupletype_ptr, &tupletype_spec,  0);
+    OPTENT3(0, "tupletype",   OPT_STRING, &tupletype_tmp, &tupletype_spec,  0);
+    OPTENT3(0, "rgb",         OPT_FLAG,   NULL,           &rgb_spec,        0);
+    OPTENT3(0, "grayscale",   OPT_FLAG,   NULL,           &grayscale_spec,  0);
+    OPTENT3(0, "maxval",      OPT_INT,    maxval,         &maxval_spec,     0);
 
     opt.opt_table     = option_def;
     opt.short_allowed = false;
@@ -49,9 +51,17 @@ parse_command_line(int *         const argc_ptr,
 
     pm_optParseOptions3(argc_ptr, (char **)argv, opt, sizeof(opt), 0);
 
-    if (!width_spec || !height_spec || !attribs_spec) {
+    if (!width_spec || !height_spec || (!attribs_spec && !(rgb_spec || grayscale_spec))) {
         pm_errormsg(
-            "you must at least specify -width, -height and -num_attribs.");
+            "you must at least specify -width, -height and "
+	    "either -num_attribs, -rgb or -grayscale.");
+
+        return 0;
+    }
+
+    if (rgb_spec + grayscale_spec + attribs_spec != 1) {
+        pm_errormsg("you must provide either only -num_attribs, "
+                    "-rgb or -grayscale; not a combination of those.");
 
         return 0;
     }
@@ -70,8 +80,6 @@ parse_command_line(int *         const argc_ptr,
 
     if (maxval_spec) {
         if (*maxval < 1 || *maxval > PAM_OVERALL_MAXVAL) {
-
-
             pm_errormsg("invalid maxval.");
 
             return 0;
@@ -80,6 +88,16 @@ parse_command_line(int *         const argc_ptr,
         *maxval = 255;
     }
 
+    if (rgb_spec) {
+        *num_attribs = 3;
+        set_tupletype("RGB_ALPHA", tupletype);
+    }
+
+    if (grayscale_spec) {
+        *num_attribs = 1;
+        set_tupletype("GRAYSCALE_ALPHA", tupletype);
+    }
+
     if (*num_attribs < 1 || *num_attribs > MAX_NUM_ATTRIBS) {
         pm_errormsg("invalid number of generic attributes per vertex.");
 
@@ -87,8 +105,15 @@ parse_command_line(int *         const argc_ptr,
     }
 
     if (tupletype_spec) {
-        if (!set_tupletype(tupletype_ptr, tupletype)) {
-            pm_errormsg("warning: invalid tuple type; using the null string.");
+        if(rgb_spec || grayscale_spec) {
+            pm_errormsg("you may not provide -tupletype together with "
+                        "-rgb or -grayscale.");
+
+            return 0;
+        }
+
+        if (!set_tupletype(tupletype_tmp, tupletype)) {
+            pm_errormsg("warning: invalid tuple type; using empty string.");
 
             set_tupletype(NULL, tupletype);
         }
@@ -106,15 +131,20 @@ main(int argc, const char ** argv) {
 
     framebuffer_info fbi;
     boundary_info bi;
-    input_info ii;
+    Input input;
+    bool no_more_commands;
 
     pm_proginit(&argc, (const char**)argv);
 
     set_tupletype(NULL, fbi.outpam.tuple_type);
 
-    if (!parse_command_line(&argc, argv,
-                            &fbi.width, &fbi.height, &fbi.maxval,
-                            &fbi.num_attribs, fbi.outpam.tuple_type)) {
+    if (!parse_command_line(&argc,
+                            argv,
+                            &fbi.width,
+                            &fbi.height,
+                            &fbi.maxval,
+                            &fbi.num_attribs,
+                            fbi.outpam.tuple_type)) {
         return 1;
     }
 
@@ -126,11 +156,12 @@ main(int argc, const char ** argv) {
 
     init_boundary_buffer(&bi, fbi.height);
 
-    init_input_processor(&ii);
+    input_init(&input);
 
-    while (process_next_command(&ii, &bi, &fbi));
+    for (no_more_commands = false; !no_more_commands; )
+        input_process_next_command(&input, &bi, &fbi, &no_more_commands);
 
-    free_input_processor(&ii);
+    input_term(&input);
     free_boundary_buffer(&bi);
     free_framebuffer(&fbi);
 
diff --git a/generator/pamtris/triangle.c b/generator/pamtris/triangle.c
index 09d821e0..5143f9ee 100644
--- a/generator/pamtris/triangle.c
+++ b/generator/pamtris/triangle.c
@@ -9,7 +9,7 @@
 #include "netpbm/mallocvar.h"
 
 #include "utils.h"
-#include "fract.h"
+#include "varying.h"
 #include "boundaries.h"
 #include "framebuffer.h"
 
@@ -17,29 +17,30 @@
 
 static void
 draw_partial_triangle(
-    const fract *         const left_attribs_input,
-    const fract *         const left_attribs_steps,
-    const fract *         const rght_attribs_input,
-    const fract *         const rght_attribs_steps,
-    int32_t               const left_div,
-    int32_t               const rght_div,
+    const varying *       const left_attribs_input,
+    const varying *       const rght_attribs_input,
     bool                  const upper_part,
     const boundary_info * const bi,
     framebuffer_info *    const fbi) {
 
-    uint8_t const num_planes = fbi->num_attribs + 1;
+    uint8_t const z = fbi->num_attribs;
+    uint8_t const w = z + 1;
+    uint8_t const n = w + 1;
 
-    fract * left_attribs;
-    fract * rght_attribs;
+    varying * left_attribs;
+    varying * rght_attribs;
+
+    varying * attribs;
 
     int32_t first_row_index;
     int32_t last_row_index;
 
-    MALLOCARRAY_NOFAIL(left_attribs, num_planes);
-    MALLOCARRAY_NOFAIL(rght_attribs, num_planes);
+    MALLOCARRAY_NOFAIL(left_attribs, n);
+    MALLOCARRAY_NOFAIL(rght_attribs, n);
+    MALLOCARRAY_NOFAIL(attribs, n);
 
-    memcpy(left_attribs, left_attribs_input, num_planes * sizeof(fract));
-    memcpy(rght_attribs, rght_attribs_input, num_planes * sizeof(fract));
+    memcpy(left_attribs, left_attribs_input, n * sizeof(varying));
+    memcpy(rght_attribs, rght_attribs_input, n * sizeof(varying));
 
     if (upper_part) {
         first_row_index = 0;
@@ -57,41 +58,26 @@ draw_partial_triangle(
         int32_t left_boundary;
         int32_t rght_boundary;
 
-        for (row = first_row_index; row <= last_row_index; ) {
+        for (row = first_row_index; row <= last_row_index; row++) {
             get_triangle_boundaries(row, &left_boundary, &rght_boundary, bi);
             {
                 int32_t const column_delta = rght_boundary - left_boundary;
                 int32_t start_column;
                 int32_t span_length;
 
-                fract   * attribs_start;
-                int32_t * attribs_begin;
-                int32_t * attribs_end;
-                fract   * attribs_steps;
-
-                MALLOCARRAY_NOFAIL(attribs_start, num_planes);
-                MALLOCARRAY_NOFAIL(attribs_begin, num_planes);
-                MALLOCARRAY_NOFAIL(attribs_end,   num_planes);
-                MALLOCARRAY_NOFAIL(attribs_steps, num_planes);
-
                 start_column = left_boundary;  /* initial value */
                 span_length = column_delta;    /* initial value */
 
-                fract_to_int32_array(left_attribs, attribs_begin, num_planes);
-                fract_to_int32_array(rght_attribs, attribs_end, num_planes);
-
-                int32_to_fract_array(attribs_begin, attribs_start, num_planes);
-
-                gen_steps(attribs_begin, attribs_end, attribs_steps,
-                          num_planes, column_delta);
+                prepare_for_interpolation(left_attribs, rght_attribs,
+                                          attribs, column_delta,
+                                          n);
 
                 if (left_boundary < 0) {
                     start_column = 0;
 
                     span_length += left_boundary;
 
-                    multi_step_up(attribs_start, attribs_steps, num_planes,
-                                  -left_boundary, column_delta);
+                    multi_step_up(attribs, -left_boundary, n);
                 }
 
                 if (rght_boundary >= fbi->width) {
@@ -101,24 +87,17 @@ draw_partial_triangle(
                 }
 
                 draw_span(
-                    ((bi->start_scanline + row) * fbi->width) + start_column,
-                    span_length, attribs_start, attribs_steps, column_delta,
-                    fbi);
+                    (bi->start_scanline + row) * fbi->width + start_column,
+                    span_length, attribs, fbi);
 
                 if (row_delta > 0) {
-                    step_up(left_attribs, left_attribs_steps, num_planes,
-                            left_div);
-                    step_up(rght_attribs, rght_attribs_steps, num_planes,
-                            rght_div);
+                    step_up(left_attribs, n);
+                    step_up(rght_attribs, n);
                 }
-                row++;
-                free(attribs_steps);
-                free(attribs_end);
-                free(attribs_begin);
-                free(attribs_start);
             }
         }
     }
+    free(attribs);
     free(rght_attribs);
     free(left_attribs);
 }
@@ -127,31 +106,19 @@ draw_partial_triangle(
 
 static void
 draw_degenerate_horizontal(Xy                 const xy,
-                           fract *            const attribs_left,
-                           fract *            const attribs_mid,
-                           const fract *      const top2mid_steps,
-                           const fract *      const top2bot_steps,
-                           const fract *      const mid2bot_steps,
-                           int32_t            const top2mid_delta,
-                           int32_t            const top2bot_delta,
-                           int32_t            const mid2bot_delta,
+                           varying *          const top2mid,
+                           varying *          const top2bot,
+                           varying *          const mid2bot,
                            framebuffer_info * const fbi) {
 
-    uint8_t const num_planes = fbi->num_attribs + 1;
-
-    fract * attribs_left_bkup;
-
-    MALLOCARRAY_NOFAIL(attribs_left_bkup, num_planes);
-
-    memcpy(attribs_left_bkup, attribs_left, num_planes * sizeof(fract));
+    uint8_t const n = fbi->num_attribs + 2;
 
     {
         int16_t const y = xy._[0][1];
 
         int16_t x[3];
         int16_t x_start[3];
-        fract * attribs[3];
-        const fract * steps[3];
+        varying * attribs[3];
         int32_t span_length[3];
         unsigned int i;
 
@@ -163,28 +130,21 @@ draw_degenerate_horizontal(Xy                 const xy,
         x_start[1] = x[0];
         x_start[2] = x[1];
 
-        attribs[0] = attribs_left;
-        attribs[1] = attribs_left_bkup;
-        attribs[2] = attribs_mid;
-
-        steps[0] = top2bot_steps;
-        steps[1] = top2mid_steps;
-        steps[2] = mid2bot_steps;
+        attribs[0] = top2bot;
+        attribs[1] = top2mid;
+        attribs[2] = mid2bot;
 
         span_length[0] = x[2] - x[0];
         span_length[1] = x[1] - x[0];
         span_length[2] = x[2] - x[1];
 
         for (i = 0; i < 3; i++) {
-            int32_t const column_delta = span_length[i];
-
             if (x_start[i] >= fbi->width || x_start[i] + span_length[i] < 0) {
                 continue;
             }
 
             if (x_start[i] < 0) {
-                multi_step_up(attribs[i], steps[i], num_planes, -x_start[i],
-                              column_delta);
+                multi_step_up(attribs[i], -x_start[i], n);
 
                 span_length[i] += x_start[i];
 
@@ -197,11 +157,10 @@ draw_degenerate_horizontal(Xy                 const xy,
                 span_length[i]++;
             }
 
-            draw_span((y * fbi->width) + x_start[i], span_length[i],
-                      attribs[i], steps[i], column_delta, fbi);
+            draw_span(y * fbi->width + x_start[i], span_length[i],
+                      attribs[i], fbi);
         }
     }
-    free(attribs_left_bkup);
 }
 
 
@@ -212,23 +171,28 @@ draw_triangle(Xy                 const xy_input,
               boundary_info *    const bi,
               framebuffer_info * const fbi) {
 
-    uint8_t const num_planes = fbi->num_attribs + 1;
+    uint8_t const z = fbi->num_attribs;
+    uint8_t const w = z + 1;
+    uint8_t const n = w + 1;
 
     Xy xy;
-    int32_t * attribs[3];
+    varying * attribs[3];
     unsigned int i;
     uint8_t index_array[3];
     int32_t y_array[3];
     int32_t x_array[3];
 
-    MALLOCARRAY_NOFAIL(attribs[0], num_planes);
-    MALLOCARRAY_NOFAIL(attribs[1], num_planes);
-    MALLOCARRAY_NOFAIL(attribs[2], num_planes);
+    MALLOCARRAY_NOFAIL(attribs[0], n);
+    MALLOCARRAY_NOFAIL(attribs[1], n);
+    MALLOCARRAY_NOFAIL(attribs[2], n);
 
     xy = xy_input;
 
     for (i = 0; i < 3; i++) {
-        memcpy(attribs[i], attribs_input._[i], num_planes * sizeof(int32_t));
+        int32_to_varying_array(attribs_input._[i], attribs[i], n);
+	attribs[i][z] = compute_varying_z(attribs_input._[i][z]);
+	attribs[i][w] = inverse_varying(attribs[i][w]);
+        multiply_varying_array_by_varying(attribs[i], attribs[i][w], z);
     }
 
     /* Argument preparations for sort3: */
@@ -259,122 +223,65 @@ draw_triangle(Xy                 const xy_input,
             gen_triangle_boundaries(xy_sorted, bi, fbi->width, fbi->height);
 
         if (bi->start_scanline == -1) {
-            /* Triangle is completely out of the bounds of the framebuffer. */
+            /* Triangle is completely out of the bounds of the frame buffer. */
         } else {
             bool const no_upper_part =
                 (xy_sorted._[1][1] == xy_sorted._[0][1]);
 
             bool const horizontal =
                 (xy._[0][1] == xy._[1][1] && xy._[1][1] == xy._[2][1]);
-                /* We are dealing with a degenerate horizontal triangle */
+                /* Tells whether we are dealing with a degenerate
+                 * horizontal triangle */
 
-            uint8_t t = ~horizontal & 1;
+            uint8_t const t = horizontal ^ 1;
 
             int32_t top2mid_delta = xy._[mid][t] - xy._[top][t];
             int32_t top2bot_delta = xy._[bot][t] - xy._[top][t];
             int32_t mid2bot_delta = xy._[bot][t] - xy._[mid][t];
 
-            fract * top2mid_steps;
-            fract * top2bot_steps;
-            fract * mid2bot_steps;
+            varying * top2mid;
+            varying * top2bot;
+            varying * mid2bot;
 
-            fract * upper_left_attribs_steps;
-            fract * lower_left_attribs_steps;
-            fract * upper_rght_attribs_steps;
-            fract * lower_rght_attribs_steps;
+            varying * upper_left_attribs;
+            varying * lower_left_attribs;
+            varying * upper_rght_attribs;
+            varying * lower_rght_attribs;
 
-            int32_t upper_left_delta;
-            int32_t lower_left_delta;
-            int32_t upper_rght_delta;
-            int32_t lower_rght_delta;
+            MALLOCARRAY_NOFAIL(top2mid, n);
+            MALLOCARRAY_NOFAIL(top2bot, n);
+            MALLOCARRAY_NOFAIL(mid2bot, n);
 
-            fract * left_attribs;
-            fract * rght_attribs;
-
-            bool degenerate_horizontal;
-
-            MALLOCARRAY_NOFAIL(top2mid_steps, num_planes);
-            MALLOCARRAY_NOFAIL(top2bot_steps, num_planes);
-            MALLOCARRAY_NOFAIL(mid2bot_steps, num_planes);
-            MALLOCARRAY_NOFAIL(left_attribs, num_planes);
-            MALLOCARRAY_NOFAIL(rght_attribs, num_planes);
-
-            if (!horizontal) {
-                top2mid_delta += !no_upper_part;
-                top2bot_delta += 1;
-                mid2bot_delta += no_upper_part;
-            }
-
-            gen_steps(attribs[top], attribs[mid], top2mid_steps, num_planes,
-                      top2mid_delta);
-            gen_steps(attribs[top], attribs[bot], top2bot_steps, num_planes,
-                      top2bot_delta);
-            gen_steps(attribs[mid], attribs[bot], mid2bot_steps, num_planes,
-                      mid2bot_delta);
-
-            int32_to_fract_array(attribs[top], left_attribs, num_planes);
-            int32_to_fract_array(attribs[top], rght_attribs, num_planes);
+            prepare_for_interpolation(attribs[top], attribs[mid], top2mid, top2mid_delta, n);
+            prepare_for_interpolation(attribs[top], attribs[bot], top2bot, top2bot_delta, n);
+            prepare_for_interpolation(attribs[mid], attribs[bot], mid2bot, mid2bot_delta, n);
 
             if (mid_is_to_the_left) {
-                upper_left_attribs_steps = top2mid_steps;
-                lower_left_attribs_steps = mid2bot_steps;
-                upper_rght_attribs_steps = top2bot_steps;
-                lower_rght_attribs_steps = upper_rght_attribs_steps;
-
-                upper_left_delta = top2mid_delta;
-                lower_left_delta = mid2bot_delta;
-                upper_rght_delta = top2bot_delta;
-                lower_rght_delta = upper_rght_delta;
+                upper_left_attribs = top2mid;
+                lower_left_attribs = mid2bot;
+                upper_rght_attribs = top2bot;
+                lower_rght_attribs = upper_rght_attribs;
             } else {
-                upper_rght_attribs_steps = top2mid_steps;
-                lower_rght_attribs_steps = mid2bot_steps;
-                upper_left_attribs_steps = top2bot_steps;
-                lower_left_attribs_steps = upper_left_attribs_steps;
-
-                upper_rght_delta = top2mid_delta;
-                lower_rght_delta = mid2bot_delta;
-                upper_left_delta = top2bot_delta;
-                lower_left_delta = upper_left_delta;
+                upper_rght_attribs = top2mid;
+                lower_rght_attribs = mid2bot;
+                upper_left_attribs = top2bot;
+                lower_left_attribs = upper_left_attribs;
             }
 
-            if (no_upper_part) {
-                int32_to_fract_array(attribs[mid], rght_attribs, num_planes);
-
-                if (horizontal) {
-                    degenerate_horizontal = true;
-                } else {
-                    degenerate_horizontal = false;
-
-                    step_up(left_attribs, lower_left_attribs_steps, num_planes,
-                            lower_left_delta);
-                    step_up(rght_attribs, lower_rght_attribs_steps, num_planes,
-                            lower_rght_delta);
-                }
-            } else {
+            if (!(horizontal || no_upper_part)) {
                 int32_t delta;
 
-                degenerate_horizontal = false;
-
-                step_up(left_attribs, upper_left_attribs_steps, num_planes,
-                        upper_left_delta);
-                step_up(rght_attribs, upper_rght_attribs_steps, num_planes,
-                        upper_rght_delta);
-
                 if (bi->num_upper_rows > 0) {
-
                     if (bi->start_scanline > xy._[top][1]) {
                         delta = bi->start_scanline - xy._[top][1];
 
-                        multi_step_up(left_attribs, upper_left_attribs_steps,
-                                      num_planes, delta, upper_left_delta);
-                        multi_step_up(rght_attribs, upper_rght_attribs_steps,
-                                      num_planes, delta, upper_rght_delta);
+                        multi_step_up(upper_left_attribs, delta, n);
+                        multi_step_up(upper_rght_attribs, delta, n);
                     }
 
                     draw_partial_triangle(
-                        left_attribs, upper_left_attribs_steps,
-                        rght_attribs, upper_rght_attribs_steps,
-                        upper_left_delta, upper_rght_delta,
+                        upper_left_attribs,
+                        upper_rght_attribs,
                         true,
                         bi,
                         fbi
@@ -385,40 +292,33 @@ draw_triangle(Xy                 const xy_input,
                     delta = top2mid_delta;
                 }
 
-                multi_step_up(left_attribs, upper_left_attribs_steps,
-                              num_planes, delta, upper_left_delta);
-                multi_step_up(rght_attribs, upper_rght_attribs_steps,
-                              num_planes, delta, upper_rght_delta);
+                multi_step_up(upper_left_attribs, delta, n);
+                multi_step_up(upper_rght_attribs, delta, n);
             }
-            if (degenerate_horizontal) {
+
+            if (horizontal) {
                 draw_degenerate_horizontal(
                     xy_sorted,
-                    left_attribs, rght_attribs,
-                    top2mid_steps, top2bot_steps, mid2bot_steps,
-                    top2mid_delta, top2bot_delta, mid2bot_delta,
+                    top2mid, top2bot, mid2bot,
                     fbi
                     );
             } else {
                 if (bi->start_scanline > xy._[mid][1]) {
                     int32_t const delta = bi->start_scanline - xy._[mid][1];
 
-                    multi_step_up(left_attribs, lower_left_attribs_steps,
-                                  num_planes, delta, lower_left_delta);
-                    multi_step_up(rght_attribs, lower_rght_attribs_steps,
-                                  num_planes, delta, lower_rght_delta);
+                    multi_step_up(lower_left_attribs, delta, n);
+                    multi_step_up(lower_rght_attribs, delta, n);
                 }
 
                 draw_partial_triangle(
-                    left_attribs, lower_left_attribs_steps,
-                    rght_attribs, lower_rght_attribs_steps,
-                    lower_left_delta, lower_rght_delta,
+                    lower_left_attribs,
+                    lower_rght_attribs,
                     false,
                     bi,
                     fbi
                     );
             }
-            free(rght_attribs); free(left_attribs);
-            free(mid2bot_steps); free(top2bot_steps); free(top2mid_steps);
+            free(mid2bot); free(top2bot); free(top2mid);
         }
     }
     free(attribs[2]); free(attribs[1]); free(attribs[0]);
diff --git a/generator/pamtris/triangle.h b/generator/pamtris/triangle.h
index 79178ad0..e043e95c 100644
--- a/generator/pamtris/triangle.h
+++ b/generator/pamtris/triangle.h
@@ -13,7 +13,7 @@ typedef struct {
 } Xy;
 
 typedef struct {
-    int32_t _[3][MAX_NUM_ATTRIBS + 1];
+    int32_t _[3][MAX_NUM_ATTRIBS + 2];
 } Attribs;
 
 void
diff --git a/generator/pamtris/utils.c b/generator/pamtris/utils.c
index 09c9b4d0..a6b6e7d4 100644
--- a/generator/pamtris/utils.c
+++ b/generator/pamtris/utils.c
@@ -6,171 +6,181 @@
 
 #include <stdlib.h>
 #include <stdint.h>
+#include <math.h>
 
-#include "fract.h"
+#include "limits_pamtris.h"
+#include "varying.h"
 
 #include "utils.h"
 
 
 
 void
-step_up(fract *       const vars,
-        const fract * const steps,
-        uint8_t       const element_ct,
-        int32_t       const divisor) {
-/*----------------------------------------------------------------------------
-  Apply interpolation steps steps[] to a collection of fract variables vars[]
-  once.  I.e. add each steps[i] to vars[i].
+prepare_for_interpolation(const varying * const begin,
+                          const varying * const end,
+                          varying *       const out,
+                          int32_t               num_steps,
+                          uint8_t         const elements) {
 
-  'element_ct' is the number of elements in 'vars' and 'steps'.
+    double inverse_num_steps;
+    unsigned int i;
 
-  'divisor' is the divisor used to interpret the fractions.
+    if (num_steps < 1) {
+        num_steps = 1;
+    }
 
-  It *is* safe to pass a 0 divisor to this function.
------------------------------------------------------------------------------*/
-    unsigned int i;
+    inverse_num_steps = 1.0 / num_steps;
 
-    for (i = 0; i < element_ct; ++i) {
-        /* To add the fraction steps[i] to the fraction vars[i]: add the
-           quotient of step steps[i] to the quotient of variable vars[i] and
-           the remainder of the step to the remainder of the variable. If this
-           makes the agumented remainder equal to or larger than the divisor,
-           increment the quotient of the variable if the step is positive or
-           decrement it if the step is negative, and subtract the divisor from
-           the remainder of the variable (in either case).
-        */
+    for (i = 0; i < elements; i++) {
+        out[i].v = begin[i].v;
+        out[i].s = (end[i].v - begin[i].v) * inverse_num_steps;
+    }
+}
 
-        vars[i].q += steps[i].q;
-        vars[i].r += steps[i].r;
 
-        {
-            uint32_t const negative_mask = -steps[i].negative_flag;
-                /* (-1 if the step is negative; 1 otherwise) */
 
-            uint32_t const overdiv_mask =
-                -(((uint32_t)~(vars[i].r - divisor)) >> 31);
-                /*  = ~0 if var->r >= div; 0 otherwise. */
+varying
+compute_varying_z(int32_t const input_z) {
 
-            vars[i].q += (negative_mask | 1) & overdiv_mask;
-            vars[i].r -= divisor & overdiv_mask;
-        }
-    }
+    varying retval;
+
+    retval.v = 1.0 / (1 + input_z - MIN_COORD);
+    retval.s = 0.0;
+
+    return retval;
 }
 
 
 
 void
-multi_step_up(fract *       const vars,
-              const fract * const steps,
-              uint8_t       const elements,
-              int32_t       const times,
-              int32_t       const div) {
-/*----------------------------------------------------------------------------
-  Similar to step_up, but apply the interpolation step an arbitrary number
-  of times, instead of just once.
+multiply_varying_array_by_varying(varying * const vars,
+                                  varying   const multiplier,
+                                  uint8_t   const elements) {
 
-  It *is* also safe to pass a 0 divisor to this function.
------------------------------------------------------------------------------*/
     unsigned int i;
 
     for (i = 0; i < elements; i++) {
-        uint32_t const negative_mask = -steps[i].negative_flag;
+        vars[i].v *= multiplier.v;
+	vars[i].s  = 0.0;
+    }
+}
 
-        vars[i].q += times * steps[i].q;
-        vars[i].r += times * steps[i].r;
 
-        if(vars[i].r >= div && div != 0) {
-            int32_t const r_q = vars[i].r / div;
-            int32_t const r_r = vars[i].r % div;
+void
+divide_varying_array_by_varying(varying * const vars,
+                                varying   const divisor,
+                                uint8_t   const elements) {
 
-            vars[i].q += (-r_q & negative_mask) | (r_q & ~negative_mask);
-                /* = -r_q if the step is negative; r_q, otherwise. */
-            vars[i].r = r_r;
-        }
+    double const inverse_divisor = 1.0 / divisor.v;
+
+    unsigned int i;
+
+    for (i = 0; i < elements; i++) {
+        vars[i].v *= inverse_divisor;
+	vars[i].s  = 0.0;
     }
 }
 
 
 
-void
-gen_steps(const int32_t * const begin,
-          const int32_t * const end,
-          fract         * const out,
-          uint8_t         const elements,
-          int32_t         const div) {
-/*----------------------------------------------------------------------------
-  Generate the interpolation steps for a collection of initial and final
-  values. "begin" points to an array of initial values, "end" points to the
-  array of corresponding final values; each interpolation step is stored in
-  the appropriate position in the array pointed by "out"; "elements" indicates
-  the number of elements in each of the previously mentioned arrays and
-  "divisor" is the common value by which we want to divide the difference
-  between each element in the array pointed to by "end" and the corresponding
-  element in the array pointed to by "begin".  After an execution of this
-  function, for each out[i], with 0 <= i < elements, the following will hold:
-
-    1. If divisor > 1:
-      out[i].q = (end[i] - begin[i]) / divisor
-      out[i].r = abs((end[i] - begin[i]) % divisor)
-
-    2. If divisor == 1 || divisor == 0:
-      out[i].q = end[i] - begin[i]
-      out[i].r = 0
------------------------------------------------------------------------------*/
-    if (div > 1) {
-        unsigned int i;
+varying
+inverse_varying(varying const var) {
 
-        for (i = 0; i < elements; i++) {
-            int32_t const delta = end[i] - begin[i];
+    varying retval;
 
-            out[i].q = delta / div;
-            out[i].r = abs(delta % div);
-            out[i].negative_flag = ((uint32_t)delta) >> 31;
-        }
-    } else {
-        unsigned int i;
+    retval.v = 1.0 / var.v;
+    retval.s = 0.0;
 
-        for (i = 0; i < elements; i++) {
-            int32_t const delta = end[i] - begin[i];
+    return retval;
+}
 
-            out[i].q = delta;
-            out[i].r = 0;
-            out[i].negative_flag = ((uint32_t)delta) >> 31;
-        }
+
+
+varying
+multiply_varyings(varying const a,
+                  varying const b) {
+
+    varying retval;
+
+    retval.v = a.v * b.v;
+    retval.s = 0.0;
+
+    return retval;
+}
+
+
+
+void
+step_up(varying * const vars,
+        uint8_t   const elements) {
+
+    unsigned int i;
+
+    for (i = 0; i < elements; i++) {
+        vars[i].v += vars[i].s;
     }
 }
 
 
 
 void
-fract_to_int32_array(const fract * const in,
-                     int32_t *     const out,
-                     uint8_t       const elements) {
+multi_step_up(varying * const vars,
+              int32_t   const times,
+              uint8_t   const elements) {
 
     unsigned int i;
 
     for (i = 0; i < elements; i++) {
-        out[i] = in[i].q;
+        vars[i].v += times * vars[i].s;
     }
 }
 
 
 
 void
-int32_to_fract_array(const int32_t * const in,
-                     fract *         const out,
-                     uint8_t         const elements) {
+int32_to_varying_array(const int32_t * const in,
+                       varying *       const out,
+                       uint8_t         const elements) {
 
     unsigned int i;
 
     for (i = 0; i < elements; i++) {
-        out[i].q = in[i];
-        out[i].r = 0;
+        out[i].v = in[i];
+        out[i].s = 0.0;
     }
 }
 
 
 
+/* static int64_t
+abs64(int64_t x)
+{
+
+    int64_t const nm = ~geq_mask64(x, 0);
+
+    return (-x & nm) | (x & ~nm);
+} */
+
+
+
+int32_t
+round_varying(varying const var) {
+
+    return round(var.v);
+}
+
+
+
+int64_t
+geq_mask64(int64_t a, int64_t b) {
+
+    uint64_t const diff = a - b;
+
+    return -((~diff) >> 63);
+}
+
+
+
 static void
 swap(uint8_t * const a,
      uint8_t * const b) {
diff --git a/generator/pamtris/utils.h b/generator/pamtris/utils.h
index 3b7cfbe4..bd9dcdbe 100644
--- a/generator/pamtris/utils.h
+++ b/generator/pamtris/utils.h
@@ -1,37 +1,54 @@
 #ifndef UTIL_H_INCLUDED
 #define UTIL_H_INCLUDED
 
-#include "fract.h"
+#include "varying.h"
 
 void
-gen_steps(const int32_t * const begin,
-          const int32_t * const end,
-          fract *         const out,
-          uint8_t         const elements,
-          int32_t         const divisor);
+prepare_for_interpolation(const varying * const begin,
+                          const varying * const end,
+                          varying *       const out,
+                          int32_t               num_steps,
+                          uint8_t         const elements);
+
+varying
+compute_varying_z(int32_t const input_z);
 
 void
-step_up(fract *       const vars,
-        const fract * const steps,
-        uint8_t       const elements,
-        int32_t       const divisor);
+multiply_varying_array_by_varying(varying * const vars,
+                                  varying   const divisor,
+                                  uint8_t   const elements);
 
 void
-multi_step_up(fract *       const vars,
-              const fract * const steps,
-              uint8_t       const elements,
-              int32_t       const times,
-              int32_t       const divisor);
+divide_varying_array_by_varying(varying * const vars,
+                                varying   const divisor,
+                                uint8_t   const elements);
+
+varying
+inverse_varying(varying const var);
+
+varying
+multiply_varyings(varying const a,
+                  varying const b);
 
 void
-fract_to_int32_array(const fract * const in,
-                     int32_t     * const out,
-                     uint8_t       const elements);
+step_up(varying * const vars,
+       uint8_t    const elements);
 
 void
-int32_to_fract_array(const int32_t * const in,
-                     fract *         const out,
-                     uint8_t         const elements);
+multi_step_up(varying * const vars,
+             int32_t    const times,
+             uint8_t    const elements);
+
+void
+int32_to_varying_array(const int32_t * const in,
+                       varying *       const out,
+                       uint8_t         const elements);
+
+int32_t
+round_varying(varying const var);
+
+int64_t
+geq_mask64(int64_t a, int64_t b);
 
 void
 sort3(uint8_t *       const index_array,
diff --git a/generator/pamtris/varying.h b/generator/pamtris/varying.h
new file mode 100644
index 00000000..6605f02d
--- /dev/null
+++ b/generator/pamtris/varying.h
@@ -0,0 +1,12 @@
+#ifndef VARYING_H_INCLUDED
+#define VARYING_H_INCLUDED
+
+#include <stdint.h>
+
+
+typedef struct {
+    double v; /* Value */
+    double s; /* Step */
+} varying;
+
+#endif
diff --git a/generator/pbmtext.c b/generator/pbmtext.c
index e52d5199..e6f27865 100644
--- a/generator/pbmtext.c
+++ b/generator/pbmtext.c
@@ -364,10 +364,11 @@ fixControlChars(const PM_WCHAR  * const input,
                 output[outCursor++] = L' ';
         } else if (currentChar > fontP->maxglyph ||
                    !fontP->glyph[currentChar]) {
-        if (currentChar > PM_FONT2_MAXGLYPH)
-            pm_message("code point %X is beyond what this program "
-                       "can handle.  Max=%X",
-                       (unsigned int)currentChar, PM_FONT2_MAXGLYPH);
+            if (currentChar > PM_FONT2_MAXGLYPH)
+                pm_message("code point %X is beyond what this program "
+                           "can handle.  Max=%X",
+                           (unsigned int)currentChar, PM_FONT2_MAXGLYPH);
+
             /* Turn this unknown char into a single space. */
             if (fontP->glyph[L' '] == NULL)
                 pm_error("space character not defined in font");
diff --git a/lib/colorname.c b/lib/colorname.c
index c4d34fc2..9400adf7 100644
--- a/lib/colorname.c
+++ b/lib/colorname.c
@@ -206,9 +206,10 @@ pm_parse_dictionary_namen(char   const colorname[],
                  (unsigned)strlen(colorname));
 
     pm_canonstr(canoncolor);
-    gotit = FALSE;
-    colorfileExhausted = FALSE;
-    while (!gotit && !colorfileExhausted) {
+
+    for(gotit = FALSE, colorfileExhausted = FALSE;
+        !gotit && !colorfileExhausted; ) {
+
         colorfileEntry = pm_colorget(fP);
         if (colorfileEntry.colorname) {
             pm_canonstr(colorfileEntry.colorname);
diff --git a/lib/libpamcolor.c b/lib/libpamcolor.c
index 49abd063..f9add1a1 100644
--- a/lib/libpamcolor.c
+++ b/lib/libpamcolor.c
@@ -14,10 +14,6 @@
 #define _FILE_OFFSET_BITS 64
 #define _LARGE_FILES
 
-#define _DEFAULT_SOURCE 1  /* New name for SVID & BSD source defines */
-#define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
-#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
-
 #include <string.h>
 #include <limits.h>
 #include <math.h>
@@ -415,8 +411,8 @@ pnm_colorname(struct pam * const pamP,
 
     colorname = ppm_colorname(&colorp, pamP->maxval, hexok);
 
-    retval = strdup(colorname);
-    if (retval == NULL)
+    retval = pm_strdup(colorname);
+    if (retval == pm_strsol)
         pm_error("Couldn't get memory for color name string");
 
     return retval;
diff --git a/lib/libpbmfont0.c b/lib/libpbmfont0.c
index add08047..503c7ee7 100644
--- a/lib/libpbmfont0.c
+++ b/lib/libpbmfont0.c
@@ -216,8 +216,8 @@ pbm_destroybdffont2_base(struct font2 * const font2P) {
 
     free(font2P->selector);
 
-    free(font2P->name);
-    free(font2P->charset_string);
+    pm_strfree(font2P->name);
+    pm_strfree(font2P->charset_string);
     free(font2P->glyph);
 
     if (font2P->oldfont !=NULL)
diff --git a/lib/libpbmfont1.c b/lib/libpbmfont1.c
index 2b0993a9..2d269da7 100644
--- a/lib/libpbmfont1.c
+++ b/lib/libpbmfont1.c
@@ -347,9 +347,9 @@ pbm_loadpbmfont2(const char * const filename) {
     retval->load_fn = LOAD_PBMSHEET;
     retval->default_char = (PM_WCHAR) ' ';
     retval->default_char_defined = TRUE;
-    retval->name = strdup("(PBM sheet font has no name)");
+    retval->name = pm_strdup("(PBM sheet font has no name)");
     retval->charset = ISO646_1991_IRV;
-    retval->charset_string = strdup("ASCII");
+    retval->charset_string = pm_strdup("ASCII");
     retval->total_chars = retval->chars = nCharsInFont;
 
     return(retval);
diff --git a/lib/libpbmfont2.c b/lib/libpbmfont2.c
index 7f168648..b354e91b 100644
--- a/lib/libpbmfont2.c
+++ b/lib/libpbmfont2.c
@@ -653,39 +653,49 @@ static void
 processBdfFontNameLine(Readline     * const readlineP,
                        struct font2 * const font2P) {
 
-    if (font2P->name != NULL)
+    if (font2P->name)  /* We've already processed a FONT line */
         pm_error("Multiple FONT lines in BDF font file");
+    else {
+        char * buffer;
 
-    font2P->name = malloc (MAXBDFLINE+1);
-    if (font2P->name == NULL)
-        pm_error("No memory for font name");
+        MALLOCARRAY(buffer, MAXBDFLINE+1);
 
-    if (readlineP->wordCt == 1)
-        strcpy(font2P->name, "(no name)");
+        if (!buffer)
+            pm_error("Failed to get memory for %u-character font name buffer",
+                     MAXBDFLINE+1);
 
-    else {
-        unsigned int tokenCt;
+        if (readlineP->wordCt == 1)
+            strcpy(buffer, "(no name)");
+
+        else {
+            unsigned int tokenCt;
 
-        font2P->name[0] ='\0';
+            buffer[0] ='\0';
 
-        for (tokenCt=1;
-             tokenCt < ARRAY_SIZE(readlineP->arg) &&
-                 readlineP->arg[tokenCt] != NULL; ++tokenCt) {
-          strcat(font2P->name, " ");
-          strcat(font2P->name, readlineP->arg[tokenCt]);
+            for (tokenCt=1;
+                 tokenCt < ARRAY_SIZE(readlineP->arg) &&
+                     readlineP->arg[tokenCt] != NULL; ++tokenCt) {
+                strcat(buffer, " ");
+                strcat(buffer, readlineP->arg[tokenCt]);
+            }
         }
+        font2P->name = buffer;
     }
 }
 
 
+
 static void
-loadCharsetString(const char * const registry,
-                  const char * const encoding,
-                  char **      const string) {
+loadCharsetString(const char *  const registry,
+                  const char *  const encoding,
+                  const char ** const charsetStringP) {
 
+    char * dest;
     unsigned int inCt, outCt;
-    char * const dest = malloc (strlen(registry) + strlen(encoding) + 1);
-    if (dest == NULL)
+
+    dest = malloc(strlen(registry) + strlen(encoding) + 1);
+
+    if (!dest)
         pm_error("no memory to load CHARSET_REGISTRY and CHARSET_ENCODING "
                "from BDF file");
 
@@ -703,7 +713,7 @@ loadCharsetString(const char * const registry,
     }
 
     dest[outCt] = '\0';
-    *string = dest;
+    *charsetStringP = dest;
 }
 
 
diff --git a/lib/libpm.c b/lib/libpm.c
index b335debb..47a2f498 100644
--- a/lib/libpm.c
+++ b/lib/libpm.c
@@ -9,7 +9,6 @@
 **************************************************************************/
 
 #define _DEFAULT_SOURCE      /* New name for SVID & BSD source defines */
-#define _BSD_SOURCE          /* Make sure strdup is in string.h */
 #define _XOPEN_SOURCE 500    /* Make sure ftello, fseeko are defined */
 
 #include "netpbm/pm_config.h"
@@ -439,7 +438,8 @@ pm_maxvaltobits(int const maxval) {
         return 16;
     else
         pm_error( "maxval of %d is too large!", maxval );
-        return -1;  /* Should never come here */
+
+    assert(false);
 }
 
 int
diff --git a/lib/libppmcolor.c b/lib/libppmcolor.c
index 27340d5f..7079482c 100644
--- a/lib/libppmcolor.c
+++ b/lib/libppmcolor.c
@@ -9,10 +9,6 @@
 ** implied warranty.
 */
 
-#define _DEFAULT_SOURCE 1  /* New name for SVID & BSD source defines */
-#define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
-#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
-
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
@@ -194,9 +190,9 @@ processColorfileEntry(struct colorfile_entry const ce,
             *errorP = NULL;
         } else {
             ppm_addtocolorhash(cht, &color, *colornameIndexP);
-            colornames[*colornameIndexP] = strdup(ce.colorname);
+            colornames[*colornameIndexP] = pm_strdup(ce.colorname);
             colors[*colornameIndexP] = color;
-            if (colornames[*colornameIndexP] == NULL)
+            if (colornames[*colornameIndexP] == pm_strsol)
                 pm_asprintf(errorP, "Unable to allocate space for color name");
             else {
                 *errorP = NULL;
diff --git a/lib/pbmfont.h b/lib/pbmfont.h
index 57f19ddc..c8b3934b 100644
--- a/lib/pbmfont.h
+++ b/lib/pbmfont.h
@@ -251,7 +251,7 @@ struct font2 {
            FALSE: font file has no DEFAULT_CHAR field.
         */
 
-    char * name;
+    const char * name;
         /* Name of the font.  Available in BDF fonts.
            NULL means no name.
         */
@@ -261,7 +261,7 @@ struct font2 {
            Set by analyzing following charset_string.
         */
 
-    char * charset_string;
+    const char * charset_string;
         /* Charset registry and encoding.
            Available in most BDF fonts between STARPROPERTIES - ENDPROPERTIES.
            NULL means no name.
diff --git a/lib/pm.h b/lib/pm.h
index 81647873..3fc92fb4 100644
--- a/lib/pm.h
+++ b/lib/pm.h
@@ -110,10 +110,10 @@ extern int pm_plain_output;
     */
 extern const char * pm_progname;
 
-void 
+void
 pm_init(const char * const progname, unsigned int const flags);
 
-void 
+void
 pm_proginit(int * const argcP, const char * argv[]);
 
 void
@@ -122,7 +122,7 @@ pm_setMessage(int const newState, int * const oldStateP);
 int
 pm_getMessage(void);
 
-FILE * 
+FILE *
 pm_tmpfile(void);
 
 int
@@ -141,22 +141,22 @@ pm_nextimage(FILE * const file, int * const eofP);
 
 /* Variable-sized arrays definitions. */
 
-char** 
+char**
 pm_allocarray (int const cols, int const rows, int const size );
 
-void * 
+void *
 pm_allocrow(unsigned int const cols,
             unsigned int const size);
 
-void 
+void
 pm_freearray (char** const its, int const rows);
 
-void 
+void
 pm_freerow(void * const row);
 
 
 /* Obsolete -- use shhopt instead */
-int 
+int
 pm_keymatch(const char * const str,
             const char * const keyword,
             int          const minchars);
@@ -169,7 +169,7 @@ int PURE_FN_ATTR
 pm_bitstomaxval(int const bits);
 
 unsigned int PURE_FN_ATTR
-pm_lcm (unsigned int const x, 
+pm_lcm (unsigned int const x,
         unsigned int const y,
         unsigned int const z,
         unsigned int const limit);
@@ -211,37 +211,37 @@ void
 pm_setusererrormsgfn(pm_usererrormsgfn * fn);
 
 void PM_GNU_PRINTF_ATTR(1,2)
-pm_message (const char format[], ...);     
+pm_message (const char format[], ...);
 
 void PM_GNU_PRINTF_ATTR(1,2)
 pm_errormsg(const char format[], ...);
 
 void PM_GNU_PRINTF_ATTR(1,2)
-pm_error (const char reason[], ...);       
+pm_error (const char reason[], ...);
 
 int
 pm_have_float_format(void);
 
 /* Obsolete - use shhopt and user's manual instead */
-void 
-pm_usage (const char usage[]);             
+void
+pm_usage (const char usage[]);
 
-FILE* 
+FILE*
 pm_openr (const char* const name);
-         
-FILE*    
+
+FILE*
 pm_openw (const char* const name);
-         
+
 FILE *
 pm_openr_seekable(const char name[]);
 
-void     
+void
 pm_close (FILE* const f);
 
-void 
+void
 pm_closer (FILE* const f);
-          
-void      
+
+void
 pm_closew (FILE* const f);
 
 
@@ -267,11 +267,11 @@ pm_writecharu(FILE *        const ofP,
 }
 
 int
-pm_readbigshort(FILE *  const ifP, 
+pm_readbigshort(FILE *  const ifP,
                 short * const sP);
 
 static __inline__ int
-pm_readbigshortu(FILE*            const ifP, 
+pm_readbigshortu(FILE*            const ifP,
                  unsigned short * const sP) {
     return pm_readbigshort(ifP, (short *) sP);
 }
@@ -287,7 +287,7 @@ pm_writebigshortu(FILE *          const ofP,
 }
 
 int
-pm_readbiglong(FILE * const ifP, 
+pm_readbiglong(FILE * const ifP,
                long * const lP);
 
 static __inline__ int
@@ -297,7 +297,7 @@ pm_readbiglongu(FILE *          const ifP,
 }
 
 int
-pm_readbiglong2(FILE * const ifP, 
+pm_readbiglong2(FILE * const ifP,
                 int32_t * const lP);
 
 static __inline__ int
@@ -366,11 +366,11 @@ pm_writelittlelongu(FILE *        const ofP,
     return pm_writelittlelong(ofP, (long) l);
 }
 
-int 
+int
 pm_readmagicnumber(FILE * const ifP);
 
-char* 
-pm_read_unknown_size(FILE * const ifP, 
+char*
+pm_read_unknown_size(FILE * const ifP,
                      long * const buf);
 
 void
@@ -390,12 +390,12 @@ unsigned int
 pm_tell(FILE * const fileP);
 
 void
-pm_tell2(FILE *       const fileP, 
+pm_tell2(FILE *       const fileP,
          void *       const fileposP,
          unsigned int const fileposSize);
 
 void
-pm_seek2(FILE *             const fileP, 
+pm_seek2(FILE *             const fileP,
          const pm_filepos * const fileposP,
          unsigned int       const fileposSize);
 
@@ -415,8 +415,8 @@ enum pm_check_type {
 };
 
 void
-pm_check(FILE *               const file, 
-         enum pm_check_type   const check_type, 
+pm_check(FILE *               const file,
+         enum pm_check_type   const check_type,
          pm_filepos           const need_raster_size,
          enum pm_check_code * const retval_p);
 
diff --git a/lib/pmfileio.c b/lib/pmfileio.c
index 31ec2588..33f89110 100644
--- a/lib/pmfileio.c
+++ b/lib/pmfileio.c
@@ -14,10 +14,10 @@
 #define _BSD_SOURCE    /* Make sure strdup is defined */
 #define _XOPEN_SOURCE 500    /* Make sure ftello, fseeko, strdup are defined */
 #define _LARGEFILE_SOURCE 1  /* Make sure ftello, fseeko are defined */
-#define _LARGEFILE64_SOURCE 1 
+#define _LARGEFILE64_SOURCE 1
 #define _FILE_OFFSET_BITS 64
     /* This means ftello() is really ftello64() and returns a 64 bit file
-       position.  Unless the C library doesn't have ftello64(), in which 
+       position.  Unless the C library doesn't have ftello64(), in which
        case ftello() is still just ftello().
 
        Likewise for all the other C library file functions.
@@ -25,7 +25,7 @@
        And off_t and fpos_t are 64 bit types instead of 32.  Consequently,
        pm_filepos_t might be 64 bits instead of 32.
     */
-#define _LARGE_FILES  
+#define _LARGE_FILES
     /* This does for AIX what _FILE_OFFSET_BITS=64 does for GNU */
 #define _LARGE_FILE_API
     /* This makes the the x64() functions available on AIX */
@@ -60,9 +60,9 @@ pm_openr(const char * const name) {
         f = stdin;
     else {
         f = fopen(name, "rb");
-        if (f == NULL) 
+        if (f == NULL)
             pm_error("Unable to open file '%s' for reading.  "
-                     "fopen() returns errno %d (%s)", 
+                     "fopen() returns errno %d (%s)",
                      name, errno, strerror(errno));
     }
     return f;
@@ -78,9 +78,9 @@ pm_openw(const char * const name) {
         f = stdout;
     else {
         f = fopen(name, "wb");
-        if (f == NULL) 
+        if (f == NULL)
             pm_error("Unable to open file '%s' for writing.  "
-                     "fopen() returns errno %d (%s)", 
+                     "fopen() returns errno %d (%s)",
                      name, errno, strerror(errno));
     }
     return f;
@@ -118,7 +118,7 @@ tmpDir(void) {
 static int
 tempFileOpenFlags(void) {
 /*----------------------------------------------------------------------------
-  Open flags (argument to open()) suitable for a new temporary file  
+  Open flags (argument to open()) suitable for a new temporary file
 -----------------------------------------------------------------------------*/
     int retval;
 
@@ -182,11 +182,11 @@ mkstempx(char * const filenameBuffer) {
             } else {
                 if (errno == EEXIST) {
                     /* We'll just have to keep trying */
-                } else 
+                } else
                     error = TRUE;
             }
         }
-    }    
+    }
     if (gotFile)
         retval = fd;
     else
@@ -216,7 +216,7 @@ makeTmpfileWithTemplate(const char *  const filenameTemplate,
                         int *         const fdP,
                         const char ** const filenameP,
                         const char ** const errorP) {
-    
+
     char * filenameBuffer;  /* malloc'ed */
 
     filenameBuffer = strdup(filenameTemplate);
@@ -226,9 +226,9 @@ makeTmpfileWithTemplate(const char *  const filenameTemplate,
                     "file name");
     else {
         int rc;
-        
+
         rc = mkstemp2(filenameBuffer);
-        
+
         if (rc < 0)
             pm_asprintf(errorP,
                         "Unable to create temporary file according to name "
@@ -261,8 +261,8 @@ pm_make_tmpfile_fd(int *         const fdP,
         dirseparator = "";
     else
         dirseparator = "/";
-    
-    pm_asprintf(&filenameTemplate, "%s%s%s%s", 
+
+    pm_asprintf(&filenameTemplate, "%s%s%s%s",
                 tmpdir, dirseparator, pm_progname, "_XXXXXX");
 
     if (filenameTemplate == pm_strsol)
@@ -291,7 +291,7 @@ pm_make_tmpfile(FILE **       const filePP,
     pm_make_tmpfile_fd(&fd, filenameP);
 
     *filePP = fdopen(fd, "w+b");
-    
+
     if (*filePP == NULL) {
         close(fd);
         unlink(*filenameP);
@@ -305,7 +305,7 @@ pm_make_tmpfile(FILE **       const filePP,
 
 
 
-bool const canUnlinkOpen = 
+bool const canUnlinkOpen =
 #if CAN_UNLINK_OPEN
     1
 #else
@@ -394,7 +394,7 @@ scheduleUnlinkAtExit(const char * const fileName,
    code too badly for Unix.
 -----------------------------------------------------------------------------*/
     static bool unlinkListEstablished = false;
-    
+
     if (!unlinkListEstablished) {
         atexit(unlinkTempFiles);
         unlinkListP = NULL;
@@ -418,7 +418,7 @@ arrangeUnlink(const char * const fileName,
 
 
 
-FILE * 
+FILE *
 pm_tmpfile(void) {
 
     FILE * fileP;
@@ -473,7 +473,7 @@ pm_openr_seekable(const char name[]) {
 
     original_file = pm_openr((char *) name);
 
-    /* I would use fseek() to determine if the file is seekable and 
+    /* I would use fseek() to determine if the file is seekable and
        be a little more general than checking the type of file, but I
        don't have reliable information on how to do that.  I have seen
        streams be partially seekable -- you can, for example seek to
@@ -488,16 +488,16 @@ pm_openr_seekable(const char name[]) {
     stat_rc = fstat(fileno(original_file), &statbuf);
     if (stat_rc == 0 && S_ISREG(statbuf.st_mode))
         seekable = TRUE;
-    else 
+    else
         seekable = FALSE;
 
     if (seekable) {
         seekable_file = original_file;
     } else {
         seekable_file = pm_tmpfile();
-        
+
         /* Copy the input into the temporary seekable file */
-        while (!feof(original_file) && !ferror(original_file) 
+        while (!feof(original_file) && !ferror(original_file)
                && !ferror(seekable_file)) {
             char buffer[4096];
             int bytes_read;
@@ -537,7 +537,7 @@ pm_close(FILE * const f) {
 
 
 
-/* The pnmtopng package uses pm_closer() and pm_closew() instead of 
+/* The pnmtopng package uses pm_closer() and pm_closew() instead of
    pm_close(), apparently because the 1999 Pbmplus package has them.
    I don't know what the difference is supposed to be.
 */
@@ -601,7 +601,7 @@ getcNofail(FILE * const ifP) {
 void
 pm_readchar(FILE * const ifP,
             char * const cP) {
-    
+
     *cP = (char)getcNofail(ifP);
 }
 
@@ -617,7 +617,7 @@ pm_writechar(FILE * const ofP,
 
 
 int
-pm_readbigshort(FILE *  const ifP, 
+pm_readbigshort(FILE *  const ifP,
                 short * const sP) {
 
     unsigned short s;
@@ -633,7 +633,7 @@ pm_readbigshort(FILE *  const ifP,
 
 
 int
-pm_writebigshort(FILE * const ofP, 
+pm_writebigshort(FILE * const ofP,
                  short  const s) {
 
     putc((s >> 8) & 0xff, ofP);
@@ -645,7 +645,7 @@ pm_writebigshort(FILE * const ofP,
 
 
 int
-pm_readbiglong(FILE * const ifP, 
+pm_readbiglong(FILE * const ifP,
                long * const lP) {
 
     unsigned long l;
@@ -680,7 +680,7 @@ pm_readbiglong2(FILE *    const ifP,
 
 
 int
-pm_writebiglong(FILE * const ofP, 
+pm_writebiglong(FILE * const ofP,
                 long   const l) {
 
     putc((l >> 24) & 0xff, ofP);
@@ -694,7 +694,7 @@ pm_writebiglong(FILE * const ofP,
 
 
 int
-pm_readlittleshort(FILE *  const ifP, 
+pm_readlittleshort(FILE *  const ifP,
                    short * const sP) {
     unsigned short s;
 
@@ -709,7 +709,7 @@ pm_readlittleshort(FILE *  const ifP,
 
 
 int
-pm_writelittleshort(FILE * const ofP, 
+pm_writelittleshort(FILE * const ofP,
                     short  const s) {
 
     putc((s >> 0) & 0xff, ofP);
@@ -721,7 +721,7 @@ pm_writelittleshort(FILE * const ofP,
 
 
 int
-pm_readlittlelong(FILE * const ifP, 
+pm_readlittlelong(FILE * const ifP,
                   long * const lP) {
     unsigned long l;
 
@@ -755,7 +755,7 @@ pm_readlittlelong2(FILE *    const ifP,
 
 
 int
-pm_writelittlelong(FILE * const ofP, 
+pm_writelittlelong(FILE * const ofP,
                    long   const l) {
 
     putc((l >>  0) & 0xff, ofP);
@@ -768,7 +768,7 @@ pm_writelittlelong(FILE * const ofP,
 
 
 
-int 
+int
 pm_readmagicnumber(FILE * const ifP) {
 
     int ich1, ich2;
@@ -805,7 +805,7 @@ pm_readmagicnumber(FILE * const ifP) {
                                   than this. */
 
 char *
-pm_read_unknown_size(FILE * const file, 
+pm_read_unknown_size(FILE * const file,
                      long * const nread) {
     long nalloc;
     char * buf;
@@ -831,7 +831,7 @@ pm_read_unknown_size(FILE * const file,
         val = getc(file);
         if (val == EOF)
             eof = TRUE;
-        else 
+        else
             buf[(*nread)++] = val;
     }
     return buf;
@@ -946,7 +946,7 @@ pm_bs_long(long const l) {
 
 
 void
-pm_tell2(FILE *       const fileP, 
+pm_tell2(FILE *       const fileP,
          void *       const fileposP,
          unsigned int const fileposSize) {
 /*----------------------------------------------------------------------------
@@ -978,7 +978,7 @@ pm_tell2(FILE *       const fileP,
         }
     } else
         pm_error("File position size passed to pm_tell() is invalid: %u.  "
-                 "Valid sizes are %u and %u", 
+                 "Valid sizes are %u and %u",
                  fileposSize, (unsigned int)sizeof(pm_filepos),
                  (unsigned int) sizeof(long));
 }
@@ -987,7 +987,7 @@ pm_tell2(FILE *       const fileP,
 
 unsigned int
 pm_tell(FILE * const fileP) {
-    
+
     long filepos;
 
     pm_tell2(fileP, &filepos, sizeof(filepos));
@@ -998,14 +998,14 @@ pm_tell(FILE * const fileP) {
 
 
 void
-pm_seek2(FILE *             const fileP, 
+pm_seek2(FILE *             const fileP,
          const pm_filepos * const fileposP,
          unsigned int       const fileposSize) {
 /*----------------------------------------------------------------------------
    Position file *fileP to position *fileposP.  Abort if error, including
    if *fileP isn't a seekable file.
 -----------------------------------------------------------------------------*/
-    if (fileposSize == sizeof(pm_filepos)) 
+    if (fileposSize == sizeof(pm_filepos))
         /* Note: FSEEKO() is either fseeko() or fseek(), depending on the
            capabilities of the underlying C library.  It is defined in
            pm_config.h.  fseeko(), in turn, may be either fseek() or
@@ -1017,7 +1017,7 @@ pm_seek2(FILE *             const fileP,
         fseek(fileP, fileposLong, SEEK_SET);
     } else
         pm_error("File position size passed to pm_seek() is invalid: %u.  "
-                 "Valid sizes are %u and %u", 
+                 "Valid sizes are %u and %u",
                  fileposSize, (unsigned int)sizeof(pm_filepos),
                  (unsigned int) sizeof(long));
 }
@@ -1044,7 +1044,7 @@ pm_nextimage(FILE * const file, int * const eofP) {
    Position the file 'file' to the next image in the stream, assuming it is
    now positioned just after the current image.  I.e. read off any white
    space at the end of the current image's raster.  Note that the raw formats
-   don't permit such white space, but this routine tolerates it anyway, 
+   don't permit such white space, but this routine tolerates it anyway,
    because the plain formats do permit white space after the raster.
 
    Iff there is no next image, return *eofP == TRUE.
@@ -1069,7 +1069,7 @@ pm_nextimage(FILE * const file, int * const eofP) {
         int c;
         c = getc(file);
         if (c == EOF) {
-            if (feof(file)) 
+            if (feof(file))
                 eof = TRUE;
             else
                 pm_error("File error on getc() to position to image");
@@ -1080,10 +1080,10 @@ pm_nextimage(FILE * const file, int * const eofP) {
                 nonWhitespaceFound = TRUE;
 
                 /* Have to put the non-whitespace character back in
-                   the stream -- it's part of the next image.  
+                   the stream -- it's part of the next image.
                 */
                 rc = ungetc(c, file);
-                if (rc == EOF) 
+                if (rc == EOF)
                     pm_error("File error doing ungetc() "
                              "to position to image.");
             }
@@ -1095,8 +1095,8 @@ pm_nextimage(FILE * const file, int * const eofP) {
 
 
 void
-pm_check(FILE *               const file, 
-         enum pm_check_type   const check_type, 
+pm_check(FILE *               const file,
+         enum pm_check_type   const check_type,
          pm_filepos           const need_raster_size,
          enum pm_check_code * const retval_p) {
 /*----------------------------------------------------------------------------
@@ -1114,9 +1114,9 @@ pm_check(FILE *               const file,
     curpos = FTELLO(file);
     if (curpos >= 0) {
         /* This type of file has a current position */
-            
+
         rc = fstat(fileno(file), &statbuf);
-        if (rc != 0) 
+        if (rc != 0)
             pm_error("fstat() failed to get size of file, though ftello() "
                      "successfully identified\n"
                      "the current position.  Errno=%s (%d)",
@@ -1126,12 +1126,12 @@ pm_check(FILE *               const file,
             if (retval_p) *retval_p = PM_CHECK_UNCHECKABLE;
         } else {
             pm_filepos const have_raster_size = statbuf.st_size - curpos;
-            
+
             if (have_raster_size < need_raster_size)
                 pm_error("File has invalid format.  The raster should "
                          "contain %u bytes, but\n"
                          "the file ends after only %u bytes.",
-                         (unsigned int) need_raster_size, 
+                         (unsigned int) need_raster_size,
                          (unsigned int) have_raster_size);
             else if (have_raster_size > need_raster_size) {
                 if (retval_p) *retval_p = PM_CHECK_TOO_LONG;
diff --git a/lib/util/runlength.c b/lib/util/runlength.c
index a4bb9057..62e3bf0c 100644
--- a/lib/util/runlength.c
+++ b/lib/util/runlength.c
@@ -22,9 +22,9 @@
 
 ===============================================================================
 
-  Packbits is a simple yet efficient simple run-length compression method.  It
-  has a provision for uncompressed sequences which allows efficient encoding
-  of noisy input.
+  Packbits is a simple yet efficient simple run-length compression method.
+  It has a provision for uncompressed sequences which allows efficient
+  encoding of noisy input.
 
   A survey of netpbm source code in 2015 found Packbits encoding in the
   following Netpbm programs: pbmtoescp2, pbmtomacp, pnmtopalm, pnmtopclxl,
@@ -34,8 +34,8 @@
   images that use Packbits compression, but does so via code in the TIFF
   library (not part of Netpbm).
 
-  Variants of Packbits are employed in pnmtosgi,  pamtopdbimg,  pbmtoppa
-  and  pbmtogo.
+  Variants of Packbits are employed in pnmtosgi, pamtopdbimg, pbmtoppa
+  pbmtogo and pamtotga.
 
   All the above programs formerly did the same compression through different
   code.  This redundancy bloated the Netpbm package and made maintenance
@@ -46,7 +46,8 @@
   called "run length encoding."  In ppmtoilbm the name is "byterun1."
 
   Today, all Netpbm programs that do Packbits compression with the exception
-  of pbmtoppa and pbmtogo use the facilities   in this file for it.  
+  of pamtotiff, pbmtoppa, pbmtogo and pamtotga use the facilities in this
+  file for it.  
 =============================================================================*/
 
 #include <string.h>
@@ -184,11 +185,11 @@ pm_rlenc_compressword(const uint16_t   * const inbuf,
                       size_t             const inSize,
                       size_t           * const outputSizeP) {
 /*---------------------------------------------------------------------------
-   Similar to pm_rlenc_byte(), but this works with two-byte elements.  The
-   difference between SGI16 and PALM16 is the size of the flag.  SGI16 : 16
-   bits; PALM16 : 8 bits
+   Similar to pm_rlenc_compressbyte(), but this works with two-byte elements.
+   The difference between SGI16 and PALM16 is the size of the flag.
+   SGI16 : 16 bits; PALM16 : 8 bits
 
-   'inSize' is a number of words,but *outputSizeP is a number of bytes.
+   'inSize' is a number of words, but *outputSizeP is a number of bytes.
 -----------------------------------------------------------------------------*/
     size_t inCurs, outCurs;
     size_t flagSz;
@@ -277,9 +278,9 @@ pm_rlenc_compressword(const uint16_t   * const inbuf,
    different from its neighbors.
 
    A compressed block is one that encodes a sequence of identical values
-   (which could be a run or just part of a run) as a value and a count.
-   count.  An uncompressed block is one that encodes a sequence of any values
-   by listing the values individually.
+   (which could be a run or just part of a very long run) as a value and
+   a count.  An uncompressed block is one that encodes a sequence of any
+   values by listing the values individually.
 
    Start by encoding the entire input as uncompressed blocks.  Seek runs that
    can be encoded with compressed blocks, but only if doing so doesn't make
@@ -330,11 +331,12 @@ pm_rlenc_maxbytes(size_t          const inSize,  /* number of elements */
    /* The upper limit could be raised above INT_MAX, but no program needs that
       today.
    */
-    size_t blockSize;
-    size_t flagSize;
-    size_t itemSize;
-    size_t miscSize;
-    size_t overhead;
+    size_t blockSize;  /* Number of items in data block */
+    size_t flagSize;   /* Size of flag, in bytes */
+    size_t itemSize;   /* Size of item, in bytes */
+    size_t miscSize;   /* Size of other elements such as term code, in bytes */
+    size_t overhead;   /* Worst-case overhead, in bytes */
+    /* return value:      Worst-case output size, in bytes */ 
 
     switch (mode) {
     case PM_RLE_PACKBITS:
diff --git a/netpbm.c b/netpbm.c
index eeb82acc..a9a0bf81 100644
--- a/netpbm.c
+++ b/netpbm.c
@@ -30,7 +30,7 @@ int
 main(int argc, char *argv[]) {
 
     const char * cp;
-    
+
     if (strcmp(pm_arg0toprogname(argv[0]), "netpbm") == 0) {
         ++argv;
         --argc;
@@ -45,7 +45,7 @@ main(int argc, char *argv[]) {
 	}
 
     cp = pm_arg0toprogname(argv[0]);
-    
+
     /* merge.h is an automatically generated file that generates code to
        match the string 'cp' against the name of every program that is part
        of this merge and, upon finding a match, invoke that program.
@@ -55,48 +55,8 @@ main(int argc, char *argv[]) {
 
 #include "mergetrylist"
 
-    /* Add the obsolete names for some programs */
-    TRY("bmptoppm", main_bmptopnm);
-    TRY("gemtopbm", main_gemtopnm);
-    TRY("icontopbm", main_sunicontopnm);
-    TRY("pbmtoicon", main_pbmtosunicon);
-    TRY("pgmedge", main_pamedge);
-    TRY("pgmnorm", main_pnmnorm);
-    TRY("pgmoil", main_pamoil);
-    TRY("pgmslice", main_pamslice);
-    TRY("pnmarith", main_pamarith);
-    TRY("pngtopnm", main_pngtopam);
-    TRY("pnmarith", main_pamarith);
-    TRY("pnmcomp", main_pamcomp);
-    TRY("pnmcut", main_pamcut);
-    TRY("pnmdepth", main_pamdepth);
-    TRY("pnmfile", main_pamfile);
-    TRY("pnminterp", main_pamstretch);
-    TRY("pnmenlarge", main_pamenlarge);
-    TRY("pnmscale", main_pamscale);
-    TRY("pnmsplit", main_pamsplit);
-    TRY("pnmtofits", main_pamtofits);
-    TRY("pnmtopnm", main_pamtopnm);
-    TRY("ppmnorm", main_pnmnorm);
-    TRY("ppmtotga", main_pamtotga);
-    TRY("ppmtouil", main_pamtouil);
-    TRY("pnmtopnm", main_pamtopnm);
-    TRY("ppmnorm", main_pnmnorm);
-    TRY("ppmtotga", main_pamtotga);
-
-    /* We don't do the ppmtojpeg alias because if user doesn't have a JPEG
-       library, there is no main_pnmtojpeg library.  The right way to do
-       this is to have these TRY's generated by the subdirectory makes,
-       which would know whether pnmtojpeg was built into the merged binary
-       or not.  But that's too much work.  Same with TIFF and PNG converters.
-
-    TRY("ppmtojpeg", main_pnmtojpeg); 
-    TRY("pngtopnm", main_pngtopam); 
-    TRY("pnmtotiff", main_pamtotiff);
-    TRY("pamrgbatopng", main_pamtopng);
-    */
-
     fprintf(stderr,"'%s' is an unknown Netpbm program name \n", cp );
+
     exit(1);
 }
 
diff --git a/other/Makefile b/other/Makefile
index bd2c9dc2..aa0d75bb 100644
--- a/other/Makefile
+++ b/other/Makefile
@@ -45,6 +45,8 @@ OBJECTS = $(BINARIES:%=%.o)
 MERGEBINARIES = $(BINARIES)
 MERGE_OBJECTS = $(MERGEBINARIES:%=%.o2)
 
+HAVE_MERGE_COMPAT=YES
+
 .PHONY: all
 all: $(BINARIES) $(SUBDIRS:%=%/all)
 
@@ -52,7 +54,7 @@ include $(SRCDIR)/common.mk
 
 ppmsvgalib: LDFLAGS_TARGET = $(shell $(LIBOPT) $(LINUXSVGALIB))
 
-install.bin: install.bin.local
+install.bin install.merge: install.bin.local
 .PHONY: install.bin.local
 install.bin.local: $(PKGDIR)/bin
 # Remember that $(SYMLINK) might just be a copy command.
@@ -69,4 +71,10 @@ install.bin.local: $(PKGDIR)/bin
 	  rm -f pnmdepth$(EXE) ; \
 	  $(SYMLINK) pamdepth$(EXE) pnmdepth$(EXE)
 
+mergecomptrylist:
+	cat /dev/null >$@
+	echo "TRY(\"pnmarith\", main_pamarith);" >>$@
+	echo "TRY(\"pnmsplit\", main_pamsplit);" >>$@
+	echo "TRY(\"pnmdepth\", main_pamdepth);" >>$@
+
 FORCE:
diff --git a/other/pamfix.c b/other/pamfix.c
index 8db67e08..e40f51f4 100644
--- a/other/pamfix.c
+++ b/other/pamfix.c
@@ -58,7 +58,7 @@ parseCommandLine(int argc, char ** const argv,
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
     free(option_def);
 
-    if (argc-1 == 0) 
+    if (argc-1 == 0)
         cmdlineP->inputFileName = "-";
     else if (argc-1 != 1)
         pm_error("Program takes zero or one argument (filename).  You "
@@ -119,7 +119,7 @@ analyzeRaster(const struct pam * const pamP,
     unsigned int row;
     jmp_buf jmpbuf;
     int rc;
-    
+
     tuplerow = pnm_allocpamrow(pamP);
 
     pm_setusererrormsgfn(handleRowErrMsg);
@@ -178,13 +178,13 @@ clipPamRow(const struct pam * const pamP,
         unsigned int plane;
         for (plane = 0; plane < pamP->depth; ++plane) {
             if (tuplerow[col][plane] > pamP->maxval) {
-                if (verbose) 
+                if (verbose)
                     pm_message("Clipping: Row %u Col %u Plane %u.  "
                                "Sample value %lu exceeds the "
                                "image maxval of %lu",
                                row, col, plane, tuplerow[col][plane],
                                pamP->maxval);
-	            tuplerow[col][plane] = pamP->maxval;
+                tuplerow[col][plane] = pamP->maxval;
             }
         }
     }
@@ -211,7 +211,7 @@ copyGoodRows(const struct pam * const inpamP,
         clipPamRow(outpamP, tuplerow, row, verbose);
         pnm_writepamrow(outpamP, tuplerow);
     }
-    
+
     pnm_freepamrow(tuplerow);
 }
 
@@ -283,7 +283,7 @@ main(int argc, char * argv[]) {
     copyGoodRows(&tweakedPam, &outpam, cmdline.verbose);
 
     pm_close(inpam.file);
-    
+
     return 0;
 }
 
diff --git a/other/pnmcolormap.c b/other/pnmcolormap.c
index 57db4329..f687f037 100644
--- a/other/pnmcolormap.c
+++ b/other/pnmcolormap.c
@@ -50,9 +50,9 @@ struct cmdlineInfo {
     */
     const char *inputFilespec;  /* Filespec of input file */
     unsigned int allcolors;  /* boolean: select all colors from the input */
-    unsigned int newcolors;    
+    unsigned int newcolors;
         /* Number of colors argument; meaningless if allcolors true */
-    enum methodForLargest methodForLargest; 
+    enum methodForLargest methodForLargest;
         /* -spreadintensity/-spreadluminosity options */
     enum methodForRep methodForRep;
         /* -center/-meancolor/-meanpixel options */
@@ -68,7 +68,7 @@ parseCommandLine (int argc, 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.  
+   and argv.  Return the information in the options as *cmdlineP.
 
    If command line is internally inconsistent (invalid options, etc.),
    issue error message to stderr and abort program.
@@ -89,21 +89,21 @@ parseCommandLine (int argc, char ** argv,
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0,   "spreadbrightness", OPT_FLAG,   
+    OPTENT3(0,   "spreadbrightness", OPT_FLAG,
             NULL,                       &spreadbrightness, 0);
-    OPTENT3(0,   "spreadluminosity", OPT_FLAG,   
+    OPTENT3(0,   "spreadluminosity", OPT_FLAG,
             NULL,                       &spreadluminosity, 0);
-    OPTENT3(0,   "center",           OPT_FLAG,   
+    OPTENT3(0,   "center",           OPT_FLAG,
             NULL,                       &center,           0);
-    OPTENT3(0,   "meancolor",        OPT_FLAG,   
+    OPTENT3(0,   "meancolor",        OPT_FLAG,
             NULL,                       &meancolor,        0);
-    OPTENT3(0,   "meanpixel",        OPT_FLAG,   
+    OPTENT3(0,   "meanpixel",        OPT_FLAG,
             NULL,                       &meanpixel,        0);
-    OPTENT3(0, "sort",     OPT_FLAG,   NULL,                  
+    OPTENT3(0, "sort",     OPT_FLAG,   NULL,
             &cmdlineP->sort,       0 );
-    OPTENT3(0, "square",   OPT_FLAG,   NULL,                  
+    OPTENT3(0, "square",   OPT_FLAG,   NULL,
             &cmdlineP->square,       0 );
-    OPTENT3(0, "verbose",   OPT_FLAG,   NULL,                  
+    OPTENT3(0, "verbose",   OPT_FLAG,   NULL,
             &cmdlineP->verbose,       0 );
 
     opt.opt_table = option_def;
@@ -114,7 +114,7 @@ parseCommandLine (int argc, char ** argv,
         /* Uses and sets argc, argv, and some of *cmdline_p and others. */
 
 
-    if (spreadbrightness && spreadluminosity) 
+    if (spreadbrightness && spreadluminosity)
         pm_error("You cannot specify both -spreadbrightness and "
                  "spreadluminosity.");
     if (spreadluminosity)
@@ -127,7 +127,7 @@ parseCommandLine (int argc, char ** argv,
                  "-meanpixel.");
     if (meancolor)
         cmdlineP->methodForRep = REP_AVERAGE_COLORS;
-    else if (meanpixel) 
+    else if (meanpixel)
         cmdlineP->methodForRep = REP_AVERAGE_PIXELS;
     else
         cmdlineP->methodForRep = REP_CENTER_BOX;
@@ -179,7 +179,7 @@ static unsigned int compareplanePlane;
        tuples.  qsort() doesn't pass any arguments except the two tuples.
     */
 static int
-compareplane(const void * const arg1, 
+compareplane(const void * const arg1,
              const void * const arg2) {
 
     const struct tupleint * const * const comparandPP  = arg1;
@@ -223,7 +223,7 @@ newColorMap(unsigned int const newcolors,
 
     for (i = 0; i < newcolors; ++i) {
         unsigned int plane;
-        for (plane = 0; plane < depth; ++plane) 
+        for (plane = 0; plane < depth; ++plane)
             colormap.table[i]->tuple[plane] = 0;
     }
     colormap.size = newcolors;
@@ -269,14 +269,14 @@ findBoxBoundaries(tupletable2  const colorfreqtable,
         minval[plane] = colorfreqtable.table[boxStart]->tuple[plane];
         maxval[plane] = minval[plane];
     }
-    
+
     for (i = 1; i < boxSize; ++i) {
         unsigned int plane;
         for (plane = 0; plane < depth; ++plane) {
             sample const v = colorfreqtable.table[boxStart + i]->tuple[plane];
             if (v < minval[plane]) minval[plane] = v;
             if (v > maxval[plane]) maxval[plane] = v;
-        } 
+        }
     }
 }
 
@@ -284,11 +284,11 @@ findBoxBoundaries(tupletable2  const colorfreqtable,
 
 static unsigned int
 largestByNorm(sample minval[], sample maxval[], unsigned int const depth) {
-    
+
     unsigned int largestDimension;
     unsigned int plane;
 
-    sample largestSpreadSoFar = 0;  
+    sample largestSpreadSoFar = 0;
     largestDimension = 0;
     for (plane = 0; plane < depth; ++plane) {
         sample const spread = maxval[plane]-minval[plane];
@@ -302,11 +302,11 @@ largestByNorm(sample minval[], sample maxval[], unsigned int const depth) {
 
 
 
-static unsigned int 
-largestByLuminosity(sample minval[], sample maxval[], 
+static unsigned int
+largestByLuminosity(sample minval[], sample maxval[],
                     unsigned int const depth) {
 /*----------------------------------------------------------------------------
-   This subroutine presumes that the tuple type is either 
+   This subroutine presumes that the tuple type is either
    BLACKANDWHITE, GRAYSCALE, or RGB (which implies pamP->depth is 1 or 3).
    To save time, we don't actually check it.
 -----------------------------------------------------------------------------*/
@@ -323,7 +323,7 @@ largestByLuminosity(sample minval[], sample maxval[],
         largestSpreadSoFar = 0.0;
 
         for (plane = 0; plane < 3; ++plane) {
-            double const spread = 
+            double const spread =
                 pnm_lumin_factor[plane] * (maxval[plane]-minval[plane]);
             if (spread > largestSpreadSoFar) {
                 largestDimension = plane;
@@ -340,7 +340,7 @@ largestByLuminosity(sample minval[], sample maxval[],
 static void
 centerBox(int          const boxStart,
           int          const boxSize,
-          tupletable2  const colorfreqtable, 
+          tupletable2  const colorfreqtable,
           unsigned int const depth,
           tuple        const newTuple) {
 
@@ -351,7 +351,7 @@ centerBox(int          const boxStart,
         unsigned int i;
 
         minval = maxval = colorfreqtable.table[boxStart]->tuple[plane];
-        
+
         for (i = 1; i < boxSize; ++i) {
             int const v = colorfreqtable.table[boxStart + i]->tuple[plane];
             minval = MIN( minval, v);
@@ -366,7 +366,7 @@ centerBox(int          const boxStart,
 static void
 averageColors(int          const boxStart,
               int          const boxSize,
-              tupletable2  const colorfreqtable, 
+              tupletable2  const colorfreqtable,
               unsigned int const depth,
               tuple        const newTuple) {
 
@@ -378,7 +378,7 @@ averageColors(int          const boxStart,
 
         sum = 0;
 
-        for (i = 0; i < boxSize; ++i) 
+        for (i = 0; i < boxSize; ++i)
             sum += colorfreqtable.table[boxStart+i]->tuple[plane];
 
         newTuple[plane] = ROUNDDIV(sum, boxSize);
@@ -390,7 +390,7 @@ averageColors(int          const boxStart,
 static void
 averagePixels(int          const boxStart,
               int          const boxSize,
-              tupletable2  const colorfreqtable, 
+              tupletable2  const colorfreqtable,
               unsigned int const depth,
               tuple        const newTuple) {
 
@@ -411,7 +411,7 @@ averagePixels(int          const boxStart,
 
         sum = 0;
 
-        for (i = 0; i < boxSize; ++i) 
+        for (i = 0; i < boxSize; ++i)
             sum += colorfreqtable.table[boxStart+i]->tuple[plane]
                 * colorfreqtable.table[boxStart+i]->value;
 
@@ -423,9 +423,9 @@ averagePixels(int          const boxStart,
 
 static tupletable2
 colormapFromBv(unsigned int      const newcolors,
-               boxVector         const bv, 
+               boxVector         const bv,
                unsigned int      const boxes,
-               tupletable2       const colorfreqtable, 
+               tupletable2       const colorfreqtable,
                unsigned int      const depth,
                enum methodForRep const methodForRep) {
     /*
@@ -434,7 +434,7 @@ colormapFromBv(unsigned int      const newcolors,
     ** One would be to choose the center of the box; this ignores any structure
     ** within the boxes.  Another method would be to average all the colors in
     ** the box - this is the method specified in Heckbert's paper.  A third
-    ** method is to average all the pixels in the box. 
+    ** method is to average all the pixels in the box.
     */
     tupletable2 colormap;
     unsigned int bi;
@@ -443,8 +443,8 @@ colormapFromBv(unsigned int      const newcolors,
 
     for (bi = 0; bi < boxes; ++bi) {
         switch (methodForRep) {
-        case REP_CENTER_BOX: 
-            centerBox(bv[bi].ind, bv[bi].colors, colorfreqtable, depth, 
+        case REP_CENTER_BOX:
+            centerBox(bv[bi].ind, bv[bi].colors, colorfreqtable, depth,
                       colormap.table[bi]->tuple);
             break;
         case REP_AVERAGE_COLORS:
@@ -467,7 +467,7 @@ colormapFromBv(unsigned int      const newcolors,
 
 static unsigned int
 freqTotal(tupletable2 const freqtable) {
-    
+
     unsigned int i;
     unsigned int sum;
 
@@ -481,16 +481,16 @@ freqTotal(tupletable2 const freqtable) {
 
 
 static void
-splitBox(boxVector             const bv, 
-         unsigned int *        const boxesP, 
+splitBox(boxVector             const bv,
+         unsigned int *        const boxesP,
          unsigned int          const bi,
-         tupletable2           const colorfreqtable, 
+         tupletable2           const colorfreqtable,
          unsigned int          const depth,
          enum methodForLargest const methodForLargest) {
 /*----------------------------------------------------------------------------
    Split Box 'bi' in the box vector bv (so that bv contains one more box
    than it did as input).  Split it so that each new box represents about
-   half of the pixels in the distribution given by 'colorfreqtable' for 
+   half of the pixels in the distribution given by 'colorfreqtable' for
    the colors in the original box, but with distinct colors in each of the
    two new boxes.
 
@@ -512,7 +512,7 @@ splitBox(boxVector             const bv,
     MALLOCARRAY_NOFAIL(minval, depth);
     MALLOCARRAY_NOFAIL(maxval, depth);
 
-    findBoxBoundaries(colorfreqtable, depth, boxStart, boxSize, 
+    findBoxBoundaries(colorfreqtable, depth, boxStart, boxSize,
                       minval, maxval);
 
     /* Find the largest dimension, and sort by that component.  I have
@@ -521,28 +521,28 @@ splitBox(boxVector             const bv,
        transforming into luminosities before the comparison.
     */
     switch (methodForLargest) {
-    case LARGE_NORM: 
+    case LARGE_NORM:
         largestDimension = largestByNorm(minval, maxval, depth);
         break;
-    case LARGE_LUM: 
+    case LARGE_LUM:
         largestDimension = largestByLuminosity(minval, maxval, depth);
         break;
     }
-                                                    
+
     /* TODO: I think this sort should go after creating a box,
        not before splitting.  Because you need the sort to use
        the REP_CENTER_BOX method of choosing a color to
-       represent the final boxes 
+       represent the final boxes
     */
 
     /* Set the gross global variable 'compareplanePlane' as a
        parameter to compareplane(), which is called by qsort().
     */
     compareplanePlane = largestDimension;
-    qsort((char*) &colorfreqtable.table[boxStart], boxSize, 
-          sizeof(colorfreqtable.table[boxStart]), 
+    qsort((char*) &colorfreqtable.table[boxStart], boxSize,
+          sizeof(colorfreqtable.table[boxStart]),
           compareplane);
-            
+
     {
         /* Now find the median based on the counts, so that about half
            the pixels (not colors, pixels) are in each subdivision.  */
@@ -571,7 +571,7 @@ splitBox(boxVector             const bv,
 
 
 static void
-mediancut(tupletable2           const colorfreqtable, 
+mediancut(tupletable2           const colorfreqtable,
           unsigned int          const depth,
           int                   const newcolors,
           enum methodForLargest const methodForLargest,
@@ -605,7 +605,7 @@ mediancut(tupletable2           const colorfreqtable,
         for (bi = 0; bi < boxes && bv[bi].colors < 2; ++bi);
         if (bi >= boxes)
             multicolorBoxesExist = FALSE;
-        else 
+        else
             splitBox(bv, &boxes, bi, colorfreqtable, depth, methodForLargest);
     }
     *colormapP = colormapFromBv(newcolors, bv, boxes, colorfreqtable, depth,
@@ -646,7 +646,7 @@ addImageColorsToHash(struct pam *   const pamP,
 
     tuple * tuplerow;
     unsigned int row;
-    
+
     tuplerow = pnm_allocpamrow(pamP);
 
     for (row = 0; row < pamP->height; ++row) {
@@ -676,7 +676,7 @@ computeHistogram(FILE *         const ifP,
                  tupletable2 *  const colorfreqtableP) {
 /*----------------------------------------------------------------------------
   Make a histogram of the colors in the image stream in the file '*ifP'.
-  
+
   Return as *freqPamP a description of the tuple values in the histogram.
   Only the fields of *freqPamP that describe individual tuples are
   meaningful (depth, maxval, tuple type);
@@ -689,7 +689,7 @@ computeHistogram(FILE *         const ifP,
     tuplehash tuplehash;
     unsigned int colorCount;
     int eof;
-    
+
     pm_message("making histogram...");
 
     tuplehash = pnm_createtuplehash();
@@ -699,7 +699,7 @@ computeHistogram(FILE *         const ifP,
 
     for (imageSeq = 0; !eof; ++imageSeq) {
         struct pam inpam;
-        
+
         pm_message("Scanning image %u", imageSeq);
 
         pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
@@ -708,7 +708,7 @@ computeHistogram(FILE *         const ifP,
             firstPam = inpam;
         else
             validateCompatibleImage(&inpam, &firstPam, imageSeq);
-    
+
         addImageColorsToHash(&inpam, tuplehash, &colorCount);
 
         pm_message("%u colors so far", colorCount);
@@ -722,14 +722,14 @@ computeHistogram(FILE *         const ifP,
     pnm_destroytuplehash(tuplehash);
 
     pm_message("%u colors found", colorfreqtableP->size);
-    
+
     freqPamP->size   = sizeof(*freqPamP);
     freqPamP->len    = PAM_STRUCT_SIZE(tuple_type);
     freqPamP->maxval = firstPam.maxval;
     freqPamP->bytes_per_sample = pnm_bytespersample(freqPamP->maxval);
     freqPamP->depth  = firstPam.depth;
     STRSCPY(freqPamP->tuple_type, firstPam.tuple_type);
-    
+
     *formatP = firstPam.format;
 }
 
@@ -737,8 +737,8 @@ computeHistogram(FILE *         const ifP,
 
 static void
 computeColorMapFromInput(FILE *                const ifP,
-                         bool                  const allColors, 
-                         int                   const reqColors, 
+                         bool                  const allColors,
+                         int                   const reqColors,
                          enum methodForLargest const methodForLargest,
                          enum methodForRep     const methodForRep,
                          int *                 const formatP,
@@ -755,7 +755,7 @@ computeColorMapFromInput(FILE *                const ifP,
 
    The colormap has the same maxval as the input.
 
-   Put the colormap in newly allocated storage as a tupletable2 
+   Put the colormap in newly allocated storage as a tupletable2
    and return its address as *colormapP.  Return the number of colors in
    it as *colorsP and its maxval as *colormapMaxvalP.
 
@@ -766,7 +766,7 @@ computeColorMapFromInput(FILE *                const ifP,
     tupletable2 colorfreqtable;
 
     computeHistogram(ifP, formatP, freqPamP, &colorfreqtable);
-    
+
     if (allColors) {
         *colormapP = colorfreqtable;
     } else {
@@ -787,16 +787,16 @@ computeColorMapFromInput(FILE *                const ifP,
 
 
 static void
-sortColormap(tupletable2  const colormap, 
+sortColormap(tupletable2  const colormap,
              sample       const depth) {
 /*----------------------------------------------------------------------------
-   Sort the colormap in place, in order of ascending Plane 0 value, 
+   Sort the colormap in place, in order of ascending Plane 0 value,
    the Plane 1 value, etc.
 
    Use insertion sort.
 -----------------------------------------------------------------------------*/
     int i;
-    
+
     pm_message("Sorting %u colors...", colormap.size);
 
     for (i = 0; i < colormap.size; ++i) {
@@ -806,8 +806,8 @@ sortColormap(tupletable2  const colormap,
             bool iIsGreater, iIsLess;
 
             iIsGreater = FALSE; iIsLess = FALSE;
-            for (plane = 0; 
-                 plane < depth && !iIsGreater && !iIsLess; 
+            for (plane = 0;
+                 plane < depth && !iIsGreater && !iIsLess;
                  ++plane) {
                 if (colormap.table[i]->tuple[plane] >
                     colormap.table[j]->tuple[plane])
@@ -815,7 +815,7 @@ sortColormap(tupletable2  const colormap,
                 else if (colormap.table[i]->tuple[plane] <
                          colormap.table[j]->tuple[plane])
                     iIsLess = TRUE;
-            }            
+            }
             if (iIsGreater) {
                 for (plane = 0; plane < depth; ++plane) {
                     sample const temp = colormap.table[i]->tuple[plane];
@@ -824,21 +824,21 @@ sortColormap(tupletable2  const colormap,
                     colormap.table[j]->tuple[plane] = temp;
                 }
             }
-        }    
+        }
     }
 }
 
 
 
-static void 
+static void
 colormapToSquare(struct pam * const pamP,
                  tupletable2  const colormap,
                  tuple ***    const outputRasterP) {
     {
         unsigned int const intsqrt = (int)sqrt((float)colormap.size);
-        if (intsqrt * intsqrt == colormap.size) 
+        if (SQR(intsqrt) == colormap.size)
             pamP->width = intsqrt;
-        else 
+        else
             pamP->width = intsqrt + 1;
     }
     {
@@ -852,17 +852,17 @@ colormapToSquare(struct pam * const pamP,
         tuple ** outputRaster;
         unsigned int row;
         unsigned int colormapIndex;
-        
+
         outputRaster = pnm_allocpamarray(pamP);
 
         colormapIndex = 0;  /* initial value */
-        
+
         for (row = 0; row < pamP->height; ++row) {
             unsigned int col;
             for (col = 0; col < pamP->width; ++col) {
                 unsigned int plane;
                 for (plane = 0; plane < pamP->depth; ++plane) {
-                    outputRaster[row][col][plane] = 
+                    outputRaster[row][col][plane] =
                         colormap.table[colormapIndex]->tuple[plane];
                 }
                 if (colormapIndex < colormap.size-1)
@@ -870,24 +870,24 @@ colormapToSquare(struct pam * const pamP,
             }
         }
         *outputRasterP = outputRaster;
-    } 
+    }
 }
 
 
 
-static void 
+static void
 colormapToSingleRow(struct pam * const pamP,
                     tupletable2  const colormap,
                     tuple ***    const outputRasterP) {
 
     tuple ** outputRaster;
     unsigned int col;
-    
+
     pamP->width = colormap.size;
     pamP->height = 1;
-    
+
     outputRaster = pnm_allocpamarray(pamP);
-    
+
     for (col = 0; col < pamP->width; ++col) {
         int plane;
         for (plane = 0; plane < pamP->depth; ++plane)
@@ -904,7 +904,7 @@ colormapToImage(int                const format,
                 tupletable2        const colormap,
                 bool               const sort,
                 bool               const square,
-                struct pam *       const outpamP, 
+                struct pam *       const outpamP,
                 tuple ***          const outputRasterP) {
 /*----------------------------------------------------------------------------
    Create a tuple array and pam structure for an image which includes
@@ -924,9 +924,9 @@ colormapToImage(int                const format,
     if (sort)
         sortColormap(colormap, outpamP->depth);
 
-    if (square) 
+    if (square)
         colormapToSquare(outpamP, colormap, outputRasterP);
-    else 
+    else
         colormapToSingleRow(outpamP, colormap, outputRasterP);
 }
 
@@ -950,8 +950,8 @@ main(int argc, char * argv[] ) {
     ifP = pm_openr(cmdline.inputFilespec);
 
     computeColorMapFromInput(ifP,
-                             cmdline.allcolors, cmdline.newcolors, 
-                             cmdline.methodForLargest, 
+                             cmdline.allcolors, cmdline.newcolors,
+                             cmdline.methodForLargest,
                              cmdline.methodForRep,
                              &format, &colormapPam, &colormap);
 
@@ -964,9 +964,9 @@ main(int argc, char * argv[] ) {
         pm_message("Generating %u x %u image", outpam.width, outpam.height);
 
     outpam.file = stdout;
-    
+
     pnm_writepam(&outpam, colormapRaster);
-    
+
     pnm_freetupletable2(&colormapPam, colormap);
 
     pnm_freepamarray(colormapRaster, &outpam);
@@ -975,3 +975,6 @@ main(int argc, char * argv[] ) {
 
     return 0;
 }
+
+
+
diff --git a/pm_config.in.h b/pm_config.in.h
index 2b92c617..b30bccfe 100644
--- a/pm_config.in.h
+++ b/pm_config.in.h
@@ -10,7 +10,7 @@
 
   Wherever possible, Netpbm handles customization via the make files
   instead of via this file.  However, Netpbm's make file philosophy
-  discourages lining up a bunch of -D options on every compile, so a 
+  discourages lining up a bunch of -D options on every compile, so a
   #define here would be preferable to a -D compile option.
 
 **************************************************************************/
@@ -38,12 +38,12 @@
    what feature sets his program relies.
 
    But some C library developers have misunderstood this and think of these
-   macros like the old __ansi__ macro, which tells the C library, "Don't 
+   macros like the old __ansi__ macro, which tells the C library, "Don't
    have any features that aren't in the ANSI standard."  I.e. it's just
    the opposite -- the macro subtracts features instead of adding them.
 
    This means that on some platforms, Netpbm programs must define
-   _POSIX_SOURCE, and on others, it must not.  Netpbm's POSIX_IS_IMPLIED 
+   _POSIX_SOURCE, and on others, it must not.  Netpbm's POSIX_IS_IMPLIED
    macro indicates that we're on a platform where we need not define
    _POSIX_SOURCE (and probably must not).
 
@@ -176,7 +176,7 @@
   #if (!defined(__inline__))
     #if (defined(__sgi) || defined(_AIX))
       #define __inline__ __inline
-    #else   
+    #else
       #define __inline__
     #endif
   #endif
@@ -195,7 +195,7 @@
 #else
   #if (defined(__sgi))
     #define LITERAL_FN_DEF_MATCH 1
-  #else   
+  #else
     #define LITERAL_FN_DEF_MATCH 0
   #endif
 #endif
@@ -333,7 +333,7 @@ typedef int qsort_comparison_fn(const void *, const void *);
 #if MSVCRT
   #define pm_mkdir(dir, perm) _mkdir(dir)
 #else
-  #define pm_mkdir(dir, perm) mkdir(dir, perm) 
+  #define pm_mkdir(dir, perm) mkdir(dir, perm)
 #endif
 
 #if MSVCRT
diff --git a/test/Test-Order b/test/Test-Order
index 6abc2287..8bda73a4 100644
--- a/test/Test-Order
+++ b/test/Test-Order
@@ -1,4 +1,4 @@
-# General test
+# General tests
 
 all-in-place.test
 legacy-names.test
@@ -63,6 +63,7 @@ pnminvert.test
 pamchannel.test
 ppmchange.test
 pambackground.test
+pnmpaste-pbm.test
 
 pbmpscale.test
 pnmremap1.test
@@ -78,6 +79,7 @@ pnmshear.test
 pgmbentley.test
 
 ppmmix.test
+pammixmulti-identity.test
 
 # Symmetry test
 
@@ -111,6 +113,7 @@ pamdice-roundtrip.test
 pamslice-roundtrip.test
 lookup-roundtrip.test
 enlarge-reduce-roundtrip.test
+cut-cat-roundtrip.test
 
 # Round-trip tests : lossless converters
 
@@ -119,6 +122,7 @@ atari-roundtrip.test
 atk-roundtrip.test
 avs-roundtrip.test
 bmp-roundtrip.test
+bmp-quant-roundtrip.test
 cis-roundtrip.test
 cmuw-roundtrip.test
 facesaver-roundtrip.test
diff --git a/test/bmp-quant-roundtrip.ok b/test/bmp-quant-roundtrip.ok
new file mode 100644
index 00000000..5262df53
--- /dev/null
+++ b/test/bmp-quant-roundtrip.ok
@@ -0,0 +1,6 @@
+colors=256, bpp=8
+0 0 0 : 0
+0 0 0 : 0
+colors=16, bpp=4
+0 0 0 : 0
+0 0 0 : 0
diff --git a/test/bmp-quant-roundtrip.test b/test/bmp-quant-roundtrip.test
new file mode 100755
index 00000000..2c223b7c
--- /dev/null
+++ b/test/bmp-quant-roundtrip.test
@@ -0,0 +1,36 @@
+#! /bin/bash
+# This script tests: bmptopnm ppmtobmp pnmquant
+# Also requires: ppmhist
+
+tmpdir=${tmpdir:-/tmp}
+quant_ppm=${tmpdir}/quant.ppm
+
+colors=256      # any value between 2 - 256 works
+bpp=8
+echo colors=${colors}, bpp=${bpp} 
+
+pnmquant ${colors} testimg.ppm > ${quant_ppm}
+
+for mode in "-windows" "-os2"
+  do
+  ppmtobmp $mode -bpp=${bpp} ${quant_ppm} | bmptopnm | \
+    cmp -s - ${quant_ppm} > /dev/null
+  echo ${PIPESTATUS[@]} ":" $?
+  done
+
+rm ${quant_ppm}
+
+colors=16      # any value between 2 - 16 works
+bpp=4
+echo colors=${colors}, bpp=${bpp}
+
+pnmquant ${colors} testimg.ppm > ${quant_ppm}
+
+for mode in "-windows" "-os2"
+  do
+  ppmtobmp -bpp=${bpp} ${quant_ppm} | bmptopnm | \
+    cmp -s - ${quant_ppm} > /dev/null
+  echo ${PIPESTATUS[@]} ":" $?
+  done
+
+rm ${quant_ppm}
diff --git a/test/bmp-roundtrip.ok b/test/bmp-roundtrip.ok
index 67f7a1fe..4f4f8367 100644
--- a/test/bmp-roundtrip.ok
+++ b/test/bmp-roundtrip.ok
@@ -1,2 +1,20 @@
-1926073387 101484
+PBM
+2425386270 41
+2425386270 41
+2425386270 41
 2425386270 41
+PPM
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+PGM
+1571496937 33838
+1571496937 33838
+1571496937 33838
+1571496937 33838
+1571496937 33838
+1571496937 33838
+1571496937 33838
+1571496937 33838
+1571496937 33838
diff --git a/test/bmp-roundtrip.test b/test/bmp-roundtrip.test
index be9a4548..c9ef363a 100755
--- a/test/bmp-roundtrip.test
+++ b/test/bmp-roundtrip.test
@@ -1,7 +1,42 @@
 #! /bin/bash
 # This script tests: bmptopnm ppmtobmp
-# Also requires:
+# Also requires: pamchannel pamtopnm pamseq
 
+tmpdir=${tmpdir:-/tmp}
 
-ppmtobmp testimg.ppm | bmptopnm | cksum
-ppmtobmp testgrid.pbm | bmptopnm | cksum
+# Test 1.  Should print 2425386270 41 four times
+
+echo PBM
+
+for mode in "" "-bpp=1" "-windows" "-os2"
+  do
+  ppmtobmp ${mode} testgrid.pbm | bmptopnm | cksum
+  done
+
+# Test 2.  Should print 1926073387 101484 four times
+
+echo PPM
+
+for mode in "" "-bpp=24" "-windows" "-os2"
+  do
+  ppmtobmp ${mode} testimg.ppm | bmptopnm | cksum
+  done
+
+# Test 3.  Should print 1571496937 33838 nine times
+
+echo PGM
+
+red_pgm=${tmpdir}/red.pgm
+mapfile_pgm=${tmpdir}/mapfile.pgm
+pamseq -tupletype="GRAYSCALE" 1 255 > ${mapfile_pgm}
+
+pamchannel -infile=testimg.ppm -tupletype="GRAYSCALE" 0 | \
+    pamtopnm | tee ${red_pgm} | cksum
+
+for mode in "" "-bpp=8" "-windows" "-os2"
+  do
+  ppmtobmp ${mode} ${red_pgm} | bmptopnm | cksum
+  ppmtobmp ${mode} -mapfile=${mapfile_pgm} ${red_pgm} | bmptopnm | cksum
+  done
+
+rm ${mapfile_pgm} ${red_pgm}
\ No newline at end of file
diff --git a/test/cut-cat-roundtrip.ok b/test/cut-cat-roundtrip.ok
new file mode 100644
index 00000000..bc9b8cb4
--- /dev/null
+++ b/test/cut-cat-roundtrip.ok
@@ -0,0 +1,92 @@
+Test 1.
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+Test 2.
+3891261972 202953
+3891261972 202953
+3891261972 202953
+3891261972 202953
+3891261972 202953
+3891261972 202953
+Test 3.
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+Test 4.
+26789469 202953
+26789469 202953
+26789469 202953
+26789469 202953
+26789469 202953
+Test 5.
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+Test 6.
+1887700557 73
+1887700557 73
+1887700557 73
+1887700557 73
+1887700557 73
+1887700557 73
+1887700557 73
+1887700557 73
+1887700557 73
+1887700557 73
+1887700557 73
+1887700557 73
+1887700557 73
+1887700557 73
+1887700557 73
+Test 7.
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+Test 8.
+3221289196 73
+3221289196 73
+3221289196 73
+3221289196 73
+3221289196 73
+3221289196 73
+3221289196 73
+3221289196 73
+3221289196 73
+3221289196 73
+3221289196 73
+3221289196 73
+3221289196 73
+3221289196 73
+3221289196 73
+3221289196 73
+3221289196 73
diff --git a/test/cut-cat-roundtrip.test b/test/cut-cat-roundtrip.test
new file mode 100755
index 00000000..95ee5279
--- /dev/null
+++ b/test/cut-cat-roundtrip.test
@@ -0,0 +1,128 @@
+#! /bin/bash
+# This script tests: pamcut
+# Also requires: pnmcat pnmpad
+
+tmpdir=${tmpdir:-/tmp}
+quant_ppm=${tmpdir}/quant.ppm
+
+right_pbm=${tmpdir}/right.pbm
+left_pbm=${tmpdir}/left.pbm
+right_ppm=${tmpdir}/right.ppm
+left_ppm=${tmpdir}/left.ppm
+bottom_pbm=${tmpdir}/bottom.pbm
+top_pbm=${tmpdir}/top.pbm
+bottom_ppm=${tmpdir}/bottom.ppm
+top_ppm=${tmpdir}/top.ppm
+
+
+# Test 1.  Should print 1926073387 101484 six times
+echo Test 1.
+
+cat testimg.ppm | cksum
+for i in 0 1 128 224 225
+  do
+  pamcut -left=$((i+1)) testimg.ppm > ${right_ppm}
+  pamcut -right=$i      testimg.ppm > ${left_ppm}
+  pnmcat -lr ${left_ppm} ${right_ppm} | \
+    pamcut -left=0 -width=227| cksum
+  rm ${left_ppm} ${right_ppm}
+  done
+
+
+# Test 2.  Should print 3891261972 202953 six times
+# Not roundtrip.  Padding added to right.
+echo Test 2.
+
+pnmpad -right=227 -black testimg.ppm | cksum
+for i in  0 1 128 224 225
+  do
+  pamcut -left=$((i+1)) -width=227 -pad testimg.ppm > ${right_ppm}
+  pamcut -right=$i      -width=227 -pad testimg.ppm > ${left_ppm}
+  pnmcat -lr ${left_ppm} ${right_ppm} ${left_ppm} | \
+    pamcut -left=$((227-i-1))  -width=$((227*2)) | cksum
+  rm ${left_ppm} ${right_ppm}
+  done
+
+
+# Test 3.  Should print 1926073387 101484 five times
+echo Test 3.
+
+cat testimg.ppm | cksum
+for i in 0 1 70 147
+  do
+  pamcut -top=$((i+1)) testimg.ppm > ${bottom_ppm}
+  pamcut -bottom=$i    testimg.ppm > ${top_ppm}
+  pnmcat -tb ${top_ppm} ${bottom_ppm} | \
+    pamcut -top=0 -height=149 | cksum
+  rm ${top_ppm} ${bottom_ppm}
+  done
+
+# Test 4.  Should print 26789469 202953 five times
+# Not roundtrip.  Padding added to bottom.
+echo Test 4.
+
+pnmpad -bottom=149 -black testimg.ppm | cksum
+for i in 0 1 70 147
+  do
+  pamcut -top=$((i+1)) -height=149 -pad testimg.ppm > ${bottom_ppm}
+  pamcut -bottom=$i    -height=149 -pad testimg.ppm > ${top_ppm}
+  pnmcat -tb ${top_ppm} ${bottom_ppm} ${top_ppm} | \
+    pamcut -top=$((149-i-1))  -height=$((149*2)) | cksum
+  rm ${top_ppm} ${bottom_ppm}
+  done
+
+# Test 5.  Should print 2425386270 41 fourteen times
+echo Test 5.
+
+cat testgrid.pbm | cksum
+for i in `seq 0 12`
+  do
+  pamcut -left=$((i+1)) testgrid.pbm > ${right_pbm}
+  pamcut -right=$i      testgrid.pbm > ${left_pbm}
+  pnmcat -lr ${left_pbm} ${right_pbm} | \
+    pamcut -left=0 -width=14 | cksum
+  rm ${left_pbm} ${right_pbm}
+  done
+
+
+# Test 6.  Should print 1887700557 73 fifteen times
+# Not roundtrip.  Padding added to right.
+echo Test 6.
+
+pnmpad -right=14 -black testgrid.pbm | cksum
+for i in `seq 0 13`
+  do
+  pamcut -left=$((i+1)) -width=14 -pad testgrid.pbm > ${right_pbm}
+  pamcut -right=$i      -width=14 -pad testgrid.pbm > ${left_pbm}
+  pnmcat -lr ${left_pbm} ${right_pbm} ${left_pbm} | \
+    pamcut -left=$((14-i-1)) -width=28 | cksum
+  rm ${left_pbm} ${right_pbm}
+  done
+
+# Test 7.  Should print 2425386270 41 sixteen times
+echo Test 7.
+
+cat testgrid.pbm | cksum
+for i in `seq 0 14`
+  do
+  pamcut -top=$((i+1)) testgrid.pbm > ${bottom_pbm}
+  pamcut -bottom=$i    testgrid.pbm > ${top_pbm}
+  pnmcat -tb ${top_pbm} ${bottom_pbm} | \
+    pamcut -top=0 -height=16 | cksum
+  rm ${top_pbm} ${bottom_pbm}
+  done
+
+# Test 8.  Should print 3221289196 73 seventeen times
+# Not roundtrip.  Padding added to bottom.
+echo Test 8.
+
+pnmpad -bottom=16 -black testgrid.pbm | cksum
+for i in `seq 0 15`
+  do
+  pamcut -top=$((i+1)) -height=16 -pad testgrid.pbm > ${bottom_pbm}
+  pamcut -bottom=$i    -height=16 -pad testgrid.pbm > ${top_pbm}
+  pnmcat -tb ${top_pbm} ${bottom_pbm} ${top_pbm} | \
+    pamcut -top=$((16-i-1)) -height=32 | cksum
+  rm ${top_pbm} ${bottom_pbm}
+  done
+
diff --git a/test/g3-roundtrip.ok b/test/g3-roundtrip.ok
index 853d06d2..603c9457 100644
--- a/test/g3-roundtrip.ok
+++ b/test/g3-roundtrip.ok
@@ -1,13 +1,13 @@
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
+0 0 0 : 0
+0 0 0 : 0
+0 0 0 0 : 0
+0 0 0 : 0
+0 0 0 : 0
+0 0 0 0 : 0
+0 0 0 0 : 0
+0 0 0 : 0
+0 0 0 : 0
+0 0 0 : 0
 1777627284 265
 2985378006 3135
 3651878552 3135
diff --git a/test/g3-roundtrip.test b/test/g3-roundtrip.test
index 10174733..6e31c587 100755
--- a/test/g3-roundtrip.test
+++ b/test/g3-roundtrip.test
@@ -9,15 +9,15 @@ wideb_pbm=${tmpdir}/wideb.pbm
 
 pbmtog3 -nofixedwidth testgrid.pbm | \
 g3topbm -width=14 | cmp -s - testgrid.pbm
-echo $?
+echo ${PIPESTATUS[@]} ":" $?
 
 pbmtog3 -nofixedwidth -reversebits testgrid.pbm | \
 g3topbm -width=14 -reversebits | cmp -s - testgrid.pbm
-echo $?
+echo ${PIPESTATUS[@]} ":" $?
 
 pbmtog3 testgrid.pbm | \
 g3topbm  | pnmcrop -white -right -bottom | \
- cmp -s - testgrid.pbm ; echo $?
+ cmp -s - testgrid.pbm ; echo ${PIPESTATUS[@]} ":" $?
 
 # works with gawk and mawk
 # produce all possible 8-bit patterns
@@ -28,31 +28,31 @@ LC_ALL=C awk 'BEGIN { print "P4";         # header
                            printf("%c",i) }' > ${complete256_pbm}
 
 pbmtog3 -nofixedwidth  ${complete256_pbm} |  g3topbm -width=8 | \
- cmp -s - ${complete256_pbm} ; echo $?
+ cmp -s - ${complete256_pbm} ; echo ${PIPESTATUS[@]} ":" $?
 
 pbmtog3 -reverse -nofixedwidth ${complete256_pbm} | \
 g3topbm -reversebits -width=8 | \
- cmp -s - ${complete256_pbm} ; echo $?
+ cmp -s - ${complete256_pbm} ; echo ${PIPESTATUS[@]} ":" $?
 
 pbmtog3 -align8 ${complete256_pbm} | \
 g3topbm -width=1728 | pnmcrop -white -right | \
- cmp -s - ${complete256_pbm} ; echo $?
+ cmp -s - ${complete256_pbm} ; echo ${PIPESTATUS[@]} ":" $?
 
 pbmtog3 -align16 ${complete256_pbm} | \
 g3topbm -width=1728 | pnmcrop -white -right | \
- cmp -s - ${complete256_pbm} ; echo $?
+ cmp -s - ${complete256_pbm} ; echo ${PIPESTATUS[@]} ":" $?
 
 pbmmake -w 5000 5 > ${widew_pbm}
 pbmtog3 -nofixedwidth ${widew_pbm} | g3topbm | \
- cmp -s - ${widew_pbm} ; echo $?
+ cmp -s - ${widew_pbm} ; echo ${PIPESTATUS[@]} ":" $?
 
 pbmtog3 -nofixedwidth ${widew_pbm} | \
 g3topbm -width=5000 | \
- cmp -s - ${widew_pbm} ; echo $?
+ cmp -s - ${widew_pbm} ; echo ${PIPESTATUS[@]} ":" $?
 
 pbmmake -b 5000 5 > ${wideb_pbm}
 pbmtog3 -nofixedwidth ${wideb_pbm} | g3topbm | \
- cmp -s - ${wideb_pbm} ; echo $?
+ cmp -s - ${wideb_pbm} ; echo ${PIPESTATUS[@]} ":" $?
 
 cat ${complete256_pbm} | cksum
 cat ${wideb_pbm} | cksum
diff --git a/test/gif-quant-roundtrip.ok b/test/gif-quant-roundtrip.ok
index 573541ac..b813e8db 100644
--- a/test/gif-quant-roundtrip.ok
+++ b/test/gif-quant-roundtrip.ok
@@ -1 +1 @@
-0
+0 0 0 : 0
diff --git a/test/gif-quant-roundtrip.test b/test/gif-quant-roundtrip.test
index 8b911740..910fa369 100755
--- a/test/gif-quant-roundtrip.test
+++ b/test/gif-quant-roundtrip.test
@@ -13,6 +13,6 @@ quant_ppm=${tmpdir}/quant.ppm
 pnmquant ${colors} testimg.ppm > ${quant_ppm} &&
 pamtogif ${quant_ppm} | giftopnm | \
    cmp -s - ${quant_ppm} > /dev/null
-echo $?
+echo ${PIPESTATUS[@]} ":" $?
 
 rm ${quant_ppm}
diff --git a/test/gif-roundtrip.ok b/test/gif-roundtrip.ok
index 1704ba03..607ebd5c 100644
--- a/test/gif-roundtrip.ok
+++ b/test/gif-roundtrip.ok
@@ -10,13 +10,13 @@
 2425386270 41
 2425386270 41
 P1 4 1 0101 
-4030 0 , 4030 0
-4031 0 , 4031 0
-4097 0 , 4097 0
-238 0 , 238 0
-239 0 , 239 0
-240 0 , 240 0
-241 0 , 241 0
-255 0 , 255 0
-256 0 , 256 0
-257 0 , 257 0
+4030 : 0 0 0 0 : 0 , 4030 : 0 0 0 0 : 0
+4031 : 0 0 0 0 : 0 , 4031 : 0 0 0 0 : 0
+4097 : 0 0 0 0 : 0 , 4097 : 0 0 0 0 : 0
+238 : 0 0 0 0 : 0 , 238 : 0 0 0 0 : 0
+239 : 0 0 0 0 : 0 , 239 : 0 0 0 0 : 0
+240 : 0 0 0 0 : 0 , 240 : 0 0 0 0 : 0
+241 : 0 0 0 0 : 0 , 241 : 0 0 0 0 : 0
+255 : 0 0 0 0 : 0 , 255 : 0 0 0 0 : 0
+256 : 0 0 0 0 : 0 , 256 : 0 0 0 0 : 0
+257 : 0 0 0 0 : 0 , 257 : 0 0 0 0 : 0
diff --git a/test/gif-roundtrip.test b/test/gif-roundtrip.test
index b49cc6d2..1e6c7760 100755
--- a/test/gif-roundtrip.test
+++ b/test/gif-roundtrip.test
@@ -124,10 +124,10 @@ for size in 4030 4031 4097
     cmp - ${test_pgm}
   # pamdepth ${maxval} is necessary because
   # giftopnm output is maxval 255
-  echo -n ${size} $? ", "
+  echo -n ${size} ":" ${PIPESTATUS[@]} ":" $? ", "
   pamtogif -nolzw ${test_pgm} | giftopnm | pamdepth ${maxval} | \
     cmp - ${test_pgm}
-  echo ${size} $?
+  echo ${size} ":" ${PIPESTATUS[@]} ":" $?
   rm ${test_pgm}
   done 
 
@@ -153,10 +153,10 @@ for size in 238 239 240 241 255 256 257
   pamcut -height=${size} ${test257_pgm} > ${test_pgm} &&
   pamtogif -verbose ${test_pgm} | giftopnm | pamdepth ${maxval} | \
     cmp - ${test_pgm}
-  echo -n ${size} $? ", "
+  echo -n ${size} ":" ${PIPESTATUS[@]} ":" $? ", "
   pamtogif -nolzw -verbose ${test_pgm} | giftopnm | pamdepth ${maxval} | \
     cmp - ${test_pgm}
-  echo ${size} $?
+  echo ${size} ":" ${PIPESTATUS[@]} ":" $?
   rm ${test_pgm}
   done 
 
diff --git a/test/palm-roundtrip.ok b/test/palm-roundtrip.ok
index 5bd3cb0a..b9ea3056 100644
--- a/test/palm-roundtrip.ok
+++ b/test/palm-roundtrip.ok
@@ -1,9 +1,11 @@
+Test 1
 584219238 236
 584219238 236
 584219238 236
 584219238 236
 584219238 236
-0
-0
-0
-0
+Test 2
+0 0 0 : 0
+0 0 0 : 0
+0 0 0 : 0
+0 0 0 : 0
diff --git a/test/palm-roundtrip.test b/test/palm-roundtrip.test
index 9c053ba9..b00454ca 100755
--- a/test/palm-roundtrip.test
+++ b/test/palm-roundtrip.test
@@ -8,6 +8,8 @@ test256color_ppm=${tmpdir}/test256color.ppm
 
 # Test 1. Should print 584219238 236  5 times
 
+echo "Test 1"
+
 pamdepth 15 testgrid.pbm | tee ${test4bit_pgm} | cksum
 
 for flags in "" \
@@ -21,7 +23,9 @@ rm ${test4bit_pgm}
 
 # Test 2. Should print 0 4 times
 
-pnmquant 256 testimg.ppm > ${test256color_ppm}
+echo "Test 2"
+
+pnmquant 256 testimg.ppm > ${test256color_ppm} || echo "pnmquant failed"
 
 for flags in "" \
              "-scanline_compression" \
@@ -29,7 +33,7 @@ for flags in "" \
              "-packbits_compression" 
   do pnmtopalm -colormap $flags ${test256color_ppm} | palmtopnm | \
      cmp -s - ${test256color_ppm} > /dev/null
-     echo $?
+     echo ${PIPESTATUS[@]} ":" $?
   done
 
 rm ${test256color_ppm}
diff --git a/test/pamcut.ok b/test/pamcut.ok
index 61ef99bc..b08bc531 100644
--- a/test/pamcut.ok
+++ b/test/pamcut.ok
@@ -1,4 +1,19 @@
+Test 1.
 2958909756 124815
+Test 2.
 1550940962 10933
+Test 3.
 708474423 14
+708474423 14
+Test 4.
+659346598 80124
+659346598 80124
+659346598 80124
+659346598 80124
+Test 5.
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+Test 6.
 3412257956 129
diff --git a/test/pamcut.test b/test/pamcut.test
index fd9185a3..9971b1a5 100755
--- a/test/pamcut.test
+++ b/test/pamcut.test
@@ -2,17 +2,46 @@
 # This script tests: pamcut pbmmake
 # Also requires:
 
-
 # Test 1.  Should print 2958909756 124815
+echo Test 1.
+
 pamcut -top 0 -left 0 -width 260 -height 160 \
   -pad testimg.ppm | cksum
 
 # Test 2.  Should print 1550940962 10933
+echo Test 2.
+
 pamcut -top 200 -left 120 -width 40 -height 40 \
   -pad testimg.ppm | cksum
 
-# Test 3.  Should print 708474423 14
+# Test 3.  Should print 708474423 14 twice
+echo Test 3.
+
 pamcut -top 5 -left 5 -bottom 5 -right 5 testimg.ppm | cksum
+pamcut -width 1 -height 1 -bottom 5 -right 5 testimg.ppm | cksum
+
+
+# Test 4.  Should print 659346598 80124 four times
+echo Test 4.
+
+pamcut -croptop 10 -cropleft 10 -cropbottom 10 -cropright 10 testimg.ppm | \
+  cksum
+pamcut -top 10 -left 10 -bottom 138 -right 216 testimg.ppm | cksum
+pamcut -top 10 -left 10 -bottom -11 -right -11 testimg.ppm | cksum
+pamcut -top 10 -left 10 -width 207 -height 129 testimg.ppm | cksum
+
+
+# Test 5. Should print 2425386270 41 four times
+echo Test 5.
+
+pamcut -croptop 0 -cropleft 0 -cropbottom 0 -cropright 0 testgrid.pbm | \
+  cksum
+pamcut -top 0 -left 0 -bottom 15 -right 13 testgrid.pbm | cksum
+pamcut -top 0 -left 0 -bottom -1 -right -1 testgrid.pbm | cksum
+pamcut -top 0 -left 0 -width 14 -height 16 testgrid.pbm | cksum
+
+
+# Test 6.  Should print 3412257956 129
+echo Test 6.
 
-# Test 4.  Should print 3412257956 129
 pbmmake -g 50 50 | pamcut 5 5 30 30 | cksum
diff --git a/test/pammixmulti-identity.ok b/test/pammixmulti-identity.ok
new file mode 100644
index 00000000..9e712f7f
--- /dev/null
+++ b/test/pammixmulti-identity.ok
@@ -0,0 +1,22 @@
+Test 1.
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+Test 2.
+1926073387 101484
+1926073387 101484
+1926073387 101484
+Test 3.
+1926073387 101484
+1926073387 101484
+1926073387 101484
+Test 4.
+127
+127
+127
+127
+127
+127
diff --git a/test/pammixmulti-identity.test b/test/pammixmulti-identity.test
new file mode 100755
index 00000000..d205c359
--- /dev/null
+++ b/test/pammixmulti-identity.test
@@ -0,0 +1,77 @@
+#! /bin/bash
+# This script tests: pammixmulti
+# Also requires: pgmnoise pnminvert pamsumm
+
+tmpdir=${tmpdir:-/tmp}
+
+# Test 1.  Should print 1926073387 101484 six times
+echo Test 1.
+
+pammixmulti testimg.ppm | cksum
+pammixmulti testimg.ppm testimg.ppm | cksum
+pammixmulti testimg.ppm testimg.ppm testimg.ppm | cksum
+pammixmulti -blend=average testimg.ppm testimg.ppm | cksum
+pammixmulti -blend=average testimg.ppm testimg.ppm testimg.ppm | cksum
+pammixmulti -blend=random -randomseed=1 \
+    testimg.ppm testimg.ppm testimg.ppm | cksum
+
+
+# Test 2.  Should print 1926073387 101484 three times
+echo Test 2.
+
+mask_pgm=${tmpdir}/mask.pgm
+pgmnoise -maxval=2 -randomseed=1 227 149 > ${mask_pgm}
+
+for sd in 0.5 1.2 3.0 
+  do
+  pammixmulti -blend=mask -maskfile=${mask_pgm} -stdev=${sd} \
+      testimg.ppm testimg.ppm testimg.ppm | cksum
+  done
+rm ${mask_pgm}
+
+# Test 3.  Should print
+echo Test 3.
+
+noise_pgm=${tmpdir}/noise.pgm
+pgmnoise --randomseed=1 227 149 > ${noise_pgm}
+
+pammixmulti -blend=mask -maskfile=${noise_pgm} \
+    testimg.ppm testimg.ppm | cksum
+pammixmulti -blend=mask -maskfile=${noise_pgm} \
+    testimg.ppm testimg.ppm testimg.ppm | cksum
+pammixmulti -blend=mask -maskfile=${noise_pgm} \
+    testimg.ppm testimg.ppm testimg.ppm testimg.ppm | cksum
+rm ${noise_pgm}
+
+
+# Test 4.
+
+# Mix image with its own inverse.
+# Output should be a monotone gray sheet.
+#  Should print 127 six times
+echo Test 4.
+
+invert_ppm=${tmpdir}/invert.ppm
+monotone_ppm=${tmpdir}/monotone.ppm
+
+pnminvert testimg.ppm > ${invert_ppm}
+
+pammixmulti -blend=average testimg.ppm ${invert_ppm} | tee ${monotone_ppm} | \
+  pamsumm -brief -max &&
+  pamsumm -brief -min ${monotone_ppm}
+rm ${monotone_ppm}
+
+pammixmulti -blend=average \
+    testimg.ppm ${invert_ppm} testimg.ppm ${invert_ppm} | \
+  tee ${monotone_ppm} | \
+  pamsumm -brief -max &&
+  pamsumm -brief -min ${monotone_ppm}
+rm ${monotone_ppm}
+
+pammixmulti -blend=average \
+    testimg.ppm testimg.ppm ${invert_ppm} ${invert_ppm} | \
+  tee ${monotone_ppm} | \
+  pamsumm -brief -max &&
+  pamsumm -brief -min ${monotone_ppm}
+
+rm ${monotone_ppm} ${invert_ppm}
diff --git a/test/pbmtext-utf8.ok b/test/pbmtext-utf8.ok
index 9e65dec4..588bf617 100644
--- a/test/pbmtext-utf8.ok
+++ b/test/pbmtext-utf8.ok
@@ -2,7 +2,7 @@
 2066913605 5110
 2920616515 2301
 2920616515 2301
-0
+0 0 0 0 : 0
  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
-1
+0 1 : 1
diff --git a/test/pbmtext-utf8.test b/test/pbmtext-utf8.test
index 010c02db..cf495b7c 100755
--- a/test/pbmtext-utf8.test
+++ b/test/pbmtext-utf8.test
@@ -66,7 +66,7 @@ awk 'BEGIN { for (i=32; i<=126;++i) printf("%c",i); print ""; \
     LC_ALL=en_US.utf8 pbmtext -builtin bdf -wchar -text-dump | \
     cmp --quiet - ${output}
 
-echo $?
+echo ${PIPESTATUS[@]} ":" $?
 rm ${output}
 
 
@@ -92,4 +92,4 @@ echo "-----------------------------------------------------------" 1>&2
 LC_ALL=C \
 awk 'BEGIN { for (i=128; i<=129;++i) printf("%c",i);  print ""}' | \
         LC_ALL=en_US.utf8 pbmtext -builtin bdf -wchar -text-dump
-echo $?
+echo ${PIPESTATUS[@]} ":" $?
diff --git a/test/pdb-roundtrip.ok b/test/pdb-roundtrip.ok
index cb920669..b903da8d 100644
--- a/test/pdb-roundtrip.ok
+++ b/test/pdb-roundtrip.ok
@@ -3,16 +3,16 @@ pbm grid
 2224198737 25671
 2224198737 25671
 pbm tiled
-0 0 0
-0 0 0
-0 0 0
-0 0 0
+0 0 0 0 : 0
+0 0 0 0 : 0
+0 0 0 0 : 0
+0 0 0 0 : 0
 pgm ellipse
-0 0 0
-0 0 0
-0 0 0
-0 0 0
+0 0 0 0 0 : 0
+0 0 0 0 0 : 0
+0 0 0 0 0 : 0
+0 0 0 0 0 : 0
 pgm ellipse -4depth
-0 0 0
-0 0 0
-0 0 0
+0 0 0 0 0 : 0
+0 0 0 0 0 : 0
+0 0 0 0 0 : 0
diff --git a/test/pdb-roundtrip.test b/test/pdb-roundtrip.test
index a6de93d2..6b4e152c 100755
--- a/test/pdb-roundtrip.test
+++ b/test/pdb-roundtrip.test
@@ -24,7 +24,7 @@ for flag in "" "-compressed" "-maybecompressed" "-uncompressed"
   do
   pamtopdbimg ${flag} ${tiled_pbm} | pdbimgtopam | pamtopnm | \
     cmp -s - ${tiled_pbm}
-  echo ${PIPESTATUS[0]} ${PIPESTATUS[1]} $?
+  echo ${PIPESTATUS[@]} ":" $?
   done
 rm ${tiled_pbm}
 
@@ -37,7 +37,7 @@ for flag in "" "-compressed" "-maybecompressed" "-uncompressed"
     do
     pamtopdbimg ${flag} ${ellipse_pgm} | pdbimgtopam | \
       pamtopnm | pamdepth 3 | cmp -s - ${ellipse_pgm}
-    echo ${PIPESTATUS[0]} ${PIPESTATUS[1]} $?
+    echo ${PIPESTATUS[@]} ":" $?
     done
 rm ${ellipse_pgm}
 
@@ -50,6 +50,6 @@ for flag in "-compressed" "-maybecompressed" "-uncompressed"
     do
     pamtopdbimg -4depth ${flag} ${ellipse_pgm} | pdbimgtopam | \
       pamtopnm | pamdepth 15 | cmp -s - ${ellipse_pgm}
-    echo ${PIPESTATUS[0]} ${PIPESTATUS[1]} $?
+    echo ${PIPESTATUS[@]} ":" $?
     done
 rm ${ellipse_pgm}
\ No newline at end of file
diff --git a/test/pnmpaste-pbm.ok b/test/pnmpaste-pbm.ok
new file mode 100644
index 00000000..d3b0a7e8
--- /dev/null
+++ b/test/pnmpaste-pbm.ok
@@ -0,0 +1,22 @@
+Test 1.
+-replace
+P1 18 1 001010101010101011 
+-and
+P1 18 1 001111101111101111 
+-or
+P1 18 1 000010000010000011 
+-xor
+P1 18 1 010010010010010011 
+-nand
+P1 18 1 010000010000010011 
+-nor
+P1 18 1 011101111101111111 
+-nxor
+P1 18 1 001101101101101111 
+Test 2.
+-and  -nand
+P1 18 1 110000000000000001 
+-or  -nor
+P1 18 1 110000000000000001 
+-xor  -nxor
+P1 18 1 110000000000000001 
diff --git a/test/pnmpaste-pbm.test b/test/pnmpaste-pbm.test
new file mode 100755
index 00000000..b75797af
--- /dev/null
+++ b/test/pnmpaste-pbm.test
@@ -0,0 +1,47 @@
+#! /bin/bash
+# This script tests: pnmpaste
+# Also requires: pbmmake
+
+tmpdir=${tmpdir:-/tmp}
+base_pbm=${tmpdir}/font.pbm
+insert_pbm=${tmpdir}/insert.pbm
+
+cat > ${base_pbm} << EOF
+P1
+18 1
+000111000111000111
+EOF
+
+pbmmake -g 15 1 > ${insert_pbm}
+
+# Test 1.
+echo "Test 1."
+
+for operation in "-replace" "-and" "-or" "-xor" "-nand" "-nor" "-nxor"
+  do
+  echo ${operation} 
+  pnmpaste ${operation} -plain ${insert_pbm} 1 0 ${base_pbm} | tr '\n' ' '
+  echo
+  done
+
+
+# Test 2.
+# Perform an operation and its negative counterpart, combine the
+# resulting images with "-xor".
+# The untouched area of the base image should be 1; inserted area 0.
+
+echo "Test 2."
+
+positive_pbm=${tmpdir}/positive.pbm
+negative_pbm=${tmpdir}/negative.pbm
+
+for operation in "and" "or" "xor"
+  do
+  echo "-"$operation " -n"$operation 
+  pnmpaste "-"${operation} ${insert_pbm} 2 0 ${base_pbm} > ${positive_pbm}
+  pnmpaste "-n"${operation} ${insert_pbm} 2 0 ${base_pbm} > ${negative_pbm}
+  pnmpaste -xor -plain ${positive_pbm} 0 0 ${negative_pbm} | tr '\n ' ' '
+  echo
+  done
+
+rm ${base_pbm} ${insert_pbm} ${positive_pbm} ${negative_pbm}
diff --git a/test/pnmtile.ok b/test/pnmtile.ok
index 559d0f65..4a29e0dc 100644
--- a/test/pnmtile.ok
+++ b/test/pnmtile.ok
@@ -1,2 +1,2 @@
 4228632379 259
-0
+0 0 : 0
diff --git a/test/pnmtile.test b/test/pnmtile.test
index 409c0e50..e297da66 100755
--- a/test/pnmtile.test
+++ b/test/pnmtile.test
@@ -17,6 +17,6 @@ pnmtile 454 298 testimg.ppm > ${testimg4_ppm} &&
 pnmcat -lr testimg.ppm testimg.ppm > ${testimg2_ppm} &&
 pnmcat -tb ${testimg2_ppm} ${testimg2_ppm} | \
 cmp -s - ${testimg4_ppm}
-echo $?
+echo ${PIPESTATUS[@]} ":" $?
 
 rm ${testimg2_ppm} ${testimg4_ppm}
diff --git a/test/rgb3-roundtrip.ok b/test/rgb3-roundtrip.ok
index 64da849d..367e5429 100644
--- a/test/rgb3-roundtrip.ok
+++ b/test/rgb3-roundtrip.ok
@@ -3,4 +3,4 @@
 2425386270 41
 0
 0
-0
+0 0 : 0
diff --git a/test/rgb3-roundtrip.test b/test/rgb3-roundtrip.test
index cac52220..42fd822f 100755
--- a/test/rgb3-roundtrip.test
+++ b/test/rgb3-roundtrip.test
@@ -41,6 +41,6 @@ rgb3toppm ${testgrid_red} ${testgrid_grn} ${testgrid_blu} | \
 cmp -s ${testgrid_red} ${testgrid_grn} ; echo $?
 cmp -s ${testgrid_grn} ${testgrid_blu} ; echo $?
 pgmtopgm < testgrid.pbm | cmp -s - ${testgrid_red}
-  echo $?
+  echo ${PIPESTATUS[@]} ":" $?
 
 rm ${testgrid_pbm} ${testgrid_red} ${testgrid_grn} ${testgrid_blu}
diff --git a/test/targa-roundtrip.ok b/test/targa-roundtrip.ok
index 9a428195..514f970f 100644
--- a/test/targa-roundtrip.ok
+++ b/test/targa-roundtrip.ok
@@ -1,3 +1,43 @@
+Test 1
 2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+Test 2
+1571496937 33838
+1571496937 33838
 1571496937 33838
+1571496937 33838
+1571496937 33838
+1571496937 33838
+1571496937 33838
+1571496937 33838
+1571496937 33838
+1571496937 33838
+Test 3
+1926073387 101484
+1926073387 101484
+1926073387 101484
 1926073387 101484
+Test 4
+0 0 0 : 0
+0 0 0 : 0
+0 0 0 : 0
+0 0 0 : 0
+0 0 0 : 0
+0 0 0 : 0
+Test 5
+0 0 0 : 0
+0 0 0 : 0
+0 0 0 0 : 0
+0 0 0 0 : 0
+0 0 0 0 : 0
+0 0 0 0 : 0
+0 0 0 0 : 0
+0 0 0 0 : 0
diff --git a/test/targa-roundtrip.test b/test/targa-roundtrip.test
index f646b8c1..79b01b61 100755
--- a/test/targa-roundtrip.test
+++ b/test/targa-roundtrip.test
@@ -1,18 +1,80 @@
 #! /bin/bash
 # This script tests: pamtotga tgatoppm
-# Also requires: ppmtopgm pgmtopbm pamchannel
+# Also requires: ppmtopgm pgmtopbm pamchannel pnmquant pamdepth
 
+tmpdir=${tmpdir:-/tmp}
 
-#Test 1: Should print 2425386270 41, cksum of testgrid.pbm
+#Test 1: Should print 2425386270 41, cksum of testgrid.pbm, ten times
 
-pamtotga -mono testgrid.pbm | \
-  tgatoppm | ppmtopgm | \
-  pgmtopbm -threshold -val 0.5 | cksum
+echo "Test 1"
 
-#Test 2:  Should produce 1571496937 33838, cksum of testimg.red
-pamchannel -infile=testimg.ppm -tupletype="GRAYSCALE" 0 | \
-  pamtotga -cmap | tgatoppm | ppmtopgm | cksum
+for mode in "-mono" "-mono -norle" \
+            "-cmap" "-cmap -norle" "-cmap16" "-cmap16 -norle" \
+            "-rgb"  "-rgb  -norle" "" "-norle"
+  do
+  pamtotga ${mode} testgrid.pbm | \
+    tgatoppm | ppmtopgm | \
+    pgmtopbm -threshold -val 0.5 | cksum
+  done
 
-#Test 3: Should print 1926073387 101484, cksum of testimg.ppm
+#Test 2:  Should produce 1571496937 33838, cksum of testimg.red, ten times
 
-pamtotga -rgb testimg.ppm | tgatoppm | cksum
+echo "Test 2"
+
+test_pam=${tmpdir}/testimg.pgm
+pamchannel -infile=testimg.ppm -tupletype="GRAYSCALE" 0 > ${test_pam}
+
+for mode in "-mono" "-mono -norle" \
+            "-cmap" "-cmap -norle" "-cmap16" "-cmap16 -norle" \
+            "-rgb"  "-rgb  -norle" "" "-norle"
+  do
+  pamtotga ${mode} ${test_pam} | tgatoppm | ppmtopgm | cksum
+  done
+
+rm ${test_pam}
+
+
+#Test 3: Should print 1926073387 101484, cksum of testimg.ppm, four times
+
+echo "Test 3"
+
+for mode in "-rgb" "-rgb -norle" "" "-norle"
+  do
+  pamtotga ${mode} testimg.ppm | tgatoppm | cksum
+  done
+
+#Test 4: Should print 0 six times
+
+echo "Test 4"
+
+test256_ppm=${tmpdir}/test256.ppm
+pnmquant 256 testimg.ppm > ${test256_ppm} || echo "pnmquant failed"
+# test image may have less than 256 colors
+
+for mode in "-rgb" "-rgb -norle" "-cmap" "-cmap -norle" "" "-norle"
+  do
+  pamtotga ${mode} ${test256_ppm} | tgatoppm | cmp -s - ${test256_ppm}
+  echo ${PIPESTATUS[@]} ":" $?
+done
+
+
+#Test 5: Should print 0 eight times
+
+echo "Test 5"
+
+test256_31_ppm=${tmpdir}/test256-31.ppm
+pamdepth 31 ${test256_ppm} > ${test256_31_ppm} || echo "pamdepth failed"
+rm ${test256_ppm}
+
+for mode in "-cmap16" "-cmap16 -norle"
+  do pamtotga ${mode} ${test256_31_ppm} | tgatoppm | cmp -s - ${test256_31_ppm}
+  echo ${PIPESTATUS[@]} ":" $?
+  done
+
+for mode in  "-rgb" "-rgb -norle" "-cmap" "-cmap -norle" "" "-norle"
+  do pamtotga ${mode} ${test256_31_ppm} | tgatoppm | \
+     pamdepth 31 | cmp -s - ${test256_31_ppm}
+  echo ${PIPESTATUS[@]} ":" $?
+  done
+
+rm ${test256_31_ppm}
diff --git a/version.mk b/version.mk
index 8822223d..219ac63e 100644
--- a/version.mk
+++ b/version.mk
@@ -1,3 +1,3 @@
 NETPBM_MAJOR_RELEASE = 10
-NETPBM_MINOR_RELEASE = 84
-NETPBM_POINT_RELEASE = 5
+NETPBM_MINOR_RELEASE = 85
+NETPBM_POINT_RELEASE = 0