about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2020-06-28 17:52:14 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2020-06-28 17:52:14 +0000
commit1cd3ef0dd6c2236d0b329879bacd9360d01c88a1 (patch)
treea60016b5dd48fbf681ebfb43a6ca0d7e20a391d8
parentcbbf595776cee6b8d8a24becf49ee6468eeba712 (diff)
downloadnetpbm-mirror-1cd3ef0dd6c2236d0b329879bacd9360d01c88a1.tar.gz
netpbm-mirror-1cd3ef0dd6c2236d0b329879bacd9360d01c88a1.tar.xz
netpbm-mirror-1cd3ef0dd6c2236d0b329879bacd9360d01c88a1.zip
Promote Development to Advaanced - Release 10.91
git-svn-id: http://svn.code.sf.net/p/netpbm/code/advanced@3877 9d0c8265-081b-0410-96cb-a4ca84ce46f8
-rw-r--r--GNUmakefile5
-rwxr-xr-xbuildtools/debian/mkdeb32
-rwxr-xr-xconverter/other/anytopnm2
-rw-r--r--converter/other/cameratopam/Makefile2
-rw-r--r--converter/other/cameratopam/camera.c245
-rw-r--r--converter/other/cameratopam/canon.c24
-rw-r--r--converter/other/cameratopam/foveon.c102
-rw-r--r--converter/other/cameratopam/identify.c49
-rw-r--r--converter/other/cameratopam/ljpeg.c16
-rw-r--r--converter/other/cameratopam/stdio_nofail.c120
-rw-r--r--converter/other/cameratopam/stdio_nofail.h29
-rw-r--r--converter/other/cameratopam/util.c34
-rw-r--r--converter/other/fiasco/input/read.c2
-rw-r--r--converter/other/fiasco/lib/image.c58
-rw-r--r--converter/other/fiasco/lib/image.h2
-rw-r--r--converter/other/fiasco/lib/macros.h2
-rw-r--r--converter/other/tifftopnm.c10
-rw-r--r--converter/other/winicontopam.c82
-rw-r--r--converter/other/xwdtopnm.c2
-rw-r--r--converter/pbm/pbmtonokia.c87
-rw-r--r--converter/pbm/xbmtopbm.c36
-rwxr-xr-xconverter/ppm/hpcdtoppm/hpcdtoppm6
-rwxr-xr-xconverter/ppm/hpcdtoppm/pcdovtoppm155
-rw-r--r--converter/ppm/picttoppm.c649
-rw-r--r--converter/ppm/ppmtompeg/opts.c62
-rw-r--r--converter/ppm/ppmtompeg/specifics.c26
-rw-r--r--converter/ppm/xim.h6
-rw-r--r--converter/ppm/ximtoppm.c50
-rw-r--r--converter/ppm/xpmtoppm.c4
-rw-r--r--doc/HISTORY61
-rw-r--r--editor/pamflip/pamflip.c2
-rwxr-xr-xeditor/pamstretch-gen6
-rw-r--r--editor/pnmcrop.c4
-rwxr-xr-xeditor/pnmmargin2
-rw-r--r--editor/pnmstitch.c6
-rw-r--r--generator/pamstereogram.c278
-rw-r--r--generator/pbmtext.c382
-rw-r--r--generator/pbmtextps.c2
-rw-r--r--generator/ppmforge.c2
-rw-r--r--generator/ppmmake.c2
-rw-r--r--generator/ppmrough.c2
-rw-r--r--lib/libpam.c51
-rw-r--r--lib/libpbmfont0.c92
-rw-r--r--lib/libpbmfont1.c2
-rw-r--r--lib/libpbmfont2.c515
-rw-r--r--lib/libpm.c4
-rw-r--r--lib/pbmfont.h93
-rw-r--r--lib/pbmfontdata2.c2
-rw-r--r--lib/pm_system.h7
-rw-r--r--lib/util/mallocvar.h60
-rw-r--r--other/pamfix.c2
-rw-r--r--test/Test-Order9
-rw-r--r--test/pamendian-roundtrip.ok4
-rwxr-xr-xtest/pamendian-roundtrip.test22
-rw-r--r--test/pamexec-roundtrip.ok10
-rwxr-xr-xtest/pamexec-roundtrip.test25
-rw-r--r--test/pamexec.ok10
-rwxr-xr-xtest/pamexec.test38
-rw-r--r--test/pamfix.ok68
-rwxr-xr-xtest/pamfix.test66
-rw-r--r--test/pamvalidate.ok13
-rwxr-xr-xtest/pamvalidate.test17
-rw-r--r--test/pbmtext-iso88591.ok4
-rwxr-xr-xtest/pbmtext-iso88591.test18
-rw-r--r--test/pbmtext-utf8.ok2
-rwxr-xr-xtest/pbmtext-utf8.test22
-rw-r--r--test/pj-roundtrip.ok4
-rwxr-xr-xtest/pj-roundtrip.test22
-rw-r--r--test/rawtoppm.ok23
-rwxr-xr-xtest/rawtoppm.test72
-rw-r--r--urt/scanargs.c1448
-rw-r--r--version.mk4
72 files changed, 3460 insertions, 1917 deletions
diff --git a/GNUmakefile b/GNUmakefile
index e727b00e..f07eed01 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -52,6 +52,11 @@
 # running in.  The -f option is necessary in order to have separate
 # source and object directories.
 
+# For the check targets, results go in a results directory, which you'll need
+# if a test fails to find out how it failed.  The default is
+# RESULTDIR_DEFAULT in config.mk.  Override it with
+# 'make resultdir=/tmp/myresultdir .
+
 ifeq ($(CURDIR)x,x)
 all package install:
 	@echo "YOU NEED AT LEAST VERSION 3.77 OF GNU MAKE TO BUILD NETPBM."
diff --git a/buildtools/debian/mkdeb b/buildtools/debian/mkdeb
index f0bd6145..b152a78d 100755
--- a/buildtools/debian/mkdeb
+++ b/buildtools/debian/mkdeb
@@ -112,12 +112,30 @@ sub netpbmVersion($) {
 
 sub control($$) {
     my ($release, $architecture) = @_;
+#-----------------------------------------------------------------------------
+#  The contents for the package control file, as a hash reference.  In the
+#  referenced hash, there is one key for each line of the control file.  The
+#  key and value in the hash are the key and value for the line of the control
+#  file.
+#-----------------------------------------------------------------------------
 
-# The Debian packaging system doesn't provide a way to express Netpbm's actual
-# prerequisites.  For example, Netpbm needs Version 6.2 or better of Libjpeg,
-# but there is no way to state that here.  Instead, we state Libjpeg 6.2
-# exactly.  This makes the Netpbm package less useful.
-
+    # Because developers of some of the dependent libraries frequently switch
+    # to distributing versions not backward compatible with what they
+    # previously distributed, and Debian always packages the currently
+    # distributed version, it is virtually impossible to produce a Netpbm
+    # package that works in multiple Debian versions.  This program is coded
+    # to create a package that works on the Debian system the Netpbm
+    # maintainer currently uses to build the Debian packages he distributes.
+    # If you are building for any other version of Debian, you'll have to
+    # modify this code.
+
+    # Note that the backward incompatibility is usually only at a binary
+    # level, not source level.  And sometimes the only incompatibility for
+    # Netpbm purposes is that the soname has changed so that Linux will refuse
+    # to run a Netpbm program built for Debian N on Debian N-1.
+
+    # The following is for Debian 9.
+    
     my %control;
 
     my $debianNativeNetpbm = 
@@ -138,7 +156,7 @@ sub control($$) {
     $control{'Depends'} =
         'libc6, ' .
         'libjpeg62, ' .
-        'libpng12-0 | libpng16-16, ' .
+        'libpng16-16, ' .
         'libtiff5, ' .
         'libx11-6, ' .
         'libxml2, ' .
@@ -148,6 +166,8 @@ sub control($$) {
         'perl-base, ' .
         'bash'
         ;
+    # Note: Instead of libjpeg62, Debian 10 has libjpeg62-turbo and Ubuntu 18
+    # has libjpeg-turbo8.
     $control{'Conflicts'} = $debianNativeNetpbm;
     $control{'Replaces'} = $debianNativeNetpbm;
     $control{'Provides'} = 
diff --git a/converter/other/anytopnm b/converter/other/anytopnm
index 5409bccd..94838556 100755
--- a/converter/other/anytopnm
+++ b/converter/other/anytopnm
@@ -538,7 +538,7 @@ else
 fi
 
 tempdir=$(mktemp -d "${TMPDIR:-/tmp}/anytopnm.XXXXXXXX") ||
-    ( echo "Could not create temporary file. Exiting." 1>&2; exit 1; ) 
+    { echo "Could not create temporary file. Exiting." 1>&2; exit 1; }
 trap 'rm -rf $tempdir' 0
 
 # Take out all spaces
diff --git a/converter/other/cameratopam/Makefile b/converter/other/cameratopam/Makefile
index d6207aea..bb4c4cde 100644
--- a/converter/other/cameratopam/Makefile
+++ b/converter/other/cameratopam/Makefile
@@ -20,7 +20,7 @@ include $(BUILDDIR)/config.mk
 all: cameratopam
 
 ADDL_OBJECTS = util.o identify.o camera.o foveon.o decode.o \
-	canon.o ljpeg.o dng.o
+	canon.o ljpeg.o dng.o stdio_nofail.o
 
 OBJECTS = cameratopam.o $(ADDL_OBJECTS)
 
diff --git a/converter/other/cameratopam/camera.c b/converter/other/cameratopam/camera.c
index 439c9413..4610462c 100644
--- a/converter/other/cameratopam/camera.c
+++ b/converter/other/cameratopam/camera.c
@@ -24,6 +24,7 @@
 #include "bayer.h"
 #include "ljpeg.h"
 #include "dng.h"
+#include "stdio_nofail.h"
 
 #include "camera.h"
 
@@ -94,8 +95,8 @@ adobe_dng_load_raw_lj(Image const image) {
     unsigned short *rp;
 
     while (1) {
-        save = ftell(ifp);
-        fseek (ifp, get4(ifp), SEEK_SET);
+        save = ftell_nofail(ifp);
+        fseek_nofail (ifp, get4(ifp), SEEK_SET);
         if (!ljpeg_start (ifp, &jh)) break;
         if (trow >= raw_height) break;
         if (jh.high > raw_height-trow)
@@ -113,7 +114,7 @@ adobe_dng_load_raw_lj(Image const image) {
                 adobeCopyPixel(image,
                                trow+jrow, tcol+jcol, &rp, use_secondary);
         }
-        fseek (ifp, save+4, SEEK_SET);
+        fseek_nofail (ifp, save+4, SEEK_SET);
         if ((tcol += twide) >= raw_width) {
             tcol = 0;
             trow += jh.high;
@@ -157,14 +158,14 @@ nikon_compressed_load_raw(Image const image) {
     init_decoder();
     make_decoder (nikon_tree, 0);
 
-    fseek (ifp, nikon_curve_offset, SEEK_SET);
+    fseek_nofail (ifp, nikon_curve_offset, SEEK_SET);
     read_shorts (ifp, vpred, 4);
     csize = get2(ifp);
     curve = calloc (csize, sizeof *curve);
     merror (curve, "nikon_compressed_load_raw()");
     read_shorts (ifp, curve, csize);
 
-    fseek (ifp, data_offset, SEEK_SET);
+    fseek_nofail (ifp, data_offset, SEEK_SET);
     getbits(ifp, -1);
 
     for (row=0; row < height; row++)
@@ -197,8 +198,8 @@ nikon_load_raw(Image const image) {
     if (model[0] == 'E') {
       row = irow * 2 % height + irow / (height/2);
       if (row == 1 && atoi(model+1) < 5000) {
-    fseek (ifp, 0, SEEK_END);
-    fseek (ifp, ftell(ifp)/2, SEEK_SET);
+    fseek_nofail (ifp, 0, SEEK_END);
+    fseek_nofail (ifp, ftell_nofail(ifp)/2, SEEK_SET);
     getbits(ifp, -1);
       }
     }
@@ -227,8 +228,8 @@ nikon_is_compressed()
     return 0;
   if (strcmp(model,"D100"))
     return 1;
-  fseek (ifp, data_offset, SEEK_SET);
-  fread (test, 1, 256, ifp);
+  fseek_nofail (ifp, data_offset, SEEK_SET);
+  fread_nofail (test, 1, 256, ifp);
   for (i=15; i < 256; i+=16)
     if (test[i]) return 1;
   return 0;
@@ -244,9 +245,9 @@ nikon_e990()
   const unsigned char often[] = { 0x00, 0x55, 0xaa, 0xff };
 
   memset (histo, 0, sizeof histo);
-  fseek (ifp, 2064*1540*3/4, SEEK_SET);
+  fseek_nofail (ifp, 2064*1540*3/4, SEEK_SET);
   for (i=0; i < 2000; i++)
-    histo[fgetc(ifp)]++;
+    histo[fgetc_nofail(ifp)]++;
   for (i=0; i < 4; i++)
     if (histo[often[i]] > 400)
       return 1;
@@ -262,9 +263,9 @@ nikon_e2100()
   unsigned char t[12];
   int i;
 
-  fseek (ifp, 0, SEEK_SET);
+  fseek_nofail (ifp, 0, SEEK_SET);
   for (i=0; i < 1024; i++) {
-    fread (t, 1, 12, ifp);
+    fread_nofail (t, 1, 12, ifp);
     if (((t[2] & t[4] & t[7] & t[9]) >> 4
     & t[1] & t[6] & t[8] & t[11] & 3) != 3)
       return 0;
@@ -281,8 +282,8 @@ pentax_optio33()
   int i, sum[] = { 0, 0 };
   unsigned char tail[952];
 
-  fseek (ifp, -sizeof tail, SEEK_END);
-  fread (tail, 1, sizeof tail, ifp);
+  fseek_nofail (ifp, -sizeof tail, SEEK_END);
+  fread_nofail (tail, 1, sizeof tail, ifp);
   for (i=0; i < sizeof tail; i++)
     sum[(i>>2) & 1] += tail[i];
   return sum[0] < sum[1]*4;
@@ -297,8 +298,8 @@ minolta_z2()
   int i;
   char tail[424];
 
-  fseek (ifp, -sizeof tail, SEEK_END);
-  fread (tail, 1, sizeof tail, ifp);
+  fseek_nofail (ifp, -sizeof tail, SEEK_END);
+  fread_nofail (tail, 1, sizeof tail, ifp);
   for (i=0; i < sizeof tail; i++)
     if (tail[i]) return 1;
   return 0;
@@ -313,10 +314,10 @@ nikon_e2100_load_raw(Image const image) {
 
   for (row=0; row <= height; row+=2) {
     if (row == height) {
-      fseek (ifp, ((width==1616) << 13) - (-ftell(ifp) & -2048), SEEK_SET);
+      fseek_nofail (ifp, ((width==1616) << 13) - (-ftell_nofail(ifp) & -2048), SEEK_SET);
       row = 1;
     }
-    fread (data, 1, width*3/2, ifp);
+    fread_nofail (data, 1, width*3/2, ifp);
     for (dp=data, pix=pixel; pix < pixel+width; dp+=12, pix+=8) {
       pix[0] = (dp[2] >> 4) + (dp[ 3] << 4);
       pix[1] = (dp[2] << 8) +  dp[ 1];
@@ -356,7 +357,7 @@ fuji_s2_load_raw(Image const image) {
   unsigned short pixel[2944];
   int row, col, r, c;
 
-  fseek (ifp, (2944*24+32)*2, SEEK_CUR);
+  fseek_nofail (ifp, (2944*24+32)*2, SEEK_CUR);
   for (row=0; row < 2144; row++) {
     read_shorts(ifp, pixel, 2944);
     for (col=0; col < 2880; col++) {
@@ -372,7 +373,7 @@ fuji_s3_load_raw(Image const image) {
   unsigned short pixel[4352];
   int row, col, r, c;
 
-  fseek (ifp, (4352*2+32)*2, SEEK_CUR);
+  fseek_nofail (ifp, (4352*2+32)*2, SEEK_CUR);
   for (row=0; row < 1440; row++) {
     read_shorts(ifp, pixel, 4352);
     for (col=0; col < 4288; col++) {
@@ -408,7 +409,7 @@ fuji_common_load_raw(Image        const image,
 void
 fuji_s5000_load_raw(Image const image) {
 
-  fseek (ifp, (1472*4+24)*2, SEEK_CUR);
+  fseek_nofail (ifp, (1472*4+24)*2, SEEK_CUR);
   fuji_common_load_raw(image, 1472, 1423, 2152);
 }
 
@@ -449,7 +450,7 @@ rollei_load_raw(Image const image) {
   unsigned iten=0, isix, i, buffer=0, row, col, todo[16];
 
   isix = raw_width * raw_height * 5 / 8;
-  while (fread (pixel, 1, 10, ifp) == 10) {
+  while (fread_or_eof_nofail (pixel, 1, 10, ifp) == 10) {
     for (i=0; i < 10; i+=2) {
       todo[i]   = iten++;
       todo[i+1] = pixel[i] << 8 | pixel[i+1];
@@ -474,11 +475,11 @@ phase_one_load_raw(Image const image) {
   int row, col, a, b;
   unsigned short *pixel, akey, bkey;
 
-  fseek (ifp, 8, SEEK_CUR);
-  fseek (ifp, get4(ifp) + 296, SEEK_CUR);
+  fseek_nofail (ifp, 8, SEEK_CUR);
+  fseek_nofail (ifp, get4(ifp) + 296, SEEK_CUR);
   akey = get2(ifp);
   bkey = get2(ifp);
-  fseek (ifp, data_offset + 12 + top_margin*raw_width*2, SEEK_SET);
+  fseek_nofail (ifp, data_offset + 12 + top_margin*raw_width*2, SEEK_SET);
   pixel = calloc (raw_width, sizeof *pixel);
   merror (pixel, "phase_one_load_raw()");
   for (row=0; row < height; row++) {
@@ -501,7 +502,7 @@ ixpress_load_raw(Image const image) {
   int row, col;
 
   order = 0x4949;
-  fseek (ifp, 304 + 6*2*4090, SEEK_SET);
+  fseek_nofail (ifp, 304 + 6*2*4090, SEEK_SET);
   for (row=height; --row >= 0; ) {
     read_shorts(ifp, pixel, 4090);
     for (col=0; col < width; col++)
@@ -567,7 +568,7 @@ olympus_e300_load_raw(Image const image) {
   merror (data, "olympus_e300_load_raw()");
   pixel = (unsigned short *) (data + dwide);
   for (row=0; row < height; row++) {
-    fread (data, 1, dwide, ifp);
+    fread_nofail (data, 1, dwide, ifp);
     for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=3, pix+=2) {
       if (((dp-data) & 15) == 15) dp++;
       pix[0] = dp[1] << 8 | dp[0];
@@ -586,7 +587,7 @@ olympus_cseries_load_raw(Image const image) {
   for (irow=0; irow < height; irow++) {
     row = irow * 2 % height + irow / (height/2);
     if (row < 2) {
-      fseek (ifp, data_offset - row*(-width*height*3/4 & -2048), SEEK_SET);
+      fseek_nofail (ifp, data_offset - row*(-width*height*3/4 & -2048), SEEK_SET);
       getbits(ifp, -1);
     }
     for (col=0; col < width; col++)
@@ -602,7 +603,7 @@ eight_bit_load_raw(Image const image) {
   pixel = calloc (raw_width, sizeof *pixel);
   merror (pixel, "eight_bit_load_raw()");
   for (row=0; row < height; row++) {
-    fread (pixel, 1, raw_width, ifp);
+    fread_nofail (pixel, 1, raw_width, ifp);
     for (col=0; col < width; col++)
       BAYER(row,col) = pixel[col];
   }
@@ -617,7 +618,7 @@ casio_qv5700_load_raw(Image const image) {
   int row, col;
 
   for (row=0; row < height; row++) {
-    fread (data, 1, 3232, ifp);
+    fread_nofail (data, 1, 3232, ifp);
     for (dp=data, pix=pixel; dp < data+3220; dp+=5, pix+=4) {
       pix[0] = (dp[0] << 2) + (dp[1] >> 6);
       pix[1] = (dp[1] << 4) + (dp[2] >> 4);
@@ -783,7 +784,7 @@ fill_input_buffer (j_decompress_ptr cinfo)
   static char jpeg_buffer[4096];
   size_t nbytes;
 
-  nbytes = fread (jpeg_buffer, 1, 4096, ifp);
+  nbytes = fread_or_eof_nofail (jpeg_buffer, 1, 4096, ifp);
   swab (jpeg_buffer, jpeg_buffer, nbytes);
   cinfo->src->next_input_byte = jpeg_buffer;
   cinfo->src->bytes_in_buffer = nbytes;
@@ -840,7 +841,7 @@ kodak_dc120_load_raw(Image const image)
   int row, shift, col;
 
   for (row=0; row < height; row++) {
-    fread (pixel, 848, 1, ifp);
+    fread_nofail (pixel, 848, 1, ifp);
     shift = row * mul[row & 3] + add[row & 3];
     for (col=0; col < width; col++)
       BAYER(row,col) = (unsigned short) pixel[(col + shift) % 848];
@@ -878,7 +879,7 @@ kodak_easy_load_raw(Image const image)
   pixel = calloc (raw_width, sizeof *pixel);
   merror (pixel, "kodak_easy_load_raw()");
   for (row=0; row < height; row++) {
-    fread (pixel, 1, raw_width, ifp);
+    fread_nofail (pixel, 1, raw_width, ifp);
     for (col=0; col < raw_width; col++) {
       icol = col - left_margin;
       if (icol < width)
@@ -912,21 +913,21 @@ kodak_compressed_load_raw(Image const image)
       if ((col & 255) == 0) {       /* Get the bit-lengths of the */
     len = width - col;      /* next 256 pixel values      */
     if (len > 256) len = 256;
-    save = ftell(ifp);
+    save = ftell_nofail(ifp);
     for (israw=i=0; i < len; i+=2) {
-      c = fgetc(ifp);
+      c = fgetc_nofail(ifp);
       if ((blen[i+0] = c & 15) > 12 ||
           (blen[i+1] = c >> 4) > 12 )
         israw = 1;
     }
     bitbuf = bits = pred[0] = pred[1] = 0;
     if (len % 8 == 4) {
-      bitbuf  = fgetc(ifp) << 8;
-      bitbuf += fgetc(ifp);
+      bitbuf  = fgetc_nofail(ifp) << 8;
+      bitbuf += fgetc_nofail(ifp);
       bits = 16;
     }
     if (israw)
-      fseek (ifp, save, SEEK_SET);
+      fseek_nofail (ifp, save, SEEK_SET);
       }
       if (israw) {          /* If the data is not compressed */
     switch (col & 7) {
@@ -944,7 +945,7 @@ kodak_compressed_load_raw(Image const image)
     len = blen[col & 255];      /* Number of bits for this pixel */
     if (bits < len) {       /* Got enough bits in the buffer? */
       for (i=0; i < 32; i+=8)
-        bitbuf += (INT64) fgetc(ifp) << (bits+(i^8));
+        bitbuf += (INT64) fgetc_nofail(ifp) << (bits+(i^8));
       bits += 32;
     }
     diff = bitbuf & (0xffff >> (16-len));  /* Pull bits from buffer */
@@ -976,14 +977,14 @@ kodak_yuv_load_raw(Image const image)
     len = (width - col + 1) * 3 & -4;
     if (len > 384) len = 384;
     for (i=0; i < len; ) {
-      c = fgetc(ifp);
+      c = fgetc_nofail(ifp);
       blen[i++] = c & 15;
       blen[i++] = c >> 4;
     }
     li = bitbuf = bits = y[1] = y[3] = cb = cr = 0;
     if (len % 8 == 4) {
-      bitbuf  = fgetc(ifp) << 8;
-      bitbuf += fgetc(ifp);
+      bitbuf  = fgetc_nofail(ifp) << 8;
+      bitbuf += fgetc_nofail(ifp);
       bits = 16;
     }
       }
@@ -991,7 +992,7 @@ kodak_yuv_load_raw(Image const image)
     len = blen[li++];
     if (bits < len) {
       for (i=0; i < 32; i+=8)
-        bitbuf += (INT64) fgetc(ifp) << (bits+(i^8));
+        bitbuf += (INT64) fgetc_nofail(ifp) << (bits+(i^8));
       bits += 32;
     }
     diff = bitbuf & (0xffff >> (16-len));
@@ -1062,20 +1063,20 @@ sony_load_raw(Image const image)
   struct pixel * pixelrow;
   unsigned i, key, row, col;
 
-  fseek (ifp, 200896, SEEK_SET);
-  fseek (ifp, (unsigned) fgetc(ifp)*4 - 1, SEEK_CUR);
+  fseek_nofail (ifp, 200896, SEEK_SET);
+  fseek_nofail (ifp, (unsigned) fgetc_nofail(ifp)*4 - 1, SEEK_CUR);
   order = 0x4d4d;
   key = get4(ifp);
-  fseek (ifp, 164600, SEEK_SET);
-  fread (head, 1, 40, ifp);
+  fseek_nofail (ifp, 164600, SEEK_SET);
+  fread_nofail (head, 1, 40, ifp);
   sony_decrypt ((void *) head, 10, 1, key);
   for (i=26; i-- > 22; )
     key = key << 8 | head[i];
-  fseek (ifp, data_offset, SEEK_SET);
+  fseek_nofail (ifp, data_offset, SEEK_SET);
   MALLOCARRAY(pixelrow, raw_width);
   merror (pixelrow, "sony_load_raw()");
   for (row=0; row < height; row++) {
-    fread (pixelrow, 2, raw_width, ifp);
+    fread_nofail (pixelrow, 2, raw_width, ifp);
     sony_decrypt ((void *) pixelrow, raw_width/2, !row, key);
     for (col=9; col < left_margin; col++)
       black += pixelrow[col].bytes[0] * 256 + pixelrow[col].bytes[1];
@@ -1095,14 +1096,14 @@ parse_minolta(FILE * const ifp)
 {
   int save, tag, len, offset, high=0, wide=0;
 
-  fseek (ifp, 4, SEEK_SET);
+  fseek_nofail (ifp, 4, SEEK_SET);
   offset = get4(ifp) + 8;
-  while ((save=ftell(ifp)) < offset) {
+  while ((save=ftell_nofail(ifp)) < offset) {
     tag = get4(ifp);
     len = get4(ifp);
     switch (tag) {
       case 0x505244:                /* PRD */
-    fseek (ifp, 8, SEEK_CUR);
+    fseek_nofail (ifp, 8, SEEK_CUR);
     high = get2(ifp);
     wide = get2(ifp);
     break;
@@ -1114,9 +1115,9 @@ parse_minolta(FILE * const ifp)
     camera_blue = get2(ifp) / camera_blue;
     break;
       case 0x545457:                /* TTW */
-    parse_tiff(ifp, ftell(ifp));
+    parse_tiff(ifp, ftell_nofail(ifp));
     }
-    fseek (ifp, save+len+8, SEEK_SET);
+    fseek_nofail (ifp, save+len+8, SEEK_SET);
   }
   raw_height = high;
   raw_width  = wide;
@@ -1168,24 +1169,24 @@ parse_ciff(FILE * const ifp,
       strcmp(model,"Canon PowerShot S70") &&
       strcmp(model,"Canon PowerShot Pro1"))
     key[0] = key[1] = 0;
-  fseek (ifp, offset+length-4, SEEK_SET);
+  fseek_nofail (ifp, offset+length-4, SEEK_SET);
   tboff = get4(ifp) + offset;
-  fseek (ifp, tboff, SEEK_SET);
+  fseek_nofail (ifp, tboff, SEEK_SET);
   nrecs = get2(ifp);
   for (i = 0; i < nrecs; i++) {
     type = get2(ifp);
     len  = get4(ifp);
     roff = get4(ifp);
     aoff = offset + roff;
-    save = ftell(ifp);
+    save = ftell_nofail(ifp);
     if (type == 0x080a) {       /* Get the camera make and model */
-      fseek (ifp, aoff, SEEK_SET);
-      fread (make, 64, 1, ifp);
-      fseek (ifp, aoff+strlen(make)+1, SEEK_SET);
-      fread (model, 64, 1, ifp);
+      fseek_nofail (ifp, aoff, SEEK_SET);
+      fread_nofail (make, 64, 1, ifp);
+      fseek_nofail (ifp, aoff+strlen(make)+1, SEEK_SET);
+      fread_nofail (model, 64, 1, ifp);
     }
     if (type == 0x102a) {       /* Find the White Balance index */
-      fseek (ifp, aoff+14, SEEK_SET);   /* 0=auto, 1=daylight, 2=cloudy ... */
+      fseek_nofail (ifp, aoff+14, SEEK_SET);   /* 0=auto, 1=daylight, 2=cloudy ... */
       wbi = get2(ifp);
       if (((!strcmp(model,"Canon EOS DIGITAL REBEL") ||
         !strcmp(model,"Canon EOS 300D DIGITAL"))) && wbi == 6)
@@ -1194,19 +1195,19 @@ parse_ciff(FILE * const ifp,
     if (type == 0x102c) {       /* Get white balance (G2) */
       if (!strcmp(model,"Canon PowerShot G1") ||
       !strcmp(model,"Canon PowerShot Pro90 IS")) {
-    fseek (ifp, aoff+120, SEEK_SET);
+    fseek_nofail (ifp, aoff+120, SEEK_SET);
     white[0][1] = get2(ifp);
     white[0][0] = get2(ifp);
     white[1][0] = get2(ifp);
     white[1][1] = get2(ifp);
       } else {
-    fseek (ifp, aoff+100, SEEK_SET);
+    fseek_nofail (ifp, aoff+100, SEEK_SET);
     goto common;
       }
     }
     if (type == 0x0032) {       /* Get white balance (D30 & G3) */
       if (!strcmp(model,"Canon EOS D30")) {
-    fseek (ifp, aoff+72, SEEK_SET);
+    fseek_nofail (ifp, aoff+72, SEEK_SET);
 common:
     camera_red   = get2(ifp) ^ key[0];
     camera_red   =(get2(ifp) ^ key[1]) / camera_red;
@@ -1214,13 +1215,13 @@ common:
     camera_blue /= get2(ifp) ^ key[1];
       } else if (!strcmp(model,"Canon PowerShot G6") ||
          !strcmp(model,"Canon PowerShot S70")) {
-    fseek (ifp, aoff+96 + remap_s70[wbi]*8, SEEK_SET);
+    fseek_nofail (ifp, aoff+96 + remap_s70[wbi]*8, SEEK_SET);
     goto common;
       } else if (!strcmp(model,"Canon PowerShot Pro1")) {
-    fseek (ifp, aoff+96 + wbi*8, SEEK_SET);
+    fseek_nofail (ifp, aoff+96 + wbi*8, SEEK_SET);
     goto common;
       } else {
-    fseek (ifp, aoff+80 + (wbi < 6 ? remap[wbi]*8 : 0), SEEK_SET);
+    fseek_nofail (ifp, aoff+80 + (wbi < 6 ? remap[wbi]*8 : 0), SEEK_SET);
     if (!camera_red)
       goto common;
       }
@@ -1228,38 +1229,38 @@ common:
     if (type == 0x10a9) {       /* Get white balance (D60) */
       if (!strcmp(model,"Canon EOS 10D"))
     wbi = remap_10d[wbi];
-      fseek (ifp, aoff+2 + wbi*8, SEEK_SET);
+      fseek_nofail (ifp, aoff+2 + wbi*8, SEEK_SET);
       camera_red  = get2(ifp);
       camera_red /= get2(ifp);
       camera_blue = get2(ifp);
       camera_blue = get2(ifp) / camera_blue;
     }
     if (type == 0x1030 && (wbi == 6 || wbi == 15)) {
-      fseek (ifp, aoff, SEEK_SET);  /* Get white sample */
+      fseek_nofail (ifp, aoff, SEEK_SET);  /* Get white sample */
       ciff_block_1030();
     }
     if (type == 0x1031) {       /* Get the raw width and height */
-      fseek (ifp, aoff+2, SEEK_SET);
+      fseek_nofail (ifp, aoff+2, SEEK_SET);
       raw_width  = get2(ifp);
       raw_height = get2(ifp);
     }
     if (type == 0x180e) {       /* Get the timestamp */
-      fseek (ifp, aoff, SEEK_SET);
+      fseek_nofail (ifp, aoff, SEEK_SET);
       timestamp = get4(ifp);
     }
     if (type == 0x580e)
       timestamp = len;
     if (type == 0x1810) {       /* Get the rotation */
-      fseek (ifp, aoff+12, SEEK_SET);
+      fseek_nofail (ifp, aoff+12, SEEK_SET);
       flip = get4(ifp);
     }
     if (type == 0x1835) {       /* Get the decoder table */
-      fseek (ifp, aoff, SEEK_SET);
+      fseek_nofail (ifp, aoff, SEEK_SET);
       crw_init_tables (get4(ifp));
     }
     if (type >> 8 == 0x28 || type >> 8 == 0x30) /* Get sub-tables */
       parse_ciff(ifp, aoff, len);
-    fseek (ifp, save, SEEK_SET);
+    fseek_nofail (ifp, save, SEEK_SET);
   }
   if (wbi == 0 && !strcmp(model,"Canon EOS D30"))
     camera_red = -1;            /* Use my auto WB for this photo */
@@ -1273,9 +1274,9 @@ parse_rollei(FILE * const ifp)
   struct tm t;
   time_t ts;
 
-  fseek (ifp, 0, SEEK_SET);
+  fseek_nofail (ifp, 0, SEEK_SET);
   do {
-    fgets (line, 128, ifp);
+    fgets_nofail (line, 128, ifp);
     if ((val = strchr(line,'=')))
       *val++ = 0;
     else
@@ -1314,13 +1315,13 @@ parse_mos(FILE * const ifp,
     char data[40];
     int skip, from, i, neut[4];
 
-    fseek (ifp, offset, SEEK_SET);
+    fseek_nofail (ifp, offset, SEEK_SET);
     while (1) {
-        fread (data, 1, 8, ifp);
+        fread_nofail (data, 1, 8, ifp);
         if (strcmp(data,"PKTS")) break;
-        fread (data, 1, 40, ifp);
+        fread_nofail (data, 1, 40, ifp);
         skip = get4(ifp);
-        from = ftell(ifp);
+        from = ftell_nofail(ifp);
         if (!strcmp(data,"NeutObj_neutrals")) {
             for (i=0; i < 4; i++)
                 fscanf (ifp, "%d", neut+i);
@@ -1328,7 +1329,7 @@ parse_mos(FILE * const ifp,
             camera_blue = (float) neut[2] / neut[3];
         }
         parse_mos(ifp, from);
-        fseek (ifp, skip+from, SEEK_SET);
+        fseek_nofail (ifp, skip+from, SEEK_SET);
     }
 }
 
@@ -1369,43 +1370,43 @@ parse_makernote(FILE * const ifp)
    its own byte-order!), or it might just be a table.
  */
   sorder = order;
-  fread (buf, 1, 10, ifp);
+  fread_nofail (buf, 1, 10, ifp);
   if (!strncmp (buf,"KC" ,2) ||     /* these aren't TIFF format */
       !strncmp (buf,"MLY",3)) return;
   if (!strcmp (buf,"Nikon")) {
-    base = ftell(ifp);
+    base = ftell_nofail(ifp);
     order = get2(ifp);
     if (get2(ifp) != 42) goto quit;
     offset = get4(ifp);
-    fseek (ifp, offset-8, SEEK_CUR);
+    fseek_nofail (ifp, offset-8, SEEK_CUR);
   } else if (!strncmp (buf,"FUJIFILM",8) ||
          !strcmp  (buf,"Panasonic")) {
     order = 0x4949;
-    fseek (ifp,  2, SEEK_CUR);
+    fseek_nofail (ifp,  2, SEEK_CUR);
   } else if (!strcmp (buf,"OLYMP") ||
          !strcmp (buf,"LEICA") ||
          !strcmp (buf,"EPSON"))
-    fseek (ifp, -2, SEEK_CUR);
+    fseek_nofail (ifp, -2, SEEK_CUR);
   else if (!strcmp (buf,"AOC") ||
        !strcmp (buf,"QVC"))
-    fseek (ifp, -4, SEEK_CUR);
-  else fseek (ifp, -10, SEEK_CUR);
+    fseek_nofail (ifp, -4, SEEK_CUR);
+  else fseek_nofail (ifp, -10, SEEK_CUR);
 
   entries = get2(ifp);
   while (entries--) {
     tag  = get2(ifp);
     type = get2(ifp);
     len  = get4(ifp);
-    save = ftell(ifp);
+    save = ftell_nofail(ifp);
     if (len * size[type < 13 ? type:0] > 4)
-      fseek (ifp, get4(ifp)+base, SEEK_SET);
+      fseek_nofail (ifp, get4(ifp)+base, SEEK_SET);
 
     if (tag == 0xc && len == 4) {
       camera_red  = getrat();
       camera_blue = getrat();
     }
     if (tag == 0x14 && len == 2560 && type == 7) {
-      fseek (ifp, 1248, SEEK_CUR);
+      fseek_nofail (ifp, 1248, SEEK_CUR);
       goto get2_256;
     }
     if (strstr(make,"PENTAX")) {
@@ -1413,19 +1414,19 @@ parse_makernote(FILE * const ifp)
       if (tag == 0x1c) tag = 0x1017;
     }
     if (tag == 0x8c)
-      nikon_curve_offset = ftell(ifp) + 2112;
+      nikon_curve_offset = ftell_nofail(ifp) + 2112;
     if (tag == 0x96)
-      nikon_curve_offset = ftell(ifp) + 2;
+      nikon_curve_offset = ftell_nofail(ifp) + 2;
     if (tag == 0x97) {
       if (!strcmp(model,"NIKON D100 ")) {
-    fseek (ifp, 72, SEEK_CUR);
+    fseek_nofail (ifp, 72, SEEK_CUR);
     camera_red  = get2(ifp) / 256.0;
     camera_blue = get2(ifp) / 256.0;
       } else if (!strcmp(model,"NIKON D2H")) {
-    fseek (ifp, 10, SEEK_CUR);
+    fseek_nofail (ifp, 10, SEEK_CUR);
     goto get2_rggb;
       } else if (!strcmp(model,"NIKON D70")) {
-    fseek (ifp, 20, SEEK_CUR);
+    fseek_nofail (ifp, 20, SEEK_CUR);
     camera_red  = get2(ifp);
     camera_red /= get2(ifp);
     camera_blue = get2(ifp);
@@ -1449,12 +1450,12 @@ parse_makernote(FILE * const ifp)
       black = (get4(ifp)+get4(ifp)+get4(ifp)+get4(ifp))/4;
     }
     if (tag == 0xe80 && len == 256 && type == 7) {
-      fseek (ifp, 48, SEEK_CUR);
+      fseek_nofail (ifp, 48, SEEK_CUR);
       camera_red  = get2(ifp) * 508 * 1.078 / 0x10000;
       camera_blue = get2(ifp) * 382 * 1.173 / 0x10000;
     }
     if (tag == 0xf00 && len == 614 && type == 7) {
-      fseek (ifp, 188, SEEK_CUR);
+      fseek_nofail (ifp, 188, SEEK_CUR);
       goto get2_256;
     }
     if (tag == 0x1017)
@@ -1468,14 +1469,14 @@ get2_256:
       camera_blue = get2(ifp) / 256.0;
     }
     if (tag == 0x4001) {
-      fseek (ifp, strstr(model,"EOS-1D") ? 68:50, SEEK_CUR);
+      fseek_nofail (ifp, strstr(model,"EOS-1D") ? 68:50, SEEK_CUR);
 get2_rggb:
       camera_red  = get2(ifp);
       camera_red /= get2(ifp);
       camera_blue = get2(ifp);
       camera_blue = get2(ifp) / camera_blue;
     }
-    fseek (ifp, save+4, SEEK_SET);
+    fseek_nofail (ifp, save+4, SEEK_SET);
   }
 quit:
   order = sorder;
@@ -1514,8 +1515,8 @@ parse_exif(FILE * const ifp, int base)
     /* type = */ get2(ifp);
     len  = get4(ifp);
     val  = get4(ifp);
-    save = ftell(ifp);
-    fseek (ifp, base+val, SEEK_SET);
+    save = ftell_nofail(ifp);
+    fseek_nofail (ifp, base+val, SEEK_SET);
     if (tag == 0x9003 || tag == 0x9004)
       get_timestamp(ifp);
     if (tag == 0x927c) {
@@ -1524,7 +1525,7 @@ parse_exif(FILE * const ifp, int base)
       else
     parse_makernote(ifp);
     }
-    fseek (ifp, save, SEEK_SET);
+    fseek_nofail (ifp, save, SEEK_SET);
   }
 }
 
@@ -1550,10 +1551,10 @@ parse_tiff_ifd(FILE * const ifp, int base, int level)
     tag  = get2(ifp);
     type = get2(ifp);
     len  = get4(ifp);
-    save = ftell(ifp);
+    save = ftell_nofail(ifp);
     if (tag > 50700 && tag < 50800) done = 1;
     if (len * size[type < 13 ? type:0] > 4)
-      fseek (ifp, get4(ifp)+base, SEEK_SET);
+      fseek_nofail (ifp, get4(ifp)+base, SEEK_SET);
     switch (tag) {
       case 0x11:
     camera_red  = get4(ifp) / 256.0;
@@ -1580,10 +1581,10 @@ parse_tiff_ifd(FILE * const ifp, int base, int level)
     kodak_data_compression = get2(ifp);
     break;
       case 0x10f:           /* Make */
-    fgets (make, 64, ifp);
+    fgets_nofail (make, 64, ifp);
     break;
       case 0x110:           /* Model */
-    fgets (model, 64, ifp);
+    fgets_nofail (model, 64, ifp);
     break;
       case 0x111:           /* StripOffset */
     data_offset = get4(ifp);
@@ -1595,7 +1596,7 @@ parse_tiff_ifd(FILE * const ifp, int base, int level)
     tiff_samples = get2(ifp);
     break;
       case 0x131:           /* Software tag */
-    fgets (software, 64, ifp);
+    fgets_nofail (software, 64, ifp);
     if (!strncmp(software,"Adobe",5))
       make[0] = 0;
     break;
@@ -1604,7 +1605,7 @@ parse_tiff_ifd(FILE * const ifp, int base, int level)
     break;
       case 0x144:           /* TileOffsets */
     if (level) {
-      data_offset = ftell(ifp);
+      data_offset = ftell_nofail(ifp);
     } else {
       strcpy (make, "Leaf");
       data_offset = get4(ifp);
@@ -1614,18 +1615,18 @@ parse_tiff_ifd(FILE * const ifp, int base, int level)
     if (len > 2 && !is_dng && !strcmp(make,"Kodak"))
         len = 2;
     while (len--) {
-      i = ftell(ifp);
-      fseek (ifp, get4(ifp)+base, SEEK_SET);
+      i = ftell_nofail(ifp);
+      fseek_nofail (ifp, get4(ifp)+base, SEEK_SET);
       if (parse_tiff_ifd(ifp, base, level+1)) break;
-      fseek (ifp, i+4, SEEK_SET);
+      fseek_nofail (ifp, i+4, SEEK_SET);
     }
     break;
       case 33405:           /* Model2 */
-    fgets (model2, 64, ifp);
+    fgets_nofail (model2, 64, ifp);
     break;
       case 33422:           /* CFAPattern */
     if ((plen=len) > 16) plen = 16;
-    fread (cfa_pat, 1, plen, ifp);
+    fread_nofail (cfa_pat, 1, plen, ifp);
     for (colors=cfa=i=0; i < plen; i++) {
       colors += !(cfa & (1 << cfa_pat[i]));
       cfa |= 1 << cfa_pat[i];
@@ -1634,7 +1635,7 @@ parse_tiff_ifd(FILE * const ifp, int base, int level)
     if (cfa == 072) memcpy (cfa_pc,"\005\003\004\001",4);   /* GMCY */
     goto guess_cfa_pc;
       case 34665:           /* EXIF tag */
-    fseek (ifp, get4(ifp)+base, SEEK_SET);
+    fseek_nofail (ifp, get4(ifp)+base, SEEK_SET);
     parse_exif(ifp, base);
     break;
       case 50706:           /* DNGVersion */
@@ -1644,7 +1645,7 @@ parse_tiff_ifd(FILE * const ifp, int base, int level)
       case 50710:           /* CFAPlaneColor */
     if (len > 4) len = 4;
     colors = len;
-    fread (cfa_pc, 1, colors, ifp);
+    fread_nofail (cfa_pc, 1, colors, ifp);
 guess_cfa_pc:
     FORC4 tab[cfa_pc[c]] = c;
     for (i=16; i--; )
@@ -1701,7 +1702,7 @@ guess_cfa_pc:
     xyz[1] = getrat();
     xyz[2] = 1 - xyz[0] - xyz[1];
     }
-    fseek (ifp, save+4, SEEK_SET);
+    fseek_nofail (ifp, save+4, SEEK_SET);
   }
   for (i=0; i < colors; i++)
     FORC4 cc[i][c] *= ab[i];
@@ -1729,16 +1730,16 @@ parse_tiff(FILE * const ifp, int base)
 {
   int doff;
 
-  fseek (ifp, base, SEEK_SET);
+  fseek_nofail (ifp, base, SEEK_SET);
   order = get2(ifp);
   if (order != 0x4949 && order != 0x4d4d) return;
   get2(ifp);
   while ((doff = get4(ifp))) {
-    fseek (ifp, doff+base, SEEK_SET);
+    fseek_nofail (ifp, doff+base, SEEK_SET);
     if (parse_tiff_ifd(ifp, base, 0)) break;
   }
   if (!is_dng && !strncmp(make,"Kodak",5)) {
-    fseek (ifp, 12+base, SEEK_SET);
+    fseek_nofail (ifp, 12+base, SEEK_SET);
     parse_tiff_ifd(ifp, base, 2);
   }
 }
diff --git a/converter/other/cameratopam/canon.c b/converter/other/cameratopam/canon.c
index 96a6210b..cbf5ece0 100644
--- a/converter/other/cameratopam/canon.c
+++ b/converter/other/cameratopam/canon.c
@@ -6,9 +6,10 @@
 #include "decode.h"
 #include "bayer.h"
 #include "canon.h"
+#include "stdio_nofail.h"
 
 
-void 
+void
 canon_600_load_raw(Image const image) {
     unsigned char  data[1120], *dp;
     unsigned short pixel[896], *pix;
@@ -16,7 +17,7 @@ canon_600_load_raw(Image const image) {
 
     for (irow=orow=0; irow < height; irow++)
     {
-        fread (data, 1120, 1, ifp);
+        fread_nofail (data, 1120, 1, ifp);
         for (dp=data, pix=pixel; dp < data+1120; dp+=10, pix+=8)
         {
             pix[0] = (dp[0] << 2) + (dp[1] >> 6    );
@@ -48,7 +49,7 @@ canon_a5_load_raw(Image const image) {
     int row, col;
 
     for (row=0; row < height; row++) {
-        fread (data, raw_width * 10 / 8, 1, ifp);
+        fread_nofail (data, raw_width * 10 / 8, 1, ifp);
         for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=10, pix+=8)
         {
             pix[0] = (dp[1] << 2) + (dp[0] >> 6);
@@ -84,8 +85,8 @@ canon_has_lowbits()
     unsigned char test[0x4000];
     int ret=1, i;
 
-    fseek (ifp, 0, SEEK_SET);
-    fread (test, 1, sizeof test, ifp);
+    fseek_nofail (ifp, 0, SEEK_SET);
+    fread_nofail (test, 1, sizeof test, ifp);
     for (i=540; i < sizeof test - 1; i++)
         if (test[i] == 0xff) {
             if (test[i+1]) return 1;
@@ -96,7 +97,7 @@ canon_has_lowbits()
 
 
 
-void 
+void
 canon_compressed_load_raw(Image const image) {
     unsigned short *pixel, *prow;
     int lowbits, i, row, r, col, save, val;
@@ -110,7 +111,7 @@ canon_compressed_load_raw(Image const image) {
         pm_error("Unable to allocate space for %u pixels", raw_width*8);
     lowbits = canon_has_lowbits();
     if (!lowbits) maximum = 0x3ff;
-    fseek (ifp, 540 + lowbits*raw_height*raw_width/4, SEEK_SET);
+    fseek_nofail (ifp, 540 + lowbits*raw_height*raw_width/4, SEEK_SET);
     zero_after_ff = 1;
     getbits(ifp, -1);
     for (row = 0; row < raw_height; row += 8) {
@@ -141,17 +142,17 @@ canon_compressed_load_raw(Image const image) {
             }
         }
         if (lowbits) {
-            save = ftell(ifp);
-            fseek (ifp, 26 + row*raw_width/4, SEEK_SET);
+            save = ftell_nofail(ifp);
+            fseek_nofail (ifp, 26 + row*raw_width/4, SEEK_SET);
             for (prow=pixel, i=0; i < raw_width*2; i++) {
-                c = fgetc(ifp);
+                c = fgetc_nofail(ifp);
                 for (r=0; r < 8; r+=2, prow++) {
                     val = (*prow << 2) + ((c >> r) & 3);
                     if (raw_width == 2672 && val < 512) val += 2;
                     *prow = val;
                 }
             }
-            fseek (ifp, save, SEEK_SET);
+            fseek_nofail (ifp, save, SEEK_SET);
         }
         for (r=0; r < 8; r++) {
             irow = row - top_margin + r;
@@ -169,4 +170,3 @@ canon_compressed_load_raw(Image const image) {
     if (raw_width > width)
         black /= (raw_width - width) * height;
 }
-
diff --git a/converter/other/cameratopam/foveon.c b/converter/other/cameratopam/foveon.c
index 992f3883..5a26777b 100644
--- a/converter/other/cameratopam/foveon.c
+++ b/converter/other/cameratopam/foveon.c
@@ -2,7 +2,6 @@
 
 #define _XOPEN_SOURCE 500  /* get M_PI in math.h */
 
-#include <stdio.h>
 #include <assert.h>
 #include <string.h>
 #include <float.h>
@@ -13,6 +12,7 @@
 #include "global_variables.h"
 #include "decode.h"
 #include "foveon.h"
+#include "stdio_nofail.h"
 
 #if HAVE_INT64
    typedef int64_t INT64;
@@ -32,13 +32,13 @@
 
 
 
-static char *  
-foveon_gets(int    const offset, 
-            char * const str, 
+static char *
+foveon_gets(int    const offset,
+            char * const str,
             int    const len) {
 
     unsigned int i;
-    fseek (ifp, offset, SEEK_SET);
+    fseek_nofail (ifp, offset, SEEK_SET);
     for (i=0; i < len-1; ++i) {
         /* It certains seems wrong that we're reading a 16 bit integer
            and assigning it to char, but that's what Dcraw does.
@@ -55,7 +55,7 @@ foveon_gets(int    const offset,
 
 
 
-void 
+void
 parse_foveon(FILE * const ifp) {
     long fliplong;
     long pos;
@@ -63,14 +63,14 @@ parse_foveon(FILE * const ifp) {
     long junk;
     long entries;
 
-    fseek (ifp, 36, SEEK_SET);
+    fseek_nofail (ifp, 36, SEEK_SET);
     pm_readlittlelong(ifp, &fliplong);
     flip = fliplong;
-    fseek (ifp, -4, SEEK_END);
+    fseek_nofail (ifp, -4, SEEK_END);
     pm_readlittlelong(ifp, &pos);
-    fseek (ifp, pos, SEEK_SET);
+    fseek_nofail (ifp, pos, SEEK_SET);
     pm_readlittlelong(ifp, &magic);
-    if (magic != 0x64434553) 
+    if (magic != 0x64434553)
         return; /* SECd */
     pm_readlittlelong(ifp, &junk);
     pm_readlittlelong(ifp, &entries);
@@ -85,17 +85,17 @@ parse_foveon(FILE * const ifp) {
         pm_readlittlelong(ifp, &off);
         pm_readlittlelong(ifp, &len);
         pm_readlittlelong(ifp, &tag);
-            
-        save = ftell(ifp);
-        fseek (ifp, off, SEEK_SET);
+
+        save = ftell_nofail(ifp);
+        fseek_nofail (ifp, off, SEEK_SET);
         pm_readlittlelong(ifp, &sec_);
         if (sec_ != (0x20434553 | (tag << 24))) return;
         switch (tag) {
         case 0x47414d49:          /* IMAG */
-            if (data_offset) 
+            if (data_offset)
                 break;
             data_offset = off + 28;
-            fseek (ifp, 12, SEEK_CUR);
+            fseek_nofail (ifp, 12, SEEK_CUR);
             {
                 long wlong, hlong;
                 pm_readlittlelong(ifp, &wlong);
@@ -113,7 +113,7 @@ parse_foveon(FILE * const ifp) {
         case 0x504f5250:          /* PROP */
             pm_readlittlelong(ifp, &junk);
             pm_readlittlelong(ifp, &pent);
-            fseek (ifp, 12, SEEK_CUR);
+            fseek_nofail (ifp, 12, SEEK_CUR);
             off += pent*8 + 24;
             if (pent > 256) pent=256;
             for (i=0; i < pent*2; i++) {
@@ -133,14 +133,14 @@ parse_foveon(FILE * const ifp) {
                     timestamp = atoi (foveon_gets (poff[i][1], name, 64));
             }
         }
-        fseek (ifp, save, SEEK_SET);
+        fseek_nofail (ifp, save, SEEK_SET);
     }
     is_foveon = 1;
 }
 
 
 
-void  
+void
 foveon_coeff(int * const useCoeffP,
              float       coeff[3][4]) {
 
@@ -159,8 +159,8 @@ foveon_coeff(int * const useCoeffP,
 
 
 
-static void  
-foveon_decoder (unsigned int const huff[1024], 
+static void
+foveon_decoder (unsigned int const huff[1024],
                 unsigned int const code) {
 
     struct decode *cur;
@@ -180,7 +180,7 @@ foveon_decoder (unsigned int const huff[1024],
             }
         }
     }
-    if ((len = code >> 27) > 26) 
+    if ((len = code >> 27) > 26)
         return;
     code2 = (len+1) << 27 | (code & 0x3ffffff) << 1;
 
@@ -192,14 +192,14 @@ foveon_decoder (unsigned int const huff[1024],
 
 
 
-static void  
+static void
 foveon_load_camf() {
     unsigned int i, val;
     long key;
 
-    fseek (ifp, meta_offset, SEEK_SET);
+    fseek_nofail (ifp, meta_offset, SEEK_SET);
     pm_readlittlelong(ifp, &key);
-    fread (meta_data, 1, meta_length, ifp);
+    fread_nofail (meta_data, 1, meta_length, ifp);
     for (i=0; i < meta_length; i++) {
         key = (key * 1597 + 51749) % 244944;
         assert(have64BitArithmetic);
@@ -210,7 +210,7 @@ foveon_load_camf() {
 
 
 
-void  
+void
 foveon_load_raw(Image const image) {
 
     struct decode *dindex;
@@ -234,14 +234,14 @@ foveon_load_raw(Image const image) {
     for (row=0; row < height; row++) {
         long junk;
         memset (pred, 0, sizeof pred);
-        if (!bit) 
+        if (!bit)
             pm_readlittlelong(ifp, &junk);
         for (col=bit=0; col < width; col++) {
             FORC3 {
                 for (dindex=first_decode; dindex->branch[0]; ) {
                     if ((bit = (bit-1) & 31) == 31)
                         for (i=0; i < 4; i++)
-                            bitbuf = (bitbuf << 8) + fgetc(ifp);
+                            bitbuf = (bitbuf << 8) + fgetc_nofail(ifp);
                     dindex = dindex->branch[bitbuf >> bit & 1];
                 }
                 pred[c] += diff[dindex->leaf];
@@ -262,8 +262,8 @@ sget4(char const s[]) {
 
 
 
-static char *  
-foveon_camf_param (const char * const block, 
+static char *
+foveon_camf_param (const char * const block,
                    const char * const param) {
     unsigned idx, num;
     char *pos, *cp, *dp;
@@ -287,8 +287,8 @@ foveon_camf_param (const char * const block,
 
 
 
-static void *  
-foveon_camf_matrix (int                dim[3], 
+static void *
+foveon_camf_matrix (int                dim[3],
                     const char * const name) {
 
     unsigned i, idx, type, ndim, size, *mat;
@@ -325,9 +325,9 @@ foveon_camf_matrix (int                dim[3],
 
 
 
-static int  
-foveon_fixed (void *       const ptr, 
-              int          const size, 
+static int
+foveon_fixed (void *       const ptr,
+              int          const size,
               const char * const name) {
     void *dp;
     int dim[3];
@@ -345,7 +345,7 @@ static float  foveon_avg (unsigned short *pix, int range[2], float cfilt)
     float val, min=FLT_MAX, max=-FLT_MAX, sum=0;
 
     for (i=range[0]; i <= range[1]; i++) {
-        sum += val = 
+        sum += val =
             (short)pix[i*4] + ((short)pix[i*4]-(short)pix[(i-1)*4]) * cfilt;
         if (min > val) min = val;
         if (max < val) max = val;
@@ -390,11 +390,11 @@ static int  foveon_apply_curve (short *curve, int i)
     return i < 0 ? -(unsigned short)curve[1-i] : (unsigned short)curve[1+i];
 }
 
-void  
+void
 foveon_interpolate(Image const image,
                    float coeff[3][4]) {
 
-    static const short hood[] = { 
+    static const short hood[] = {
         -1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1 };
     short *pix, prev[3], *curve[8], (*shrink)[3];
     float cfilt=0.8, ddft[3][3][2], ppm[3][3][3];
@@ -441,7 +441,7 @@ foveon_interpolate(Image const image,
         for (i=0; i < 3; i++)
             FORC3 diag[c][i] = LAST(1,1)*LAST(2,2) - LAST(1,2)*LAST(2,1);
 #undef LAST
-        FORC3 div[c] = 
+        FORC3 div[c] =
             diag[c][0]*0.3127 + diag[c][1]*0.329 + diag[c][2]*0.3583;
     }
     num = 0;
@@ -494,11 +494,11 @@ foveon_interpolate(Image const image,
     for (row=1; row < height-1; row++) {
         FORC3 if (last[1][c] > last[0][c]) {
             if (last[1][c] > last[2][c])
-                black[row][c] = 
+                black[row][c] =
                     (last[0][c] > last[2][c]) ? last[0][c]:last[2][c];
         } else
             if (last[1][c] < last[2][c])
-                black[row][c] = 
+                black[row][c] =
                     (last[0][c] < last[2][c]) ? last[0][c]:last[2][c];
         memmove (last, last+1, 2*sizeof last[0]);
         memcpy (last[2], black[row+1], sizeof last[2]);
@@ -547,8 +547,8 @@ foveon_interpolate(Image const image,
                 diff = pix[c] - prev[c];
                 prev[c] = pix[c];
                 ipix[c] = pix[c] + floor ((diff + (diff*diff >> 14)) * cfilt
-                                          - ddft[0][c][1] 
-                                          - ddft[0][c][0] 
+                                          - ddft[0][c][1]
+                                          - ddft[0][c][0]
                                             * ((float) col/width - 0.5)
                                           - black[row][c] );
             }
@@ -563,7 +563,7 @@ foveon_interpolate(Image const image,
                         val += ppm[c][i][j] * work[i][j];
                 ipix[c] = floor ((ipix[c] + floor(val)) *
                                  ( sgrow[col/sgx  ][c] * (sgx - col%sgx) +
-                                   sgrow[col/sgx+1][c] * (col%sgx) ) / sgx / 
+                                   sgrow[col/sgx+1][c] * (col%sgx) ) / sgx /
                                  div[c]);
                 if (ipix[c] > 32000) ipix[c] = 32000;
                 pix[c] = ipix[c];
@@ -584,7 +584,7 @@ foveon_interpolate(Image const image,
             memset (fsum, 0, sizeof fsum);
             for (sum=j=0; j < 8; j++)
                 if (badpix[i] & (1 << j)) {
-                    FORC3 fsum[c] += 
+                    FORC3 fsum[c] +=
                         image[(row+hood[j*2])*width+col+hood[j*2+1]][c];
                     sum++;
                 }
@@ -665,8 +665,8 @@ foveon_interpolate(Image const image,
         pix = (short*)image[row*width+2];
         for (col=2; col < width-2; col++) {
             FORC3 dev[c] = -foveon_apply_curve (curve[7], pix[c] -
-                                                ((smrow[1][col][c] + 
-                                                  2*smrow[2][col][c] + 
+                                                ((smrow[1][col][c] +
+                                                  2*smrow[2][col][c] +
                                                   smrow[3][col][c]) >> 2));
             sum = (dev[0] + dev[1] + dev[2]) >> 3;
             FORC3 pix[c] += dev[c] - sum;
@@ -695,7 +695,7 @@ foveon_interpolate(Image const image,
             if (sum < 0) sum = 0;
             j = total[3] > 375 ? (sum << 16) / total[3] : sum * 174;
             FORC3 pix[c] += foveon_apply_curve (curve[6],
-                                                ((j*total[c] + 0x8000) >> 16) 
+                                                ((j*total[c] + 0x8000) >> 16)
                                                 - pix[c]);
             pix += 4;
         }
@@ -732,7 +732,7 @@ foveon_interpolate(Image const image,
                     shrink[row*(width/4)+col][c] = ipix[c] >> 4;
                 else
                     shrink[row*(width/4)+col][c] =
-                        (shrink[(row+1)*(width/4)+col][c]*1840 + 
+                        (shrink[(row+1)*(width/4)+col][c]*1840 +
                          ipix[c]*141 + 2048) >> 12;
         }
     }
@@ -742,7 +742,7 @@ foveon_interpolate(Image const image,
         if ((row & 3) == 0)
             for (col = width & ~3 ; col--; )
                 FORC3 smrow[0][col][c] = ipix[c] =
-                    (shrink[(row/4)*(width/4)+col/4][c]*1485 + 
+                    (shrink[(row/4)*(width/4)+col/4][c]*1485 +
                      ipix[c]*6707 + 4096) >> 13;
 
         /* Then smooth left-to-right */
@@ -757,7 +757,7 @@ foveon_interpolate(Image const image,
         else
             for (col=0; col < (width & ~3); col++)
                 FORC3 smrow[2][col][c] =
-                    (smrow[2][col][c]*6707 + smrow[1][col][c]*1485 + 4096) 
+                    (smrow[2][col][c]*6707 + smrow[1][col][c]*1485 + 4096)
                         >> 13;
 
         /* Adjust the chroma toward the smooth values */
@@ -770,7 +770,7 @@ foveon_interpolate(Image const image,
             for (sum=c=0; c < 3; c++) {
                 ipix[c] = foveon_apply_curve(
                     curve[c+3],
-                    ((smrow[2][col][c] * j + 0x8000) >> 16) - 
+                    ((smrow[2][col][c] * j + 0x8000) >> 16) -
                     image[row*width+col][c]);
                 sum += ipix[c];
             }
diff --git a/converter/other/cameratopam/identify.c b/converter/other/cameratopam/identify.c
index 26fa329e..e5df6b22 100644
--- a/converter/other/cameratopam/identify.c
+++ b/converter/other/cameratopam/identify.c
@@ -13,6 +13,7 @@
 #include "dng.h"
 #include "ljpeg.h"
 #include "camera.h"
+#include "stdio_nofail.h"
 
 #include "identify.h"
 
@@ -38,7 +39,7 @@ static const char *memmem_internal (const char *haystack, size_t haystacklen,
 
 
 
-static void 
+static void
 adobeCoeff(const char * const make,
            const char * const model) {
     /*
@@ -47,7 +48,7 @@ adobeCoeff(const char * const make,
     struct CoeffTableEntry {
         const char * prefix;
         short trans[12];
-    }; 
+    };
 
     static struct CoeffTableEntry const table[] = {
         { "Canon EOS D2000C",
@@ -331,17 +332,17 @@ identify(FILE *       const ifp,
 
     order = get2(ifp);
     hlen = get4(ifp);
-    fseek (ifp, 0, SEEK_SET);
-    fread (head, 1, 32, ifp);
-    fseek (ifp, 0, SEEK_END);
-    fsize = ftell(ifp);
+    fseek_nofail (ifp, 0, SEEK_SET);
+    fread_nofail (head, 1, 32, ifp);
+    fseek_nofail (ifp, 0, SEEK_END);
+    fsize = ftell_nofail(ifp);
     if ((c = (char*)memmem_internal(head, 32, "MMMMRawT", 8))) {
         strcpy (make, "Phase One");
         data_offset = c - head;
-        fseek (ifp, data_offset + 8, SEEK_SET);
-        fseek (ifp, get4(ifp) + 136, SEEK_CUR);
+        fseek_nofail (ifp, data_offset + 8, SEEK_SET);
+        fseek_nofail (ifp, get4(ifp) + 136, SEEK_CUR);
         raw_width = get4(ifp);
-        fseek (ifp, 12, SEEK_CUR);
+        fseek_nofail (ifp, 12, SEEK_CUR);
         raw_height = get4(ifp);
     } else if (order == 0x4949 || order == 0x4d4d) {
         if (!memcmp (head+6, "HEAPCCDR", 8)) {
@@ -356,14 +357,14 @@ identify(FILE *       const ifp,
         parse_minolta(ifp);
     else if (!memcmp (head, "\xff\xd8\xff\xe1", 4) &&
              !memcmp (head+6, "Exif", 4)) {
-        fseek (ifp, 4, SEEK_SET);
-        fseek (ifp, 4 + get2(ifp), SEEK_SET);
-        if (fgetc(ifp) != 0xff)
+        fseek_nofail (ifp, 4, SEEK_SET);
+        fseek_nofail (ifp, 4 + get2(ifp), SEEK_SET);
+        if (fgetc_nofail(ifp) != 0xff)
             parse_tiff(ifp, 12);
     } else if (!memcmp (head, "BM", 2)) {
         data_offset = 0x1000;
         order = 0x4949;
-        fseek (ifp, 38, SEEK_SET);
+        fseek_nofail (ifp, 38, SEEK_SET);
         if (get4(ifp) == 2834 && get4(ifp) == 2834) {
             strcpy (model, "BMQ");
             flip = 3;
@@ -374,7 +375,7 @@ identify(FILE *       const ifp,
     nucore:
         strcpy (make, "Nucore");
         order = 0x4949;
-        fseek (ifp, 10, SEEK_SET);
+        fseek_nofail (ifp, 10, SEEK_SET);
         data_offset += get4(ifp);
         get4(ifp);
         raw_width  = get4(ifp);
@@ -386,16 +387,16 @@ identify(FILE *       const ifp,
     } else if (!memcmp (head+25, "ARECOYK", 7)) {
         strcpy (make, "Contax");
         strcpy (model,"N Digital");
-        fseek (ifp, 60, SEEK_SET);
+        fseek_nofail (ifp, 60, SEEK_SET);
         camera_red  = get4(ifp);
         camera_red /= get4(ifp);
         camera_blue = get4(ifp);
         camera_blue = get4(ifp) / camera_blue;
     } else if (!memcmp (head, "FUJIFILM", 8)) {
         long data_offset_long;
-        fseek (ifp, 84, SEEK_SET);
+        fseek_nofail (ifp, 84, SEEK_SET);
         parse_tiff(ifp, get4(ifp)+12);
-        fseek (ifp, 100, SEEK_SET);
+        fseek_nofail (ifp, 100, SEEK_SET);
         pm_readbiglong(ifp, &data_offset_long);
         data_offset = data_offset_long;
     } else if (!memcmp (head, "DSC-Image", 9))
@@ -737,13 +738,13 @@ identify(FILE *       const ifp,
         width  = 2312;
         raw_width = 2336;
         data_offset = 4034;
-        fseek (ifp, 2032, SEEK_SET);
+        fseek_nofail (ifp, 2032, SEEK_SET);
         goto konica_400z;
     } else if (!strcmp(model,"Digital Camera KD-510Z")) {
         data_offset = 4032;
         pre_mul[0] = 1.297;
         pre_mul[2] = 1.438;
-        fseek (ifp, 2032, SEEK_SET);
+        fseek_nofail (ifp, 2032, SEEK_SET);
         goto konica_510z;
     } else if (!strcasecmp(make,"MINOLTA")) {
         load_raw = unpacked_load_raw;
@@ -767,19 +768,19 @@ identify(FILE *       const ifp,
                 data_offset = 5056;
                 pre_mul[0] = 1.602;
                 pre_mul[2] = 1.441;
-                fseek (ifp, 2078, SEEK_SET);
+                fseek_nofail (ifp, 2078, SEEK_SET);
                 height = 1716;
                 width  = 2304;
             } else if (model[8] == '5') {
                 data_offset = 4016;
-                fseek (ifp, 1936, SEEK_SET);
+                fseek_nofail (ifp, 1936, SEEK_SET);
             konica_510z:
                 height = 1956;
                 width  = 2607;
                 raw_width = 2624;
             } else if (model[8] == '6') {
                 data_offset = 4032;
-                fseek (ifp, 2030, SEEK_SET);
+                fseek_nofail (ifp, 2030, SEEK_SET);
                 height = 2136;
                 width  = 2848;
             }
@@ -885,7 +886,7 @@ identify(FILE *       const ifp,
         pre_mul[0] = 1.963;
         pre_mul[2] = 1.430;
     } else if (!strcmp(make,"Sinar") && !memcmp(head,"8BPS",4)) {
-        fseek (ifp, 14, SEEK_SET);
+        fseek_nofail (ifp, 14, SEEK_SET);
         height = get4(ifp);
         width  = get4(ifp);
         filters = 0x61616161;
@@ -1199,7 +1200,7 @@ dng_skip:
             for (i=0; i < 3; i++)
                 coeff[i][3] = coeff[i][1] /= 2;
     }
-    fseek (ifp, data_offset, SEEK_SET);
+    fseek_nofail (ifp, data_offset, SEEK_SET);
 
     *loadRawFnP = load_raw;
 
diff --git a/converter/other/cameratopam/ljpeg.c b/converter/other/cameratopam/ljpeg.c
index 331d258c..35f50f4b 100644
--- a/converter/other/cameratopam/ljpeg.c
+++ b/converter/other/cameratopam/ljpeg.c
@@ -2,7 +2,6 @@
 #define _BSD_SOURCE    /* Make sure string.h containst strcasecmp() */
 #include <stdlib.h>
 #include <string.h>
-#include <stdio.h>
 #include <limits.h>
 
 #include "pm.h"
@@ -11,6 +10,7 @@
 #include "util.h"
 #include "decode.h"
 #include "bayer.h"
+#include "stdio_nofail.h"
 
 #include "ljpeg.h"
 
@@ -20,7 +20,7 @@
    enough to decode Canon, Kodak and Adobe DNG images.
  */
 
-int  
+int
 ljpeg_start(FILE *         const ifP,
             struct jhead * const jhP) {
 
@@ -30,12 +30,12 @@ ljpeg_start(FILE *         const ifP,
     init_decoder();
     for (i=0; i < 4; i++)
         jhP->huff[i] = free_decode;
-    fread (data, 2, 1, ifP);
+    fread_nofail (data, 2, 1, ifP);
     if (data[0] != 0xff || data[1] != 0xd8) return 0;
     do {
         unsigned int len;
 
-        fread (data, 2, 2, ifP);
+        fread_nofail (data, 2, 2, ifP);
         tag =  data[0] << 8 | data[1];
         len = data[2] << 8 | data[3];
 
@@ -45,7 +45,7 @@ ljpeg_start(FILE *         const ifP,
             unsigned int const dataLen = len - 2;
 
             if (tag <= 0xff00 || dataLen > 255) return 0;
-            fread (data, 1, dataLen, ifP);
+            fread_nofail (data, 1, dataLen, ifP);
             switch (tag) {
             case 0xffc3:
                 jhP->bits = data[0];
@@ -73,7 +73,7 @@ ljpeg_start(FILE *         const ifP,
 
 
 
-int 
+int
 ljpeg_diff(FILE *          const ifP,
            struct decode * const dindexHeadP) {
 
@@ -111,7 +111,7 @@ ljpeg_row(FILE *         const ifP,
 
 
 
-void  
+void
 lossless_jpeg_load_raw(Image  const image) {
 
     int jwide, jrow, jcol, val, jidx, i, row, col;
@@ -161,5 +161,3 @@ lossless_jpeg_load_raw(Image  const image) {
     if (!strcasecmp(make,"KODAK"))
         black = min;
 }
-
-
diff --git a/converter/other/cameratopam/stdio_nofail.c b/converter/other/cameratopam/stdio_nofail.c
new file mode 100644
index 00000000..97a8796d
--- /dev/null
+++ b/converter/other/cameratopam/stdio_nofail.c
@@ -0,0 +1,120 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <netpbm/pm.h>
+
+#include "stdio_nofail.h"
+
+
+
+size_t
+fread_or_eof_nofail(void * const ptr,
+                    size_t const size,
+                    size_t const nmemb,
+                    FILE * const streamP) {
+
+    size_t rc;
+
+    rc = fread(ptr, size, nmemb, streamP);
+
+    if (rc < nmemb) {
+        if (!feof(streamP))
+            pm_error("File read failed.  Errno=%d (%s)",
+                     errno, strerror(errno));
+    }
+    return rc;
+}
+
+
+
+void
+fread_nofail(void * const ptr,
+             size_t const size,
+             size_t const nmemb,
+             FILE * const streamP) {
+
+    size_t rc;
+
+    rc = fread(ptr, size, nmemb, streamP);
+
+    if (rc < nmemb) {
+        if (feof(streamP))
+            pm_error("File read failed.  Premature end of file");
+        else
+            pm_error("File read failed.  Errno=%d (%s)",
+                     errno, strerror(errno));
+    }
+}
+
+
+
+int
+fgetc_nofail(FILE * streamP) {
+
+    int rc;
+
+    rc = fgetc(streamP);
+
+    if (rc == EOF) {
+        if (feof(streamP))
+            pm_error("File read failed.  Premature end of file");
+        else
+            pm_error("File read failed.  Errno=%d (%s)",
+                     errno, strerror(errno));
+    }
+    return rc;
+}
+
+
+
+int
+fseek_nofail(FILE * const streamP,
+             long   const offset,
+             int    const whence) {
+
+    int rc;
+
+    rc = fseek(streamP, offset, whence);
+
+    if (rc < 0)
+        pm_error("File seek failed.  Errno=%d (%s)", errno, strerror(errno));
+
+    return rc;
+}
+
+
+
+long
+ftell_nofail(FILE * const streamP) {
+
+    long rc;
+
+    rc = ftell(streamP);
+
+    if (rc < 0)
+        pm_error("File position query failed.  Errno=%d (%s)",
+                 errno, strerror(errno));
+
+    return rc;
+}
+
+
+
+char *
+fgets_nofail(char * const s,
+             int    const size,
+             FILE * const streamP) {
+
+    char * rc;
+
+    rc = fgets(s, size, streamP);
+
+    if (ferror(streamP))
+        pm_error("File read failed.  Errno=%d (%s)", errno, strerror(errno));
+
+    return rc;
+}
+
+
+
diff --git a/converter/other/cameratopam/stdio_nofail.h b/converter/other/cameratopam/stdio_nofail.h
new file mode 100644
index 00000000..8f45b537
--- /dev/null
+++ b/converter/other/cameratopam/stdio_nofail.h
@@ -0,0 +1,29 @@
+#include <stdio.h>
+
+size_t
+fread_or_eof_nofail(void * const ptr,
+                    size_t const size,
+                    size_t const nmemb,
+                    FILE * const streamP);
+
+void
+fread_nofail(void * const ptr,
+             size_t const size,
+             size_t const nmemb,
+             FILE * const streamP);
+
+int
+fgetc_nofail(FILE * const streamP);
+
+int
+fseek_nofail(FILE * const streamP,
+             long   const offset,
+             int    const whence);
+
+long
+ftell_nofail(FILE * const streamP);
+
+char *
+fgets_nofail(char * const s,
+             int    const size,
+             FILE * const streamP);
diff --git a/converter/other/cameratopam/util.c b/converter/other/cameratopam/util.c
index b3ccf7e9..ede5ef69 100644
--- a/converter/other/cameratopam/util.c
+++ b/converter/other/cameratopam/util.c
@@ -1,10 +1,12 @@
 #define _XOPEN_SOURCE   /* Make sure unistd.h contains swab() */
 #include <unistd.h>
-#include <stdio.h>
 
-#include "pm.h"
+#include "netpbm/pm.h"
+#include "netpbm/mallocvar.h"
+
 #include "global_variables.h"
 #include "util.h"
+#include "stdio_nofail.h"
 
 #ifndef LONG_BITS
 #define LONG_BITS (8 * sizeof(long))
@@ -18,7 +20,7 @@ get2(FILE * const ifp)
 {
     unsigned char a, b;
 
-    a = fgetc(ifp);  b = fgetc(ifp);
+    a = fgetc_nofail(ifp);  b = fgetc_nofail(ifp);
 
     if (order == 0x4949)      /* "II" means little-endian */
         return a | b << 8;
@@ -34,8 +36,8 @@ get4(FILE * const ifp)
 {
     unsigned char a, b, c, d;
 
-    a = fgetc(ifp);  b = fgetc(ifp);
-    c = fgetc(ifp);  d = fgetc(ifp);
+    a = fgetc_nofail(ifp);  b = fgetc_nofail(ifp);
+    c = fgetc_nofail(ifp);  d = fgetc_nofail(ifp);
 
     if (order == 0x4949)
         return a | b << 8 | c << 16 | d << 24;
@@ -49,9 +51,21 @@ get4(FILE * const ifp)
 void
 read_shorts (FILE * const ifp, unsigned short *pixel, int count)
 {
-    fread (pixel, 2, count, ifp);
-    if ((order == 0x4949) == (BYTE_ORDER == BIG_ENDIAN))
-        swab (pixel, pixel, count*2);
+    unsigned short * buffer;
+
+    MALLOCARRAY(buffer, count);
+
+    if (!buffer)
+        pm_error("Failed to allocate a buffer for reading %u short "
+                 "integers from file", count);
+    else {
+        fread_nofail(buffer, 2, count, ifp);
+
+        if ((order == 0x4949) == (BYTE_ORDER == BIG_ENDIAN))
+            swab(buffer, pixel, count*2);
+
+        free(buffer);
+    }
 }
 
 /*
@@ -73,10 +87,10 @@ getbits (FILE * const ifp, int nbits)
         vbits -= nbits;
     }
     while (vbits < LONG_BITS - 7) {
-        c = fgetc(ifp);
+        c = fgetc_nofail(ifp);
         bitbuf = (bitbuf << 8) + c;
         if (c == 0xff && zero_after_ff)
-            fgetc(ifp);
+            fgetc_nofail(ifp);
         vbits += 8;
     }
     return ret;
diff --git a/converter/other/fiasco/input/read.c b/converter/other/fiasco/input/read.c
index b4fcefc5..c3aa77a8 100644
--- a/converter/other/fiasco/input/read.c
+++ b/converter/other/fiasco/input/read.c
@@ -261,7 +261,7 @@ read_basis (const char *filename, wfa_t *wfa)
 
       if (fscanf (input, MAXSTRLEN_SCANF, magic) != 1)
 	 error ("Format error: ASCII FIASCO initial basis file %s", filename);
-      else if (strneq (FIASCO_BASIS_MAGIC, magic))
+      else if (!streq (FIASCO_BASIS_MAGIC, magic))
 	 error ("Input file %s is not an ASCII FIASCO initial basis!",
 		filename);
    }
diff --git a/converter/other/fiasco/lib/image.c b/converter/other/fiasco/lib/image.c
index a700fe88..705a56aa 100644
--- a/converter/other/fiasco/lib/image.c
+++ b/converter/other/fiasco/lib/image.c
@@ -2,7 +2,7 @@
  *  image.c:        Input and output of PNM images.
  *
  *  Written by:     Ullrich Hafner
- *      
+ *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
  */
@@ -31,7 +31,7 @@
 /*****************************************************************************
 
                 prototypes
-  
+
 *****************************************************************************/
 
 static void
@@ -40,7 +40,7 @@ init_chroma_tables (void);
 /*****************************************************************************
 
                 local variables
-  
+
 *****************************************************************************/
 static int *Cr_r_tab = NULL;
 static int *Cr_g_tab = NULL;
@@ -50,7 +50,7 @@ static int *Cb_b_tab = NULL;
 /*****************************************************************************
 
                 public code
-  
+
 *****************************************************************************/
 
 static fiasco_image_t *
@@ -197,7 +197,7 @@ cast_image (fiasco_image_t *image)
    image_t *this = (image_t *) image->private;
    if (this)
    {
-      if (!streq (this->id, "IFIASCO"))
+      if (!STRSEQ(this->id, "IFIASCO"))
       {
      set_error (_("Parameter `image' doesn't match required type."));
      return NULL;
@@ -240,7 +240,7 @@ alloc_image (unsigned width, unsigned height, bool_t color, format_e format)
    image->color       = color;
    image->format      = format;
    image->reference_count = 1;
-   
+
    STRSCPY(image->id, "IFIASCO");
 
    for (band = first_band (color); band <= last_band (color); band++)
@@ -249,7 +249,7 @@ alloc_image (unsigned width, unsigned height, bool_t color, format_e format)
                     sizeof (word_t));
       else
      image->pixels [band] = Calloc (width * height, sizeof (word_t));
-   
+
    return image;
 }
 
@@ -266,7 +266,7 @@ clone_image (image_t *image)
    image_t *new = alloc_image (image->width, image->height, image->color,
                    image->format);
    color_e band;
-   
+
    for (band = first_band (new->color); band <= last_band (new->color); band++)
       if (new->format == FORMAT_4_2_0 && band != Y)
       {
@@ -314,7 +314,7 @@ free_image (image_t *image)
 }
 
 
-static void 
+static void
 read_image_data(image_t * const image, FILE *input, const bool_t color,
                 const int width, const int height, const xelval maxval,
                 const int format) {
@@ -336,27 +336,27 @@ read_image_data(image_t * const image, FILE *input, const bool_t color,
 
    xelrow = pnm_allocrow(width);
 
-   i = 0; 
+   i = 0;
    for (row = 0; row < height; row++) {
        int col;
        pnm_readpnmrow(input, xelrow, width, maxval, format);
        for (col = 0; col < width; col++) {
            if (color) {
-               image->pixels[Y][i] = 
-                   coeff_lu_r * PPM_GETR(xelrow[col]) 
+               image->pixels[Y][i] =
+                   coeff_lu_r * PPM_GETR(xelrow[col])
                    + coeff_lu_g * PPM_GETG(xelrow[col])
                    + coeff_lu_b * PPM_GETB(xelrow[col]) - 2048;
-               image->pixels[Cb][i] = 
-                   coeff_cb_r * PPM_GETR(xelrow[col]) 
+               image->pixels[Cb][i] =
+                   coeff_cb_r * PPM_GETR(xelrow[col])
                    + coeff_cb_g * PPM_GETG(xelrow[col])
                    + coeff_cb_b * PPM_GETB(xelrow[col]);
-               image->pixels[Cr][i] = 
-                   coeff_cr_r * PPM_GETR(xelrow[col]) 
+               image->pixels[Cr][i] =
+                   coeff_cr_r * PPM_GETR(xelrow[col])
                    + coeff_cr_g * PPM_GETG(xelrow[col])
                    + coeff_cr_b * PPM_GETB(xelrow[col]);
 
                i++;
-           } else 
+           } else
                image->pixels[GRAY][i++] =
                    PNM_GET1(xelrow[col]) * 4095 / maxval - 2048;
        }
@@ -434,7 +434,7 @@ void
 write_image (const char *image_name, const image_t *image)
 /*
  *  Write given 'image' data to the file 'image_name'.
- *  
+ *
  *  No return value.
  */
 {
@@ -446,13 +446,13 @@ write_image (const char *image_name, const image_t *image)
    unsigned *gray_clip;         /* clipping table */
 
    assert (image && image_name);
-   
+
    if (image->format == FORMAT_4_2_0)
    {
       warning ("We cannot write images in 4:2:0 format.");
       return;
    }
-   
+
    if (image_name == NULL)
        output = stdout;
    else if (streq(image_name, "-"))
@@ -466,7 +466,7 @@ write_image (const char *image_name, const image_t *image)
    init_chroma_tables ();
 
    format = image->color ? PPM_TYPE : PGM_TYPE;
-   
+
    pnm_writepnminit(output, image->width, image->height, 255, format, 0);
 
    xelrow = pnm_allocrow(image->width);
@@ -481,18 +481,18 @@ write_image (const char *image_name, const image_t *image)
                cbval = image->pixels[Cb][i] / 16;
                crval = image->pixels[Cr][i] / 16;
 
-               PPM_ASSIGN(xelrow[col], 
+               PPM_ASSIGN(xelrow[col],
                           gray_clip[yval + Cr_r_tab[crval]],
                           gray_clip[yval + Cr_g_tab[crval] + Cb_g_tab [cbval]],
                           gray_clip[yval + Cb_b_tab[cbval]]);
 
            } else
                /* The 16 below should be 4095/255 = 16.0588 */
-               PNM_ASSIGN1(xelrow[col], 
+               PNM_ASSIGN1(xelrow[col],
                            gray_clip[image->pixels[GRAY][i]/16+128]);
            i++;
        }
-       pnm_writepnmrow(output, xelrow, 
+       pnm_writepnmrow(output, xelrow,
                        image->width, 255, format, 0);
    }
    pnm_freerow(xelrow);
@@ -511,7 +511,7 @@ same_image_type (const image_t *img1, const image_t *img2)
  */
 {
    assert (img1 && img2);
-   
+
    return ((img1->width == img2->width)
        && (img1->height == img2->height)
        && (img1->color == img2->color)
@@ -521,7 +521,7 @@ same_image_type (const image_t *img1, const image_t *img2)
 /*****************************************************************************
 
                 private code
-  
+
 *****************************************************************************/
 
 static void
@@ -547,21 +547,21 @@ init_chroma_tables (void)
 
       Cr_r_tab[i] =  1.4022 * crval + 0.5;
       Cr_g_tab[i] = -0.7145 * crval + 0.5;
-      Cb_g_tab[i] = -0.3456 * cbval + 0.5; 
+      Cb_g_tab[i] = -0.3456 * cbval + 0.5;
       Cb_b_tab[i] =  1.7710 * cbval + 0.5;
    }
    for (i = 0; i < 256; i++)
    {
       Cr_r_tab[i] = Cr_r_tab[256];
       Cr_g_tab[i] = Cr_g_tab[256];
-      Cb_g_tab[i] = Cb_g_tab[256]; 
+      Cb_g_tab[i] = Cb_g_tab[256];
       Cb_b_tab[i] = Cb_b_tab[256];
    }
    for (i = 512; i < 768; i++)
    {
       Cr_r_tab[i] = Cr_r_tab[511];
       Cr_g_tab[i] = Cr_g_tab[511];
-      Cb_g_tab[i] = Cb_g_tab[511]; 
+      Cb_g_tab[i] = Cb_g_tab[511];
       Cb_b_tab[i] = Cb_b_tab[511];
    }
 
diff --git a/converter/other/fiasco/lib/image.h b/converter/other/fiasco/lib/image.h
index a87a3c05..c3c5f0df 100644
--- a/converter/other/fiasco/lib/image.h
+++ b/converter/other/fiasco/lib/image.h
@@ -29,7 +29,7 @@ typedef struct image
  *  Image data
  */
 {
-   char      id [7];
+   char      id [8];         /* NUL-terminated "IFIASCO" */
    unsigned  reference_count;
    unsigned  width;			/* Width of the image */
    unsigned  height;			/* Height of the image */
diff --git a/converter/other/fiasco/lib/macros.h b/converter/other/fiasco/lib/macros.h
index 0bc80e7c..2f404a74 100644
--- a/converter/other/fiasco/lib/macros.h
+++ b/converter/other/fiasco/lib/macros.h
@@ -34,8 +34,6 @@
   
 *****************************************************************************/
 
-#define streq(str1, str2)	(strcmp ((str1), (str2)) == 0)
-#define strneq(str1, str2)	(strcmp ((str1), (str2)) != 0)
 #define square(x)		((x) * (x))
 #define first_band(color)	((unsigned) ((color) ? Y  : GRAY))
 #define last_band(color)        ((unsigned) ((color) ? Cr : GRAY))
diff --git a/converter/other/tifftopnm.c b/converter/other/tifftopnm.c
index 05493e73..0c301a4a 100644
--- a/converter/other/tifftopnm.c
+++ b/converter/other/tifftopnm.c
@@ -1357,10 +1357,10 @@ convertRasterByRows(pnmOut *       const pnmOutP,
            represented as single array element, so it's easy to work with.
         */
     xel * xelrow;
-        /* The ppm-format row of the image row we are presently converting */
+        /* The ppm-format row of the image row we are currently converting */
     gray * alpharow;
         /* The pgm-format row representing the alpha values for the image
-           row we are presently converting.
+           row we are currently converting.
         */
 
     unsigned int row;
@@ -1465,11 +1465,11 @@ convertTiffRaster(uint32 *        const raster,
 -----------------------------------------------------------------------------*/
     xel * xelrow;
         /* The ppm-format row of the image row we are
-           presently converting
+           currently converting
         */
     gray * alpharow;
         /* The pgm-format row representing the alpha values
-           for the image row we are presently converting.
+           for the image row we are currently converting.
         */
     unsigned int row;
 
@@ -1478,7 +1478,7 @@ convertTiffRaster(uint32 *        const raster,
 
     for (row = 0; row < rows; ++row) {
         uint32 * rp;
-            /* Address of pixel in 'raster' we are presently converting */
+            /* Address of pixel in 'raster' we are currently converting */
         unsigned int col;
 
         /* Start at beginning of row: */
diff --git a/converter/other/winicontopam.c b/converter/other/winicontopam.c
index 2ddf56b1..70729cce 100644
--- a/converter/other/winicontopam.c
+++ b/converter/other/winicontopam.c
@@ -1,3 +1,25 @@
+/*=============================================================================
+                             winicontopam
+===============================================================================
+  Convert from Windows icon format to PAM
+=============================================================================*/
+
+/*
+  Here are some references for the Windows icon format:
+
+  ICO (file format) - Wikipedia
+  https://en.wikipedia.org/wiki/ICO_(file_format)
+
+  ICO - Just Solve the File Format Problem
+  http://fileformats.archiveteam.org/wiki/ICO
+  (Has links to example icon file collections)
+
+  GFF Format Summary: Microsoft Windows Cursor and Icon
+  https://web.archive.org/web/20050421161512/http:/www.oreilly.com/www/centers/gff/formats/miccur/index.htm
+
+
+*/
+
 #include <assert.h>
 #include <stdio.h>
 #include <string.h>
@@ -25,7 +47,7 @@ static bool verbose;
 
 
 struct CmdlineInfo {
-    
+
     const char * inputFileName;
     unsigned int allimages;
     unsigned int imageSpec;
@@ -78,7 +100,7 @@ parseCommandLine(int argc, const char **argv,
             pm_error("Too many arguments.  The only possible "
                      "non-option argument is the input file name");
     }
-        
+
     free(option_def);
 }
 
@@ -93,7 +115,7 @@ struct File {
     FILE *       fileP;
     const char * name;
     pm_filepos   pos;
-    
+
 };
 
 
@@ -122,7 +144,7 @@ static uint32_t
 u32_le(const unsigned char * const buf,
        size_t                const offset) {
 
-    return 
+    return
         ((uint32_t)buf[offset + 0] <<  0) +
         ((uint32_t)buf[offset + 1] <<  8) +
         ((uint32_t)buf[offset + 2] << 16) +
@@ -135,7 +157,7 @@ static uint32_t
 s32_le(const unsigned char * const buf,
        size_t                const offset) {
 
-    return 
+    return
         ((uint32_t)buf[offset + 0] <<  0) +
         ((uint32_t)buf[offset + 1] <<  8) +
         ((uint32_t)buf[offset + 2] << 16) +
@@ -156,8 +178,8 @@ u8_be(const unsigned char * const buf,
 static uint32_t
 u32_be(const unsigned char * const buf,
        size_t                const offset) {
-    
-    return 
+
+    return
         ((uint32_t)buf[offset + 0] << 24) +
         ((uint32_t)buf[offset + 1] << 16) +
         ((uint32_t)buf[offset + 2] <<  8) +
@@ -225,7 +247,7 @@ dumpIconDir(const struct IconDir * const dirP) {
     }
 }
 
-            
+
 
 static struct IconDir *
 readIconDir(struct File * const fP,
@@ -271,7 +293,7 @@ readIconDir(struct File * const fP,
 
         pm_readcharu(fP->fileP, &heightField);
         dirEntryP->height = (heightField == 0 ? 256 : heightField);
-        
+
         pm_readcharu(fP->fileP, &dirEntryP->color_count);
 
         pm_readcharu(fP->fileP, &dirEntryP->zero);
@@ -290,7 +312,7 @@ readIconDir(struct File * const fP,
     }
 
     /* The following is paranoia code only:
-     
+
        I've never seen a windows icon file in the wild with having the entries
        in the directory stored in a different order than the images
        themselves.  However, the file format allows for it ...
@@ -301,7 +323,7 @@ readIconDir(struct File * const fP,
         pm_message("%s icon directory (%u image%s):",
                    fP->name,
                    dirP->count, dirP->count == 1 ? "" : "s");
-        
+
         for (imageIndex = 0; imageIndex < dirP->count; ++imageIndex) {
             const struct IconDirEntry * const dirEntryP =
                 &dirP->entries[imageIndex];
@@ -355,7 +377,7 @@ readImage(struct File *         const fP,
 
     /*  Don't try to read an image that is smaller than the
         BITMAPINFOHEADER of BMP images (40 bytes).
-     
+
         PNG compressed images can't be smaller than that either, as the
         PNG header plus the mandantory IHDR and IEND chunks already take
         8 + 25 + 12 = 35 bytes, and there is to be a IDAT chunk too.
@@ -369,7 +391,7 @@ readImage(struct File *         const fP,
                  dirEntryP->index);
 
     /* The following is paranoia code only:
-     
+
        I've never seen a windows icon file in the wild with gaps between
        the images, but the file format allows for it, and Microsoft
        expects the user to fseek() to the start of each image.
@@ -472,11 +494,11 @@ readXorPalette(struct BitmapInfoHeader * const hdrP,
     uint32_t    bytesPerRow;
     const unsigned char * bitmapCursor;
     uint32_t sizeRemaining;
-  
+
     uint8_t (*getIdx) (const unsigned char * bitmap,
                        uint32_t rowOffset,
                        int16_t col);
-  
+
     if (hdrP->compression_method != BI_RGB)
         pm_error("image %2u: invalid compression method %u.",
                  index, hdrP->compression_method);
@@ -518,7 +540,7 @@ readXorPalette(struct BitmapInfoHeader * const hdrP,
     if (sizeRemaining < paletteSize)
         pm_error("image %2u: "
                  "reading palette: image truncated.", index);
-    
+
     palette = (const PaletteEntry *) bitmapCursor;
 
     if (needHeaderDump)
@@ -562,7 +584,7 @@ readXorPalette(struct BitmapInfoHeader * const hdrP,
 
                 /*  The palette is an array of little-endian 32-bit values,
                     where the RGB value is encoded as follows:
-                 
+
                     red:   bits 2^16..2^23
                     green: bits 2^8 ..2^15
                     blue:  bits 2^0 ..2^7
@@ -823,7 +845,7 @@ readAnd(struct BitmapInfoHeader * const hdrP,
 
         if (offset + bytesPerRow <= sizeRemaining) {
             unsigned int col;
-            
+
             for (col = 0; col < hdrP->bm_width; ++col) {
                 tuples[row][col][plane] =
                     ((u8_le(bitmap, offset + col/8)
@@ -952,7 +974,7 @@ reportImage(unsigned int            const imageIndex,
             struct BitmapInfoHeader const hdr,
             bool                    const haveAlpha) {
 
-    const char * const style = 
+    const char * const style =
         haveAlpha ? "RGB +alpha" :
         hdr.bits_per_pixel < 16 ? "RGB/palette" :
         "RGB"
@@ -973,7 +995,7 @@ convertBmp(const unsigned char * const image,
            struct IconDirEntry * const dirEntryP,
            bool                  const needHeaderDump,
            bool                  const wantAndMaskPlane) {
-    
+
     struct BitmapInfoHeader hdr;
     uint32_t                offset;
     bool                    haveAlpha;
@@ -1024,7 +1046,7 @@ convertBmp(const unsigned char * const image,
 
     tuples = pnm_allocpamarray(&outpam);
 
-    readXorMask(&hdr, &image[offset], 
+    readXorMask(&hdr, &image[offset],
                 dirEntryP->size - offset,
                 tuples, dirEntryP->index, needHeaderDump,
                 &haveAlpha, &xorByteCt);
@@ -1070,7 +1092,7 @@ convertBmp(const unsigned char * const image,
 static void
 reportPngInfo(const unsigned char * const image,
               struct IconDirEntry * const dirEntryP) {
-    
+
     struct PngIhdr ihdr;
 
     ihdr.length      = u32_be (image, sizeof(pngHeader)  +0);
@@ -1148,14 +1170,16 @@ convertPng(const unsigned char * const image,
            FILE *                const ofP,
            struct IconDirEntry * const dirEntryP) {
 
-    struct bufferDesc imageBuffer;
+    pm_bufferDesc imageBuffer;
 
     reportPngInfo(image, dirEntryP);
 
-    imageBuffer.size = dirEntryP->size;
-    imageBuffer.buffer = (unsigned char *)image;
+    imageBuffer.size              = dirEntryP->size;
+    imageBuffer.buffer            = (unsigned char *)image;
+    imageBuffer.bytesTransferredP = NULL;
+
+    fflush(stdout);
 
-    fflush (stdout);
     pm_system_lp("pngtopam", pm_feed_from_memory, &imageBuffer,
                  NULL /* stdout accepter */, NULL,
                  "pngtopam", "-alphapam", NULL);
@@ -1174,7 +1198,7 @@ bestImage(struct IconDir * const dirP) {
     bestPixelCt = 0;  /* initial value */
     bestColorCt = 0;  /* initial value */
     best        = 0;  /* initial value */
-    
+
     for (imageIndex = 0; dirP->count > imageIndex; ++imageIndex) {
         struct IconDirEntry * const dirEntryP = &dirP->entries[imageIndex];
 
@@ -1183,7 +1207,7 @@ bestImage(struct IconDir * const dirP) {
         uint32_t colorCt;
 
         /*  32-bit icons have 24 bit color information only.
-         
+
             Since NT 5.1 (aka WinXP), it is allowed to place 8-bit
             transparency information in the remaining bits (to check,
             you have to read all these bits in the image!), so I prefer
@@ -1273,7 +1297,7 @@ main (int argc, const char *argv []) {
         convertImage(&ico, &dirP->entries[bestImage(dirP)], stdout,
                      cmdline.headerdump, cmdline.andmasks);
     }
-    
+
     freeIconDir(dirP);
 
     if (ico.fileP != stdin)
diff --git a/converter/other/xwdtopnm.c b/converter/other/xwdtopnm.c
index a74da341..a99768b8 100644
--- a/converter/other/xwdtopnm.c
+++ b/converter/other/xwdtopnm.c
@@ -999,7 +999,7 @@ pixelReader_getbits(pixelReader * const rdrP,
 -----------------------------------------------------------------------------*/
     unsigned long pixel;
         /* Accumulator for the value we ultimately return.  We shift in
-           bits from the right end.  The number of bits presently in the
+           bits from the right end.  The number of bits currently in the
            accumulator is rdrP->bitsPerPixel - nBitsStillNeeded .
         */
 
diff --git a/converter/pbm/pbmtonokia.c b/converter/pbm/pbmtonokia.c
index 80b0bd59..4604064a 100644
--- a/converter/pbm/pbmtonokia.c
+++ b/converter/pbm/pbmtonokia.c
@@ -83,7 +83,7 @@ parseCommandLine(int argc, char ** argv,
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0, "fmt",     OPT_STRING, &fmtOpt, 
+    OPTENT3(0, "fmt",     OPT_STRING, &fmtOpt,
             &fmtSpec, 0);
     OPTENT3(0, "net",     OPT_STRING, &netOpt,
             &netSpec, 0);
@@ -135,7 +135,7 @@ parseCommandLine(int argc, char ** argv,
                  "the 120 characters allowed by the format.",
                  (unsigned)strlen(cmdlineP->txt));
 
-    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 "
@@ -180,7 +180,7 @@ convertToHexNol(bit **       const image,
 
     /* header */
     fprintf(ofP, "06050415820000%s00%02X%02X01", networkCode, cols, rows);
-    
+
     /* image */
     for (row = 0; row < rows; ++row) {
         unsigned int col;
@@ -245,7 +245,7 @@ convertToHexNpm(bit **       const image,
                 FILE *       const ofP) {
 
     unsigned int row;
-    
+
     /* header */
     fprintf(ofP, "060504158A0000");
 
@@ -293,7 +293,7 @@ convertToNol(bit **       const image,
     unsigned int row;
     char header[32];
     unsigned int it;
-    
+
     /* header - this is a hack */
 
     header[ 0] = 'N';
@@ -318,7 +318,7 @@ convertToNol(bit **       const image,
     header[19] = 0;
 
     fwrite(header, 20, 1, ofP);
-    
+
     /* image */
     for (row = 0; row < rows; ++row) {
         unsigned int col;
@@ -368,7 +368,7 @@ convertToNgg(bit **       const image,
     header[15] = 0;
 
     fwrite(header, 16, 1, ofP);
-    
+
     /* image */
 
     for (row = 0; row < rows; ++row) {
@@ -395,35 +395,56 @@ convertToNpm(bit **       const image,
              const char * const text,
              FILE *       const ofP) {
 
+    size_t const textLen = text ? strlen(text) : 0;
+
     unsigned int row;
     char header[132];
-    size_t len;
-
-    if (text) 
-        len = strlen(text);
-    else
-        len = 0;
 
     /* header and optional text */
 
-    header[       0] = 'N';
-    header[       1] = 'P';
-    header[       2] = 'M';
-    header[       3] = 0;
-    header[       4] = len;
-    header[       5] = 0;
-    if (text)
-        memcpy(&header[6], text, len);
-    header[ 6 + len] = cols;
-    header[ 7 + len] = rows;
-    header[ 8 + len] = 1;
-    header[ 9 + len] = 1;
-    header[10 + len] = 0; /* unknown */
-
-    assert(10 + len < sizeof(header));
-
-    fwrite(header, 11 + len, 1, ofP);
-    
+    /* Our entry condition is that 'text' be a legal text field, which means
+       no more than 120 characters:
+    */
+    assert(textLen <= 120);
+
+    /* We don't have any specification of this format, but in May 2020, we
+       found what looks like a bug: the memcpy of the text field started at
+       &header[5] (overwriting the previous setting of header[5] and leaving
+       header[6+len-1] not set to anything).  Nobody ever complained about
+       this, so maybe somehow it worked better than the sensible code we have
+       now, where the text field starts in the 7th byte.
+    */
+
+    /* The code below that deliberately avoids using 'text' as an argument to
+       memcpy when 'text' is null looks like it should have no practical
+       effect, because with a zero length memcpy, it shouldn't matter what the
+       from and to arguments are.  But it's logically correct - a null pointer
+       just doesn't point anywhere.  And believe it or not, it has a practical
+       effect - a truly bizarre one.  This code used to be simpler and just
+       pass that null pointer to memcpy, with length 0, and as reported in May
+       2020, a new optimizing compiler caused header[3] to contain random
+       values.  That's right: 3.  Skipping that presumed no-op memcpy stopped
+       the behavior.
+    */
+
+    header[           0] = 'N';
+    header[           1] = 'P';
+    header[           2] = 'M';
+    header[           3] = 0;
+    header[           4] = textLen;
+    header[           5] = 0;
+    if (text)  /* see above */
+        memcpy(&header[6], text, textLen);
+    header[ 6 + textLen] = cols;
+    header[ 7 + textLen] = rows;
+    header[ 8 + textLen] = 1;
+    header[ 9 + textLen] = 1;
+    header[10 + textLen] = 0; /* unknown */
+
+    assert(10 + textLen < sizeof(header));
+
+    fwrite(header, 11 + textLen, 1, ofP);
+
     /* image: stream of bits, each row padded to a byte boundary
        inspired by gnokii/common/gsm-filesystems.c
      */
@@ -453,7 +474,7 @@ convertToNpm(bit **       const image,
 
 
 
-int 
+int
 main(int    argc,
      char * argv[]) {
 
@@ -521,6 +542,6 @@ Testing:
   The data was send with EMI/UCP protocol over TCP/IP.
 
   - 7.6.2001: tested with Nokia 3210: 72x14 Operator Logo
-  - 7.6.2001: tested with Nokia 6210: 72x14 Operator Logo and 
+  - 7.6.2001: tested with Nokia 6210: 72x14 Operator Logo and
               72x14 Group Graphic
 */
diff --git a/converter/pbm/xbmtopbm.c b/converter/pbm/xbmtopbm.c
index bbf4e395..1f5384ed 100644
--- a/converter/pbm/xbmtopbm.c
+++ b/converter/pbm/xbmtopbm.c
@@ -109,25 +109,35 @@ parseDeclaration(const char * const line,
 -----------------------------------------------------------------------------*/
     char nameAndType[MAX_LINE];
     int rc;
-        
+
     rc = sscanf(line, "static short %s = {", nameAndType);
     if (rc == 1) {
         *version10P     = TRUE;
         *isDeclarationP = TRUE;
     } else {
         int rc;
-        rc = sscanf(line, "static char %s = {", nameAndType);
+        rc = sscanf(line, "static unsigned short %s = {", nameAndType);
         if (rc == 1) {
-            *version10P     = FALSE;
+            /* This is apparently not legal X10 XBM; we recognize it as an
+               extension.  Many non-Netpbm programs won't.
+            */
+            *version10P     = TRUE;
             *isDeclarationP = TRUE;
         } else {
             int rc;
-            rc = sscanf(line, "static unsigned char %s = {", nameAndType);
+            rc = sscanf(line, "static char %s = {", nameAndType);
             if (rc == 1) {
                 *version10P     = FALSE;
                 *isDeclarationP = TRUE;
-            } else
-                *isDeclarationP = FALSE;
+            } else {
+                int rc;
+                rc = sscanf(line, "static unsigned char %s = {", nameAndType);
+                if (rc == 1) {
+                    *version10P     = FALSE;
+                    *isDeclarationP = TRUE;
+                } else
+                    *isDeclarationP = FALSE;
+            }
         }
     }
 }
@@ -178,7 +188,7 @@ getXbmHeader(FILE *         const ifP,
         }
     }
 
-    if (!foundDeclaration) 
+    if (!foundDeclaration)
         pm_error("Unable to find a line in the file containing the start "
                  "of C array declaration (\"static char\" or whatever)");
 
@@ -208,7 +218,7 @@ getHexByte(FILE *         const ifP,
 
     assert(c1 >= 0); assert(c1 < 256);
     assert(c2 >= 0); assert(c2 < 256);
-    
+
     value = (hexTable[c1] << 4) + hexTable[c2];
     if (value >= 256)
         pm_error("Invalid XBM input.  What should be a two digit "
@@ -218,7 +228,7 @@ getHexByte(FILE *         const ifP,
 }
 
 
-                     
+
 static void
 readX10Raster(FILE *          const ifP,
               unsigned int    const rasterLength,
@@ -301,7 +311,7 @@ readBitmapFile(FILE *           const ifP,
     mustPad = (width % 16 >= 1 && width % 16 <= 8 && version10);
 
     bytesPerLine = (width + 7) / 8 + (mustPad ? 1 : 0);
-    
+
     rasterLength = bytesPerLine * height;
 
     MALLOCARRAY(data, rasterLength);
@@ -331,7 +341,7 @@ main(int    argc,
     const char * inputFileName;
     unsigned char * p;
         /* Cursor in raster data data[] */
-    
+
     initHexTable();
 
     pbm_init(&argc, argv);
@@ -339,7 +349,7 @@ main(int    argc,
     if (argc-1 > 1)
         pm_error("The only possible argument is the input file name.  "
                  "You specified %u arguments", argc-1);
-    
+
     if (argc-1 > 0)
         inputFileName = argv[1];
     else
@@ -359,7 +369,7 @@ main(int    argc,
     for (row = 0; row < rows; ++row) {
         unsigned int const bytesPerRow = pbm_packed_bytes(cols);
         unsigned int i;
-        
+
         for (i = 0; i < bytesPerRow; ++i)
             bitrow[i] = bitreverse[*p++];
 
diff --git a/converter/ppm/hpcdtoppm/hpcdtoppm b/converter/ppm/hpcdtoppm/hpcdtoppm
index 2af4a384..ec3f1763 100755
--- a/converter/ppm/hpcdtoppm/hpcdtoppm
+++ b/converter/ppm/hpcdtoppm/hpcdtoppm
@@ -8,9 +8,9 @@ The real 'hpcdtoppm' is a program that converts an image from Photo CD format
 to PPM format.  The program you are running now just issues the message you
 are reading.
 
-Please get a copy of Hpcdtoppm from 
+You can get a copy of Hpcdtoppm from 
 
-  http://terasaur.org/item/show/hpcdtoppm-netpbm-convert-photo-cd/4967
+  http://metalab.unc.edu/pub/Linux/apps/graphics/convert/hpcdtoppm.linux.tar.gz
 
 and replace this stand-in program with the real one.
 
@@ -22,4 +22,4 @@ mistake.
 
 EOF
 
-exit 1
\ No newline at end of file
+exit 1
diff --git a/converter/ppm/hpcdtoppm/pcdovtoppm b/converter/ppm/hpcdtoppm/pcdovtoppm
index dbf6f53d..7f7239e3 100755
--- a/converter/ppm/hpcdtoppm/pcdovtoppm
+++ b/converter/ppm/hpcdtoppm/pcdovtoppm
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 #
 # pcdovtoppm - generate a single PPM file from a PCD overview file
 #
@@ -19,12 +19,16 @@
 # Rewritten in sh by Steve McIntyre <93sam@debian.org>, 2001
 
 # You may want to change the default values in the next 6 lines:
-maxwidth=1152   # maximum width of the index image
-size=192                # make the images about this big
-across=6                # show this many images per row
-colors="noquant"        # maximum amount of colors or noquant (no quantization)
-back="-black"   # default background color
-font=" "                # default font or none (pbmtext's internal font)
+maxwidth=1152     # maximum width of the index image
+size=192          # make the images about this big
+across=6          # show this many images per row
+colors="noquant"  # maximum amount of colors or noquant (no quantization)
+back="-black"     # default background color
+font=" "          # default font or none (pbmtext's internal font)
+
+plainopt=""       # output plain ppm
+quietopt=""       # quiet operation (currently no effect)
+versionopt=0
 
 usage ()
 {
@@ -47,71 +51,99 @@ usage ()
     exit 1
 }
 
+version ()
+{
+    # report version using pnmscale
+    pnmscale -version $quietopt
+    exit 0
+}
+
 # Parse the options
 while :; do
     case "$1" in 
-        -m*)
+        -m|-ma|-max|-maxw|-maxwi|-maxwid|-maxwidt|-maxwidth )
              if [ $# -lt 2 ] ; then usage; fi
              maxwidth="$2"
              shift
              shift
              ;;
 
-        -s*)
+        -s|-si|-siz|-size )
              if [ $# -lt 2 ] ; then usage; fi
              size="$2"
              shift
              shift
              ;;
 
-            -a*)
-                if [ $# -lt 2 ] ; then usage; fi
-                across="$2"
-                shift
-                shift
-                ;;
-
-            -c*)
-                if [ $# -lt 2 ] ; then usage; fi
-                colors="$2"
-                shift
-                shift
-                ;;
-
-            -f*)
-                if [ $# -lt 2 ] ; then usage; fi
-                font="-font $2"
-                shift
-                shift
-                ;;
-
-            -b*)
-                back="-black"
-                shift
-                ;;
-
-            -w*)
-                back="-white"
-                shift
-                ;;
-
-            -*)
-                echo "$0 : Unknown option $1"
-                echo " "
-                usage
-                ;;
-
-            *)
-                break
-                ;;
+         -a|-ac|-acr|-acro|-acros|-across )
+             if [ $# -lt 2 ] ; then usage; fi
+             across="$2"
+             shift
+             shift
+             ;;
+
+         -c|-co|-col|-colo|-color|-colors )
+             if [ $# -lt 2 ] ; then usage; fi
+             colors="$2"
+             shift
+             shift
+             ;;
+
+         -f|-fo|-fon|-font )
+             if [ $# -lt 2 ] ; then usage; fi
+             font="-font $2"
+             shift
+             shift
+             ;;
+
+         -b|-bl|-bla|-blac|-black )
+             back="-black"
+             shift
+             ;;
+
+         -w|-wh|-whi|-whit|-white )
+             back="-white"
+             shift
+             ;;
+             
+         -p|-pl|-pla|-plai|-plain )
+             plainopt="-plain"
+             shift
+             ;;
+            
+         -q|-qu|-qui|-quie|-quiet )
+             quietopt="-quiet"
+             shift
+             ;;
+             
+         -v|-ve|-ver|-vers|-versi|-versio|-version )
+             versionopt="1"
+             shift
+             ;;
+                    
+         -*)
+             echo "$0 : Unknown option $1" 1>&2
+             echo " " 1>&2
+             usage
+             ;;
+
+         *)
+             break
+             ;;
 
     esac
 done
 
-if [ $# = 0 ]; then
+if [ $versionopt -eq 1 ] ; then
+    version
+elif [ $# = 0 ] ; then
     usage
 fi
 
+tempdir=$(mktemp -d "${TMPDIR:-/tmp}/pcdovtoppm.XXXXXXXX") ||
+    { echo "Could not create temporary file. Exiting." 1>&2; exit 1; }
+trap 'rm -rf $tempdir' 0
+
 tmpfile=`tempfile -p pi -m 600`
 
 rowfiles=()
@@ -122,10 +154,11 @@ width=$size
 
 # Convert the PCD overview file to many PPM images
 if [ -f $1 ] ; then
-    hpcdtoppm -Overview $1 $tmpfile
+    hpcdtoppm -Overview $1 $tmpfile ||
+        { echo "$0: Hpcdtoppm failed. Exiting" 1>&2 ; exit 1; }
 else
-    echo "$0 : Could not access $1"
-    echo " "
+    echo "$0 : Could not access $1" 1>&2
+    echo " " 1>&2
     usage
 fi
 
@@ -145,7 +178,7 @@ do
             fi
         fi
     fi
-    imagefile=pi.${row}.${col}.$$
+    imagefile=${tempdir}/pi.${row}.${col}
     rm -f $imagefile
     ttext="$i:t"
 
@@ -163,7 +196,7 @@ do
     imagefiles="$imagefiles $imagefile"
 
     if [ $col -ge $across -o $width -gt $maxwidth ] ; then
-        rowfile=pi.${row}.$$
+        rowfile=${tempdir}/pi.${row}
         rm -f $rowfile
     if [ "$colors" = "n" ] ; then
         pnmcat $back -lr -jbottom $imagefiles > $rowfile
@@ -183,7 +216,7 @@ do
 done
 
 if [ ${#imagefiles[*]} -gt 0 ] ; then
-    rowfile=pi.${row}.$$
+    rowfile=${tempdir}/pi.${row}
     rm -f $rowfile
     if [ "$colors" = "n" ] ; then
         pnmcat $back -lr -jbottom $imagefiles > $rowfile
@@ -195,13 +228,13 @@ if [ ${#imagefiles[*]} -gt 0 ] ; then
     rowfiles="$rowfiles $rowfile"
 fi
 
-if [ ${#rowfiles[*]} = 1 ]; then
-    cat $rowfiles
+if [ ${#rowfiles[*]} = 1 ] ; then
+    ppmtoppm $plainopt < $rowfiles
 else
     if [ "$colors" = "n" ] ; then
-        pnmcat $back -tb $rowfiles
+        pnmcat $back -tb $plainopt $rowfiles
     else
-        pnmcat $back -tb $rowfiles | ppmquant -quiet $colors
+        pnmcat $back -tb $rowfiles | ppmquant $plainopt -quiet $colors
     fi
 fi
 
@@ -210,5 +243,3 @@ rm -f $rowfiles
 exit 0
 
 
-
-
diff --git a/converter/ppm/picttoppm.c b/converter/ppm/picttoppm.c
index 656e4e5f..4bc53378 100644
--- a/converter/ppm/picttoppm.c
+++ b/converter/ppm/picttoppm.c
@@ -51,10 +51,18 @@ typedef unsigned long Longword;
  */
 
 struct Rect {
-    Word top;
-    Word left;
-    Word bottom;
-    Word right;
+/*----------------------------------------------------------------------------
+   A rectangle - description of a region of an image raster.
+
+   If last row or column is before first, it is a null rectangle - it
+   describes no pixels.
+-----------------------------------------------------------------------------*/
+    Word top;     /* Start row */
+    Word left;    /* Start column */
+    Word bottom;  /* End row */
+    Word right;   /* End column */
+
+    /* "End" means last plus one */
 };
 
 struct pixMap {
@@ -88,14 +96,21 @@ struct Pattern {
     Byte pix[64];
 };
 
-struct rgbPlanes {
+struct RgbPlanes {
+/*----------------------------------------------------------------------------
+   A raster, as three planes: red, green, blue.
+
+   Each plane is an array in row-major order.
+-----------------------------------------------------------------------------*/
+    unsigned int width;
+    unsigned int height;
     Word * red;
     Word * grn;
     Word * blu;
 };
 
 struct canvas {
-    struct rgbPlanes planes;
+    struct RgbPlanes planes;
 };
 
 typedef void (*transfer_func) (struct RGBColor* src, struct RGBColor* dst);
@@ -818,14 +833,36 @@ readRect(struct Rect * const r) {
 
 
 static int
+rectisnull(struct Rect * const r) {
+
+    return r->top >= r->bottom || r->left >= r->right;
+}
+
+
+
+static int
 rectwidth(const struct Rect * const r) {
+
     return r->right - r->left;
 }
 
 
 
+static bool
+rectequal(const struct Rect * const comparand,
+          const struct Rect * const comparator) {
+
+    return
+        comparand->top    == comparator->top &&
+        comparand->bottom == comparator->bottom &&
+        comparand->left   == comparator->left &&
+        comparand->right  == comparator->right;
+}
+
+
 static int
 rectheight(const struct Rect * const r) {
+
     return r->bottom - r->top;
 }
 
@@ -834,6 +871,7 @@ rectheight(const struct Rect * const r) {
 static bool
 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,14 +879,18 @@ rectsamesize(struct Rect const r1,
 
 
 static void
-rectinter(struct Rect   const r1,
-          struct Rect   const r2,
-          struct Rect * const intersectionP) {
+rectintersect(const struct Rect * const r1P,
+              const struct Rect * const r2P,
+              struct Rect *       const intersectionP) {
+/*----------------------------------------------------------------------------
+   Compute the intersection of two rectangles.
 
-    intersectionP->left   = MAX(r1.left,   r2.left);
-    intersectionP->top    = MAX(r1.top,    r2.top);
-    intersectionP->right  = MIN(r1.right,  r2.right);
-    intersectionP->bottom = MIN(r1.bottom, r2.bottom);
+   Note that if the rectangles are disjoint, the result is a null rectangle.
+-----------------------------------------------------------------------------*/
+    intersectionP->left   = MAX(r1P->left,   r2P->left);
+    intersectionP->top    = MAX(r1P->top,    r2P->top);
+    intersectionP->right  = MIN(r1P->right,  r2P->right);
+    intersectionP->bottom = MIN(r1P->bottom, r2P->bottom);
 }
 
 
@@ -857,16 +899,17 @@ static void
 rectscale(struct Rect * const r,
           double        const xscale,
           double        const yscale) {
-    r->left *= xscale;
-    r->right *= xscale;
-    r->top *= yscale;
+
+    r->left   *= xscale;
+    r->right  *= xscale;
+    r->top    *= yscale;
     r->bottom *= yscale;
 }
 
 
 
 static void
-    initBlitList(blitList * const blitListP) {
+initBlitList(blitList * const blitListP) {
 
     blitListP->firstP          = NULL;
     blitListP->connectorP      = &blitListP->firstP;
@@ -1192,43 +1235,122 @@ decode16(unsigned char * const sixteen) {
 
 
 static void
-doDiffSize(struct Rect       const clipsrc,
-           struct Rect       const clipdst,
-           int               const pixSize,
-           int               const xsize,
-           int               const ysize,
+closeValidatePamscalePipe(FILE * const pipeP) {
+
+    int rc;
+
+    rc = pclose(pipeP);
+
+    if (rc != 0)
+        pm_error("pamscale failed.  pclose() returned Errno %s (%d)",
+                 strerror(errno), errno);
+}
+
+
+
+static void
+convertScaledPpm(const char *      const scaledFilename,
+                 transfer_func     const trf,
+                 struct RgbPlanes  const dst,
+                 unsigned int      const dstadd) {
+
+    Word * reddst;
+    Word * grndst;
+    Word * bludst;
+    FILE * scaledP;
+    int cols, rows, format;
+    pixval maxval;
+    pixel * pixrow;
+
+    reddst = &dst.red[0];  /* initial value */
+    grndst = &dst.grn[0];  /* initial value */
+    bludst = &dst.blu[0];  /* initial value */
+
+    scaledP = pm_openr(scaledFilename);
+
+    ppm_readppminit(scaledP, &cols, &rows, &maxval, &format);
+
+    pixrow = ppm_allocrow(cols);
+
+    if (trf) {
+        unsigned int row;
+
+        for (row = 0; row < rows; ++row) {
+            unsigned int col;
+
+            ppm_readppmrow(scaledP, pixrow, cols, maxval, format);
+
+            for (col = 0; col < cols; ++col) {
+                struct RGBColor dst_c, src_c;
+                dst_c.red = *reddst;
+                dst_c.grn = *grndst;
+                dst_c.blu = *bludst;
+                src_c.red = PPM_GETR(pixrow[col]) * 65536L / (maxval + 1);
+                src_c.grn = PPM_GETG(pixrow[col]) * 65536L / (maxval + 1);
+                src_c.blu = PPM_GETB(pixrow[col]) * 65536L / (maxval + 1);
+                (*trf)(&src_c, &dst_c);
+                *reddst++ = dst_c.red;
+                *grndst++ = dst_c.grn;
+                *bludst++ = dst_c.blu;
+            }
+            reddst += dstadd;
+            grndst += dstadd;
+            bludst += dstadd;
+        }
+    } else {
+        unsigned int row;
+
+        for (row = 0; row < rows; ++row) {
+            unsigned int col;
+
+            ppm_readppmrow(scaledP, pixrow, cols, maxval, format);
+
+            for (col = 0; col < cols; ++col) {
+                *reddst++ = PPM_GETR(pixrow[col]) * 65536L / (maxval + 1);
+                *grndst++ = PPM_GETG(pixrow[col]) * 65536L / (maxval + 1);
+                *bludst++ = PPM_GETB(pixrow[col]) * 65536L / (maxval + 1);
+            }
+            reddst += dstadd;
+            grndst += dstadd;
+            bludst += dstadd;
+        }
+    }
+    assert(reddst == &dst.red[dst.height * dst.width]);
+    assert(grndst == &dst.grn[dst.height * dst.width]);
+    assert(bludst == &dst.blu[dst.height * dst.width]);
+
+    ppm_freerow(pixrow);
+    pm_close(scaledP);
+}
+
+
+
+static void
+doDiffSize(struct Rect       const srcRect,
+           struct Rect       const dstRect,
+           unsigned int      const pixSize,
            transfer_func     const trf,
            struct RGBColor * const color_map,
            unsigned char *   const src,
-           int               const srcwid,
-           struct rgbPlanes  const dst,
-           unsigned int      const dstwid) {
-
-    unsigned int const dstadd = dstwid - rectwidth(&clipdst);
+           unsigned int      const srcwid,
+           struct RgbPlanes  const dst) {
+/*----------------------------------------------------------------------------
+   Generate the raster in the plane buffers indicated by 'dst'.
 
+   'src' is the source pixels as a row-major array with rows 'srcwid' bytes
+   long.
+-----------------------------------------------------------------------------*/
     FILE * pamscalePipeP;
     const char * command;
-    FILE * scaled;
-    int cols, rows, format;
-    pixval maxval;
-    pixel * row;
-    pixel * rowp;
     FILE * tempFileP;
     const char * tempFilename;
-    Word * reddst;
-    Word * grndst;
-    Word * bludst;
-
-    reddst = dst.red;  /* initial value */
-    grndst = dst.grn;  /* initial value */
-    bludst = dst.blu;  /* initial value */
 
     pm_make_tmpfile(&tempFileP, &tempFilename);
 
     pm_close(tempFileP);
 
-    pm_asprintf(&command, "pamscale -xsize %d -ysize %d > %s",
-                rectwidth(&clipdst), rectheight(&clipdst), tempFilename);
+    pm_asprintf(&command, "pamscale -xsize %u -ysize %u > %s",
+                rectwidth(&dstRect), rectheight(&dstRect), tempFilename);
 
     pm_message("running command '%s'", command);
 
@@ -1239,108 +1361,61 @@ doDiffSize(struct Rect       const clipsrc,
 
     pm_strfree(command);
 
-    fprintf(pamscalePipeP, "P6\n%d %d\n%d\n",
-            rectwidth(&clipsrc), rectheight(&clipsrc), PPM_MAXMAXVAL);
+    fprintf(pamscalePipeP, "P6\n%u %u\n%u\n",
+            rectwidth(&srcRect), rectheight(&srcRect), PPM_MAXMAXVAL);
 
     switch (pixSize) {
     case 8: {
-        unsigned int rowNumber;
-        for (rowNumber = 0; rowNumber < ysize; ++rowNumber) {
-            unsigned char * const row = &src[rowNumber * srcwid];
-            unsigned int colNumber;
-            for (colNumber = 0; colNumber < xsize; ++colNumber) {
-                unsigned int const colorIndex = row[colNumber];
+        unsigned int row;
+        for (row = 0; row < rectheight(&srcRect); ++row) {
+            unsigned char * const rowBytes = &src[row * srcwid];
+            unsigned int col;
+            for (col = 0; col < rectwidth(&srcRect); ++col) {
+                unsigned int const colorIndex = rowBytes[col];
                 struct RGBColor * const ct = &color_map[colorIndex];
                 fputc(redepth(ct->red, 65535L), pamscalePipeP);
                 fputc(redepth(ct->grn, 65535L), pamscalePipeP);
                 fputc(redepth(ct->blu, 65535L), pamscalePipeP);
             }
         }
-    }
-    break;
+    } break;
     case 16: {
-        unsigned int rowNumber;
-        for (rowNumber = 0; rowNumber < ysize; ++rowNumber) {
-            unsigned char * const row = &src[rowNumber * srcwid];
-            unsigned int colNumber;
-            for (colNumber = 0; colNumber < xsize; ++colNumber) {
-                struct RGBColor const color = decode16(&row[colNumber * 2]);
+        unsigned int row;
+        for (row = 0; row < rectheight(&srcRect); ++row) {
+            unsigned char * const rowBytes = &src[row * srcwid];
+            unsigned int col;
+            for (col = 0; col < rectwidth(&srcRect); ++col) {
+                struct RGBColor const color = decode16(&rowBytes[col * 2]);
                 fputc(redepth(color.red, 32), pamscalePipeP);
                 fputc(redepth(color.grn, 32), pamscalePipeP);
                 fputc(redepth(color.blu, 32), pamscalePipeP);
             }
         }
-    }
-    break;
+    } break;
     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];
-            unsigned char * const grnPlane = &row[planeSize * 1];
-            unsigned char * const bluPlane = &row[planeSize * 2];
-
-            unsigned int colNumber;
-            for (colNumber = 0; colNumber < xsize; ++colNumber) {
-                fputc(redepth(redPlane[colNumber], 256), pamscalePipeP);
-                fputc(redepth(grnPlane[colNumber], 256), pamscalePipeP);
-                fputc(redepth(bluPlane[colNumber], 256), pamscalePipeP);
+        unsigned int row;
+
+        for (row = 0; row < rectheight(&srcRect); ++row) {
+            unsigned char * const rowBytes = &src[row * srcwid];
+            unsigned char * const redPlane = &rowBytes[planeSize * 0];
+            unsigned char * const grnPlane = &rowBytes[planeSize * 1];
+            unsigned char * const bluPlane = &rowBytes[planeSize * 2];
+
+            unsigned int col;
+            for (col = 0; col < rectwidth(&srcRect); ++col) {
+                fputc(redepth(redPlane[col], 256), pamscalePipeP);
+                fputc(redepth(grnPlane[col], 256), pamscalePipeP);
+                fputc(redepth(bluPlane[col], 256), pamscalePipeP);
             }
         }
-    }
-    break;
-    }
+    } break;
+    } /* switch */
 
-    if (pclose(pamscalePipeP))
-        pm_error("pamscale failed.  pclose() returned Errno %s (%d)",
-                 strerror(errno), errno);
+    closeValidatePamscalePipe(pamscalePipeP);
 
-    ppm_readppminit(scaled = pm_openr(tempFilename), &cols, &rows,
-                    &maxval, &format);
-    row = ppm_allocrow(cols);
-    /* 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 += dstadd;
-            grndst += dstadd;
-            bludst += dstadd;
-        }
-    }
-    else {
-        while (rows-- > 0) {
-            unsigned int i;
-            ppm_readppmrow(scaled, row, cols, maxval, format);
-            for (i = 0, rowp = row; i < cols; i++, rowp++) {
-                struct RGBColor dst_c, src_c;
-                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);
-                (*trf)(&src_c, &dst_c);
-                *reddst++ = dst_c.red;
-                *grndst++ = dst_c.grn;
-                *bludst++ = dst_c.blu;
-            }
-            reddst += dstadd;
-            grndst += dstadd;
-            bludst += dstadd;
-        }
-    }
+    convertScaledPpm(tempFilename, trf, dst, dst.width-rectwidth(&dstRect));
 
-    pm_close(scaled);
-    ppm_freerow(row);
     pm_strfree(tempFilename);
     unlink(tempFilename);
 }
@@ -1348,7 +1423,7 @@ doDiffSize(struct Rect       const clipsrc,
 
 
 static void
-getRgb(struct rgbPlanes  const planes,
+getRgb(struct RgbPlanes  const planes,
        unsigned int      const index,
        struct RGBColor * const rgbP) {
 
@@ -1362,7 +1437,7 @@ getRgb(struct rgbPlanes  const planes,
 static void
 putRgb(struct RGBColor  const rgb,
        unsigned int     const index,
-       struct rgbPlanes const planes) {
+       struct RgbPlanes const planes) {
 
     planes.red[index] = rgb.red;
     planes.grn[index] = rgb.grn;
@@ -1374,12 +1449,11 @@ putRgb(struct RGBColor  const rgb,
 static void
 doSameSize(transfer_func           trf,
            int               const pixSize,
-           int               const xsize,
-           int               const ysize,
+           struct Rect       const srcRect,
            unsigned char *   const src,
            unsigned int      const srcwid,
            struct RGBColor * const color_map,
-           struct rgbPlanes  const dst,
+           struct RgbPlanes  const dst,
            unsigned int      const dstwid) {
 /*----------------------------------------------------------------------------
    Transfer pixels from 'src' to 'dst', applying the transfer function
@@ -1401,6 +1475,9 @@ doSameSize(transfer_func           trf,
    colors, never a palette index.  It is an array in row-major order
    with 'dstwid' words per row.
 -----------------------------------------------------------------------------*/
+    unsigned int const xsize = rectwidth(&srcRect);
+    unsigned int const ysize = rectheight(&srcRect);
+
     switch (pixSize) {
     case 8: {
         unsigned int rowNumber;
@@ -1476,12 +1553,11 @@ doSameSize(transfer_func           trf,
 
 static void
 blitIdempotent(unsigned int          const pixSize,
-               unsigned int          const xsize,
-               unsigned int          const ysize,
+               struct Rect           const srcRect,
                unsigned char *       const src,
                unsigned int          const srcwid,
                struct RGBColor *     const colorMap,
-               struct rgbPlanes      const dst,
+               struct RgbPlanes      const dst,
                unsigned int          const dstwid) {
 /*----------------------------------------------------------------------------
   This is the same as doSameSize(), except optimized for the case that
@@ -1491,6 +1567,9 @@ blitIdempotent(unsigned int          const pixSize,
   expanding it to handle arbitrary transfer functions, added functions
   for that.
 -----------------------------------------------------------------------------*/
+    unsigned int const xsize = rectwidth(&srcRect);
+    unsigned int const ysize = rectheight(&srcRect);
+
     switch (pixSize) {
     case 8: {
         unsigned int rowNumber;
@@ -1559,7 +1638,7 @@ doBlit(struct Rect       const srcRect,
        struct Rect       const srcBounds,
        struct raster     const srcplane,
        struct Rect       const dstBounds,
-       struct rgbPlanes  const canvasPlanes,
+       struct RgbPlanes  const canvasPlanes,
        int               const pixSize,
        int               const dstwid,
        struct RGBColor * const color_map,
@@ -1579,10 +1658,8 @@ doBlit(struct Rect       const srcRect,
    with 'dstwid' words per row.
 -----------------------------------------------------------------------------*/
     unsigned char * src;
-    struct rgbPlanes dst;
+    struct RgbPlanes dst;
     int dstoff;
-    int xsize;
-    int ysize;
     transfer_func trf;
 
     if (verbose) {
@@ -1601,12 +1678,17 @@ doBlit(struct Rect       const srcRect,
         assert(srcRowNumber < srcplane.rowCount);
         assert(srcRowOffset < srcplane.rowSize);
         src = srcplane.bytes + srcRowNumber * srcplane.rowSize + srcRowOffset;
-        xsize = rectwidth(&srcRect);
-        ysize = rectheight(&srcRect);
     }
 
+    /* This 'dstoff'/'dstadd' abomination has to be fixed.  We need to pass to
+       'doDiffSize' the whole actual canvas, 'canvasPlanes', and tell it to
+       what part of the canvas to write.  It can compute the location of each
+       destination row as it comes to it.
+     */
     dstoff = (dstRect.top - dstBounds.top) * dstwid +
         (dstRect.left - dstBounds.left);
+    dst.height = canvasPlanes.height - (dstRect.top - dstBounds.top);
+    dst.width  = canvasPlanes.width;
     dst.red = canvasPlanes.red + dstoff;
     dst.grn = canvasPlanes.grn + dstoff;
     dst.blu = canvasPlanes.blu + dstoff;
@@ -1618,14 +1700,14 @@ doBlit(struct Rect       const srcRect,
         trf = transfer(mode & ~64);
 
     if (!rectsamesize(srcRect, dstRect))
-        doDiffSize(srcRect, dstRect, pixSize, xsize, ysize,
-                   trf, color_map, src, srcplane.rowSize, dst, dstwid);
+        doDiffSize(srcRect, dstRect, pixSize,
+                   trf, color_map, src, srcplane.rowSize, dst);
     else {
         if (trf == NULL)
-            blitIdempotent(pixSize, xsize, ysize, src, srcplane.rowSize,
+            blitIdempotent(pixSize, srcRect, src, srcplane.rowSize,
                            color_map, dst, dstwid);
         else
-            doSameSize(trf, pixSize, xsize, ysize, src, srcplane.rowSize,
+            doSameSize(trf, pixSize, srcRect, src, srcplane.rowSize,
                        color_map, dst, dstwid);
     }
 }
@@ -1671,8 +1753,8 @@ blit(struct Rect       const srcRect,
         struct Rect clipsrc;
         struct Rect clipdst;
 
-        rectinter(srcBounds, srcRect, &clipsrc);
-        rectinter(dstBounds, dstRect, &clipdst);
+        rectintersect(&srcBounds, &srcRect, &clipsrc);
+        rectintersect(&dstBounds, &dstRect, &clipdst);
 
         if (blitListP) {
             addBlitList(blitListP,
@@ -1702,11 +1784,14 @@ blit(struct Rect       const srcRect,
 static void
 allocPlanes(unsigned int       const width,
             unsigned int       const height,
-            struct rgbPlanes * const planesP) {
+            struct RgbPlanes * const planesP) {
 
     unsigned int const planelen = width * height;
 
-    struct rgbPlanes planes;
+    struct RgbPlanes planes;
+
+    planes.width  = width;
+    planes.height = height;
 
     MALLOCARRAY(planes.red, planelen);
     MALLOCARRAY(planes.grn, planelen);
@@ -1725,7 +1810,7 @@ allocPlanes(unsigned int       const width,
 
 
 static void
-freePlanes(struct rgbPlanes const planes) {
+freePlanes(struct RgbPlanes const planes) {
 
     free(planes.red);
     free(planes.grn);
@@ -1882,7 +1967,7 @@ doBlitList(struct canvas * const canvasP,
 
 static void
 outputPpm(FILE *           const ofP,
-          struct rgbPlanes const planes) {
+          struct RgbPlanes const planes) {
 
     unsigned int width;
     unsigned int height;
@@ -1922,8 +2007,9 @@ outputPpm(FILE *           const ofP,
  * is padded with a null.
  */
 static Word
-get_op(int const version) {
-    if ((align & 1) && version == 2) {
+nextOp(int const version) {
+
+    if ((align & 0x1) && version == 2) {
         stage = "aligning for opcode";
         readByte();
     }
@@ -1958,10 +2044,19 @@ ClipRgn(struct canvas * const canvasP,
            it to accept this clip rectangle, this program found the image to
            have an invalid raster.
         */
+        struct Rect clipRgnParm;
 
-        readRect(&clip_rect);
-        rectinter(clip_rect, picFrame, &clip_rect);
-        /* XXX should clip this by picFrame */
+        readRect(&clipRgnParm);
+
+        rectintersect(&clipRgnParm, &picFrame, &clip_rect);
+
+        if (!rectequal(&clipRgnParm, &clip_rect)) {
+            pm_message("ClipRgn opcode says to clip to a region which "
+                       "is not contained within the picture frame.  "
+                       "Ignoring the part outside the picture frame.");
+            dumpRect("ClipRgn:", clipRgnParm);
+            dumpRect("Picture frame:", picFrame);
+        }
         if (verbose)
             dumpRect("clipping to", clip_rect);
     } else
@@ -2867,19 +2962,32 @@ RGBBkCol(struct canvas * const canvasP,
 
 
 
-#define PIXEL_INDEX(x,y) ((y) - picFrame.top) * rowlen + (x) - picFrame.left
+static unsigned int
+pixelIndex(struct Rect  const picFrame,
+           unsigned int const x,
+           unsigned int const y) {
+
+    unsigned int const rowLen = picFrame.right - picFrame.left;
+
+    assert(y >= picFrame.top  && y < picFrame.bottom);
+    assert(x >= picFrame.left && x < picFrame.right);
+
+    return (y - picFrame.top) * rowLen + (x - picFrame.left);
+}
+
+
 
 static void
-draw_pixel(struct canvas *   const canvasP,
-           int               const x,
-           int               const y,
-           struct RGBColor * const clr,
-           transfer_func           trf) {
+drawPixel(struct canvas *   const canvasP,
+          int               const x,
+          int               const y,
+          struct RGBColor * const clr,
+          transfer_func           trf) {
 
     if (x < clip_rect.left || x >= clip_rect.right ||
         y < clip_rect.top  || y >= clip_rect.bottom) {
     } else {
-        unsigned int const i = PIXEL_INDEX(x, y);
+        unsigned int const i = pixelIndex(picFrame, x, y);
 
         struct RGBColor dst;
 
@@ -2898,55 +3006,66 @@ draw_pixel(struct canvas *   const canvasP,
 
 
 static void
-draw_pen_rect(struct canvas * const canvasP,
-              struct Rect *   const r) {
+drawPenRect(struct canvas * const canvasP,
+            struct Rect *   const rP) {
 
-    int const rowadd = rowlen - (r->right - r->left);
+    if (!rectisnull(rP)) {
+        unsigned int const rowadd = rowlen - (rP->right - rP->left);
 
-    int i;
-    int x, y;
-    struct RGBColor dst;
+        unsigned int i;
+        unsigned int y;
 
-    i = PIXEL_INDEX(r->left, r->top);  /* initial value */
+        dumpRect("BRYAN: drawing rectangle ", *rP);
+        i = pixelIndex(picFrame, rP->left, rP->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];
-            dst.grn = canvasP->planes.grn[i];
-            dst.blu = canvasP->planes.blu[i];
+        for (y = rP->top; y < rP->bottom; ++y) {
 
-            if (pen_pat.pix[(x & 7) + (y & 7) * 8])
-                (*pen_trf)(&black, &dst);
-            else
-                (*pen_trf)(&white, &dst);
+            unsigned int x;
+
+            for (x = rP->left; x < rP->right; ++x) {
+
+                struct RGBColor dst;
+
+                assert(i < canvasP->planes.height * canvasP->planes.width);
+
+                dst.red = canvasP->planes.red[i];
+                dst.grn = canvasP->planes.grn[i];
+                dst.blu = canvasP->planes.blu[i];
 
-            canvasP->planes.red[i] = dst.red;
-            canvasP->planes.grn[i] = dst.grn;
-            canvasP->planes.blu[i] = dst.blu;
+                if (pen_pat.pix[(x & 7) + (y & 7) * 8])
+                    (*pen_trf)(&black, &dst);
+                else
+                    (*pen_trf)(&white, &dst);
 
-            i++;
+                canvasP->planes.red[i] = dst.red;
+                canvasP->planes.grn[i] = dst.grn;
+                canvasP->planes.blu[i] = dst.blu;
+
+                ++i;
+            }
+            i += rowadd;
         }
-        i += rowadd;
     }
 }
 
 
 
 static void
-draw_pen(struct canvas * const canvasP,
-         int             const x,
-         int             const y) {
+drawPen(struct canvas * const canvasP,
+        int             const x,
+        int             const y) {
 
-    struct Rect penrect;
+    struct Rect unclippedPenrect;
+    struct Rect clippedPenrect;
 
-    penrect.left = x;
-    penrect.right = x + pen_width;
-    penrect.top = y;
-    penrect.bottom = y + pen_height;
+    unclippedPenrect.left = x;
+    unclippedPenrect.right = x + pen_width;
+    unclippedPenrect.top = y;
+    unclippedPenrect.bottom = y + pen_height;
 
-    rectinter(penrect, clip_rect, &penrect);
+    rectintersect(&unclippedPenrect, &clip_rect, &clippedPenrect);
 
-    draw_pen_rect(canvasP, &penrect);
+    drawPenRect(canvasP, &clippedPenrect);
 }
 
 /*
@@ -2963,11 +3082,11 @@ draw_pen(struct canvas * const canvasP,
  * Paul Heckbert    3 Sep 85
  */
 static void
-scan_line(struct canvas * const canvasP,
-          short           const x1,
-          short           const y1,
-          short           const x2,
-          short           const y2) {
+scanLine(struct canvas * const canvasP,
+         short           const x1,
+         short           const y1,
+         short           const x2,
+         short           const y2) {
 
     int d, x, y, ax, ay, sx, sy, dx, dy;
 
@@ -2981,7 +3100,7 @@ scan_line(struct canvas * const canvasP,
         if (ax>ay) {        /* x dominant */
             d = ay-(ax>>1);
             for (;;) {
-                draw_pen(canvasP, x, y);
+                drawPen(canvasP, x, y);
                 if (x==x2) return;
                 if ((x > rowlen) && (sx > 0)) return;
                 if (d>=0) {
@@ -2995,7 +3114,7 @@ scan_line(struct canvas * const canvasP,
         else {          /* y dominant */
             d = ax-(ay>>1);
             for (;;) {
-                draw_pen(canvasP, x, y);
+                drawPen(canvasP, x, y);
                 if (y==y2) return;
                 if ((y > collen) && (sy > 0)) return;
                 if (d>=0) {
@@ -3024,7 +3143,7 @@ Line(struct canvas * const canvasP,
   if (verbose)
     pm_message("(%d,%d) to (%d, %d)",
            p1.x,p1.y,current.x,current.y);
-  scan_line(canvasP, p1.x,p1.y,current.x,current.y);
+  scanLine(canvasP, p1.x,p1.y,current.x,current.y);
 }
 
 
@@ -3042,7 +3161,7 @@ LineFrom(struct canvas * const canvasP,
         pm_message("(%d,%d) to (%d, %d)", current.x, current.y, p1.x, p1.y);
 
     if (!blitListP)
-        scan_line(canvasP, current.x, current.y, p1.x, p1.y);
+        scanLine(canvasP, current.x, current.y, p1.x, p1.y);
 
     current.x = p1.x;
     current.y = p1.y;
@@ -3066,7 +3185,7 @@ ShortLine(struct canvas * const canvasP,
     current.y += p1.y;
 
     if (!blitListP)
-        scan_line(canvasP, p1.x, p1.y, current.x, current.y);
+        scanLine(canvasP, p1.x, p1.y, current.x, current.y);
 }
 
 
@@ -3086,7 +3205,7 @@ ShortLineFrom(struct canvas * const canvasP,
     p1.x += current.x;
     p1.y += current.y;
     if (!blitListP)
-        scan_line(canvasP, current.x, current.y, p1.x, p1.y);
+        scanLine(canvasP, current.x, current.y, p1.x, p1.y);
     current.x = p1.x;
     current.y = p1.y;
 }
@@ -3094,17 +3213,17 @@ ShortLineFrom(struct canvas * const canvasP,
 
 
 static void
-do_paintRect(struct canvas * const canvasP,
-             struct Rect     const prect) {
+doPaintRect(struct canvas * const canvasP,
+            struct Rect     const prect) {
 
     struct Rect rect;
 
     if (verbose)
         dumpRect("painting", prect);
 
-    rectinter(clip_rect, prect, &rect);
+    rectintersect(&clip_rect, &prect, &rect);
 
-    draw_pen_rect(canvasP, &rect);
+    drawPenRect(canvasP, &rect);
 }
 
 
@@ -3118,7 +3237,7 @@ paintRect(struct canvas * const canvasP,
 
     readRect(&cur_rect);
     if (!blitListP)
-        do_paintRect(canvasP, cur_rect);
+        doPaintRect(canvasP, cur_rect);
 }
 
 
@@ -3131,14 +3250,14 @@ paintSameRect(struct canvas * const canvasP,
               int             const version) {
 
     if (!blitListP)
-        do_paintRect(canvasP, cur_rect);
+        doPaintRect(canvasP, cur_rect);
 }
 
 
 
 static void
-do_frameRect(struct canvas * const canvasP,
-             struct Rect     const rect) {
+doFrameRect(struct canvas * const canvasP,
+            struct Rect     const rect) {
 
     if (verbose)
         dumpRect("framing", rect);
@@ -3147,13 +3266,13 @@ do_frameRect(struct canvas * const canvasP,
         unsigned int x, y;
 
         for (x = rect.left; x <= rect.right - pen_width; x += pen_width) {
-            draw_pen(canvasP, x, rect.top);
-            draw_pen(canvasP, x, rect.bottom - pen_height);
+            drawPen(canvasP, x, rect.top);
+            drawPen(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);
+            drawPen(canvasP, rect.left, y);
+            drawPen(canvasP, rect.right - pen_width, y);
         }
     }
 }
@@ -3168,8 +3287,9 @@ frameRect(struct canvas * const canvasP,
           int             const version) {
 
     readRect(&cur_rect);
+
     if (!blitListP)
-        do_frameRect(canvasP, cur_rect);
+        doFrameRect(canvasP, cur_rect);
 }
 
 
@@ -3182,7 +3302,7 @@ frameSameRect(struct canvas * const canvasP,
               int             const version) {
 
     if (!blitListP)
-        do_frameRect(canvasP, cur_rect);
+        doFrameRect(canvasP, cur_rect);
 }
 
 
@@ -3190,7 +3310,7 @@ frameSameRect(struct canvas * const canvasP,
 /* a stupid shell sort - I'm so embarrassed  */
 
 static void
-poly_sort(int const sort_index, struct Point points[]) {
+polySort(int const sort_index, struct Point points[]) {
   int d, i, j, temp;
 
   /* initialize and set up sort interval */
@@ -3223,9 +3343,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
-scan_poly(struct canvas * const canvasP,
-          int             const np,
-          struct Point          pts[]) {
+scanPoly(struct canvas * const canvasP,
+         int             const np,
+         struct Point          pts[]) {
 
   int dx,dy,dxabs,dyabs,i,scan_index,j,k,px,py;
   int sdx,sdy,x,y,toggle,old_sdy,sy0;
@@ -3279,7 +3399,7 @@ scan_poly(struct canvas * const canvasP,
         scan_index++;
       }
       px += sdx;
-      draw_pen(canvasP, px, py);
+      drawPen(canvasP, px, py);
     }
       }
     else
@@ -3295,7 +3415,7 @@ scan_poly(struct canvas * const canvasP,
         old_sdy = sdy;
         if (sdy != 0) scan_index--;
       }
-      draw_pen(canvasP, px,py);
+      drawPen(canvasP, px,py);
       coord[scan_index].x = px;
       coord[scan_index].y = py;
       scan_index++;
@@ -3308,14 +3428,14 @@ scan_poly(struct canvas * const canvasP,
   scan_index--;
   if (sy0 + sdy == 0) scan_index--;
 
-  poly_sort(scan_index, coord);
+  polySort(scan_index, coord);
 
   toggle = 0;
   for (i = 0; i < scan_index; i++) {
     if ((coord[i].y == coord[i+1].y) && (toggle == 0))
       {
     for (j = coord[i].x; j <= coord[i+1].x; j++)
-      draw_pen(canvasP, j, coord[i].y);
+      drawPen(canvasP, j, coord[i].y);
     toggle = 1;
       }
     else
@@ -3342,7 +3462,7 @@ paintPoly(struct canvas * const canvasP,
 
   /* scan convert poly ... */
   if (!blitListP)
-      scan_poly(canvasP, np, pts);
+      scanPoly(canvasP, np, pts);
 }
 
 
@@ -3426,7 +3546,7 @@ TxSize(struct canvas * const canvasP,
 
 
 static void
-skip_text(blitList * const blitListP) {
+skipText(blitList * const blitListP) {
 
     skip(readByte());
 
@@ -3436,7 +3556,7 @@ skip_text(blitList * const blitListP) {
 
 
 static int
-abs_value(int const x) {
+absValue(int const x) {
     if (x < 0)
         return -x;
     else
@@ -3446,18 +3566,18 @@ abs_value(int const x) {
 
 
 static struct font*
-get_font(int const font,
-         int const size,
-         int const style) {
+getFont(int const font,
+        int const size,
+        int const style) {
 
     int closeness, bestcloseness;
     struct fontinfo* fi, *best;
 
     best = 0;
     for (fi = fontlist; fi; fi = fi->next) {
-        closeness = abs_value(fi->font - font) * 10000 +
-            abs_value(fi->size - size) * 100 +
-            abs_value(fi->style - style);
+        closeness = absValue(fi->font - font) * 10000 +
+            absValue(fi->size - size) * 100 +
+            absValue(fi->style - style);
         if (!best || closeness < bestcloseness) {
             best = fi;
             bestcloseness = closeness;
@@ -3511,9 +3631,9 @@ rotate(int * const x,
 
 
 static void
-do_ps_text(struct canvas * const canvasP,
-           Word            const tx,
-           Word            const ty) {
+doPsText(struct canvas * const canvasP,
+         Word            const tx,
+         Word            const ty) {
 
     int len, width, i, w, h, x, y, rx, ry, o;
     Byte str[256], ch;
@@ -3563,7 +3683,7 @@ do_ps_text(struct canvas * const canvasP,
                 if ((rx >= picFrame.left) && (rx < picFrame.right) &&
                     (ry >= picFrame.top) && (ry < picFrame.bottom))
                 {
-                    o = PIXEL_INDEX(rx, ry);
+                    o = pixelIndex(picFrame, rx, ry);
                     if (glyph->bmap[h * glyph->width + w]) {
                         canvasP->planes.red[o] = foreground.red;
                         canvasP->planes.grn[o] = foreground.grn;
@@ -3580,19 +3700,19 @@ do_ps_text(struct canvas * const canvasP,
 
 
 static void
-do_text(struct canvas *  const canvasP,
-        blitList *       const blitListP,
-        Word             const startx,
-        Word             const starty) {
+doText(struct canvas *  const canvasP,
+       blitList *       const blitListP,
+       Word             const startx,
+       Word             const starty) {
 
     if (blitListP)
-        skip_text(blitListP);
+        skipText(blitListP);
     else {
-        if (!(tfont = get_font(text_font, text_size, text_face)))
+        if (!(tfont = getFont(text_font, text_size, text_face)))
             tfont = pbm_defaultfont("bdf");
 
         if (ps_text)
-            do_ps_text(canvasP, startx, starty);
+            doPsText(canvasP, startx, starty);
         else {
             int len;
             Word x, y;
@@ -3612,8 +3732,8 @@ do_text(struct canvas *  const canvasP,
                             struct RGBColor * const colorP =
                                 glyph->bmap[h * glyph->width + w] ?
                                 &black : &white;
-                            draw_pixel(canvasP,
-                                       x + w + glyph->x, dy, colorP, text_trf);
+                            drawPixel(canvasP,
+                                      x + w + glyph->x, dy, colorP, text_trf);
                         }
                     }
                     x += glyph->xadd;
@@ -3638,7 +3758,7 @@ LongText(struct canvas * const canvasP,
 
     readPoint(&p);
 
-    do_text(canvasP, blitListP, p.x, p.y);
+    doText(canvasP, blitListP, p.x, p.y);
 }
 
 
@@ -3652,7 +3772,7 @@ DHText(struct canvas * const canvasP,
 
     current.x += readByte();
 
-    do_text(canvasP, blitListP, current.x, current.y);
+    doText(canvasP, blitListP, current.x, current.y);
 }
 
 
@@ -3666,7 +3786,7 @@ DVText(struct canvas * const canvasP,
 
     current.y += readByte();
 
-    do_text(canvasP, blitListP, current.x, current.y);
+    doText(canvasP, blitListP, current.x, current.y);
 }
 
 
@@ -3688,7 +3808,7 @@ DHDVText(struct canvas * const canvasP,
     current.x += dh;
     current.y += dv;
 
-    do_text(canvasP, blitListP, current.x, current.y);
+    doText(canvasP, blitListP, current.x, current.y);
 }
 
 
@@ -3779,11 +3899,11 @@ DirectBitsRgn(struct canvas * const canvasP,
 
 
 static void
-do_pixmap(struct canvas * const canvasP,
-          blitList *      const blitListP,
-          int             const version,
-          Word            const rowBytes,
-          int             const is_region) {
+doPixmap(struct canvas * const canvasP,
+         blitList *      const blitListP,
+         int             const version,
+         Word            const rowBytes,
+         int             const is_region) {
 /*----------------------------------------------------------------------------
    Do a paletted image.
 -----------------------------------------------------------------------------*/
@@ -3835,12 +3955,12 @@ do_pixmap(struct canvas * const canvasP,
 
 
 static void
-do_bitmap(FILE *          const ifP,
-          struct canvas * const canvasP,
-          blitList *      const blitListP,
-          int             const version,
-          int             const rowBytes,
-          int             const is_region) {
+doBitmap(FILE *          const ifP,
+         struct canvas * const canvasP,
+         blitList *      const blitListP,
+         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.
 
@@ -3896,9 +4016,9 @@ BitsRect(struct canvas * const canvasP,
     interpretRowBytesWord(rowBytesWord, &pixMap, &rowBytes);
 
     if (pixMap)
-        do_pixmap(canvasP, blitListP, version, rowBytes, 0);
+        doPixmap(canvasP, blitListP, version, rowBytes, 0);
     else
-        do_bitmap(ifp, canvasP, blitListP, version, rowBytes, 0);
+        doBitmap(ifp, canvasP, blitListP, version, rowBytes, 0);
 }
 
 
@@ -3920,9 +4040,9 @@ BitsRegion(struct canvas * const canvasP,
     interpretRowBytesWord(rowBytesWord, &pixMap, &rowBytes);
 
     if (pixMap)
-        do_pixmap(canvasP, blitListP, version, rowBytes, 1);
+        doPixmap(canvasP, blitListP, version, rowBytes, 1);
     else
-        do_bitmap(ifp, canvasP, blitListP, version, rowBytes, 1);
+        doBitmap(ifp, canvasP, blitListP, version, rowBytes, 1);
 }
 
 
@@ -4243,7 +4363,7 @@ interpretPict(FILE * const ofP) {
     if (verbose)
         pm_message("PICT version %u", version);
 
-    while((opcode = get_op(version)) != 0xff)
+    while((opcode = nextOp(version)) != 0xff)
         processOpcode(opcode, &canvas, fullres ? &blitList : NULL, version);
 
     if (fullres) {
@@ -4335,3 +4455,6 @@ main(int argc, char * argv[]) {
 
     return 0;
 }
+
+
+
diff --git a/converter/ppm/ppmtompeg/opts.c b/converter/ppm/ppmtompeg/opts.c
index c6761968..6f5f9816 100644
--- a/converter/ppm/ppmtompeg/opts.c
+++ b/converter/ppm/ppmtompeg/opts.c
@@ -1,12 +1,12 @@
 /*===========================================================================*
- * opts.c								     *
- *									     *
+ * opts.c                                                                    *
+ *                                                                           *
  *      Special C code to handle TUNEing options                             *
- *									     *
- * EXPORTED PROCEDURES:							     *
+ *                                                                           *
+ * EXPORTED PROCEDURES:                                                      *
  *      Tune_Init                                                            *
  *      CollectQuantStats                                                    *
- *									     *
+ *                                                                           *
  *===========================================================================*/
 
 
@@ -95,9 +95,9 @@ boolean BSkipBlocks = TRUE;
  *
  * SkipSpacesTabs
  *
- *	skip all spaces and tabs
+ *      skip all spaces and tabs
  *
- * RETURNS:	point to next character not a space or tab
+ * RETURNS:     point to next character not a space or tab
  *
  * SIDE EFFECTS:    none
  *
@@ -120,7 +120,7 @@ SkipSpacesTabs(const char * const start) {
  *
  *     Setup variables to collect statistics on quantization values
  *
- * RETURNS:	nothing
+ * RETURNS:     nothing
  *
  * SIDE EFFECTS:    sets collect_quant and collect_quant_fp
  *
@@ -164,7 +164,7 @@ SetupCollectQuantStats(const char * const charPtr)
  *
  *     Do a transform on small lum values
  *
- * RETURNS:	nothing
+ * RETURNS:     nothing
  *
  * SIDE EFFECTS:    sets kill_dim, kill_dim_break, kill_dim_end
  *
@@ -176,11 +176,11 @@ SetupKillDimAreas(const char * const charPtr)
 
   kill_dim = TRUE;
   items_scanned = sscanf(charPtr, "%d %d %f",
-			 &kill_dim_break, &kill_dim_end, &kill_dim_slope);
+                         &kill_dim_break, &kill_dim_end, &kill_dim_slope);
   if (items_scanned != 3) {
     kill_dim_slope = 0.25;
     items_scanned = sscanf(charPtr, "%d %d",
-			   &kill_dim_break, &kill_dim_end);
+                           &kill_dim_break, &kill_dim_end);
     if (items_scanned != 2) {
       /* Use defaults */
       kill_dim_break = 20;
@@ -206,7 +206,7 @@ SetupKillDimAreas(const char * const charPtr)
  *
  *     Setup encoder to squash small changes in Y or Cr/Cb values
  *
- * RETURNS:	nothing
+ * RETURNS:     nothing
  *
  * SIDE EFFECTS:    sets squash_max_differences SquashMaxLum SquashMaxChr
  *
@@ -229,7 +229,7 @@ SetupSquashSmall(const char * const charPtr)
  *
  *     Setup encoder to use DCT for rate-distortion estimat ein Psearches
  *
- * RETURNS:	nothing
+ * RETURNS:     nothing
  *
  * SIDE EFFECTS:    sets SearchCompareMode and
  *                        can change LocalDCTRateScale, LocalDCTDistortScale
@@ -260,7 +260,7 @@ SetupLocalDCT(const char * const charPtr)
  *
  *     Setup encoder to find distribution for I-frames, and use for -snr
  *
- * RETURNS:	nothing
+ * RETURNS:     nothing
  *
  * SIDE EFFECTS:    sets DoLaplace, L1, L2, and Lambdas
  *
@@ -365,10 +365,10 @@ CalcLambdas(void) {
  *
  * Mpost_UnQuantZigBlockLaplace
  *
- *	unquantize and zig-zag (decode) a single block, using the distrib to get vals
+ *      unquantize and zig-zag (decode) a single block, using the distrib to get vals
  *      Iblocks only now
  *
- * RETURNS:	nothing
+ * RETURNS:     nothing
  *
  * SIDE EFFECTS:    none
  *
@@ -381,9 +381,9 @@ Mpost_UnQuantZigBlockLaplace(in, out, qscale, iblock)
     boolean iblock;
 {
     register int index;
-    int	    position;
-    register int	    qentry;
-    int	    level, coeff;
+    int     position;
+    register int            qentry;
+    int     level, coeff;
     double low, high;
     double mid,lam;
 
@@ -395,8 +395,8 @@ Mpost_UnQuantZigBlockLaplace(in, out, qscale, iblock)
       level = in[index];
 
       if (level == 0) {
-	((int16 *)out)[position] = 0;
-	continue;
+        ((int16 *)out)[position] = 0;
+        continue;
       }
       qentry = qtable[position] * qscale;
       coeff = (level*qentry)/8;
@@ -406,19 +406,19 @@ Mpost_UnQuantZigBlockLaplace(in, out, qscale, iblock)
       mid = (1.0/lam) * log(0.5*(exp(-lam*low)+exp(-lam*high)));
       mid = ABS(mid);
       if (mid - floor(mid) > .4999) {
-	mid = ceil(mid);
+        mid = ceil(mid);
       } else {
-	mid = floor(mid);
+        mid = floor(mid);
       }
       if (level<0) {mid = -mid;}
 /*printf("(%2.1lf-%2.1lf): old: %d vs %d\n",low,high,coeff,(int) mid);*/
       coeff = mid;
       if ( (coeff & 1) == 0 ) {
-	if ( coeff < 0 ) {
-	  coeff++;
-	} else if ( coeff > 0 ) {
-	  coeff--;
-	}
+        if ( coeff < 0 ) {
+          coeff++;
+        } else if ( coeff > 0 ) {
+          coeff--;
+        }
       }
       ((int16 *)out)[position] = coeff;
     }
@@ -449,7 +449,7 @@ mse(Block blk1, Block blk2)
  *
  *     Do any setup needed before coding stream
  *
- * RETURNS:	nothing
+ * RETURNS:     nothing
  *
  * SIDE EFFECTS:  varies
  *
@@ -473,7 +473,7 @@ void Tune_Init()
     for (i=0; i<64; i++)
       fprintf(collect_quant_fp, " %d", niqtable[i]);
     fprintf(collect_quant_fp, "\n# %d %d %d\n\n",
-	    GetIQScale(), GetPQScale(), GetBQScale());
+            GetIQScale(), GetPQScale(), GetBQScale());
 
   }
 
@@ -495,7 +495,7 @@ void Tune_Init()
  *
  *     Handle the strings following TUNE
  *
- * RETURNS:	nothing
+ * RETURNS:     nothing
  *
  * SIDE EFFECTS:  varies
  *
diff --git a/converter/ppm/ppmtompeg/specifics.c b/converter/ppm/ppmtompeg/specifics.c
index a8a48af3..aa3d7b18 100644
--- a/converter/ppm/ppmtompeg/specifics.c
+++ b/converter/ppm/ppmtompeg/specifics.c
@@ -67,7 +67,7 @@ void Parse_Specifics_File_v1 (FILE *fp);
 void Parse_Specifics_File_v2 (FILE *fp);
 FrameSpecList *MakeFslEntry (void);
 void AddSlc (FrameSpecList *c,int snum, int qs);
-Block_Specifics *AddBs (FrameSpecList *c,int bnum, 
+Block_Specifics *AddBs (FrameSpecList *c,int bnum,
 				    boolean rel, int qs);
 FrameSpecList *MakeFslEntry (void);
 #define my_upper(c) (((c>='a') && (c<='z')) ? (c-'a'+'A') : c)
@@ -144,7 +144,7 @@ static char version = -1;
  *   Cpp's and reads in the specifics file.  Creates fsl data structure.
  *
  *   Returns: nothing
- * 
+ *
  *   Modifies: fsl, file specificsFile".cpp"
  *
  *================================================================
@@ -153,7 +153,7 @@ void
 Specifics_Init() {
 
     FILE *specificsFP;
-  
+
     {
         const char * command;
         pm_asprintf(&command, "rm -f %s.cpp", specificsFile);
@@ -244,7 +244,7 @@ FILE *fp;
       fprintf(stderr, "Specifics file: What? *%s*\n", line);
       break;
     }}
-  
+
 }
 
 /* Version 1 */
@@ -253,7 +253,7 @@ FILE *fp;
 {
   char line[1024],*lp;
   FrameSpecList *current, *new;
-  char typ; 
+  char typ;
   int fnum,snum, bnum, qs, newqs;
 
   fsl = MakeFslEntry();
@@ -301,7 +301,7 @@ FILE *fp;
       fprintf(stderr," What? *%s*\n", line);
       break;
     }}
-  
+
 }
 
 
@@ -382,7 +382,7 @@ Parse_Specifics_File_v2(FILE * const fP) {
                 } else {
                     numScanned =
                         2 + sscanf(lp, "%s %d %d %d %d",
-                                   kind, &fx, &fy, &sx, &sy); 
+                                   kind, &fx, &fy, &sx, &sy);
                 }
 
                 qs = newqs;
@@ -573,7 +573,7 @@ int start_qs;
   FrameSpecList *tmp;
   boolean found_it;
   static int leftovers = 0;  /* Used in case of forced movement into 1..31 range */
-  
+
   *info = (BlockMV * )NULL;
   if (last == (FrameSpecList *) NULL){
     /* No cache, try to find number fn */
@@ -590,7 +590,7 @@ int start_qs;
   } else {
     if (last->framenum != fn) { /* cache miss! */
       /* first check if it is next */
-      if ((last->next != (FrameSpecList *) NULL) && 
+      if ((last->next != (FrameSpecList *) NULL) &&
 	  (last->next->framenum == fn)) {
 	last = last->next;
       } else {
@@ -617,13 +617,13 @@ int start_qs;
     fprintf(stderr, "PROGRAMMER ERROR: last has wrong number!\n");
     return -1; /* no data on it */
   }
-  
+
   switch(typ) {
   case 0: /* Frame: num is ignored */
     leftovers = 0;
 #ifdef BLEAH
     printf("QSchange frame %d to %d\n", fn, last->qscale);
-#endif 
+#endif
     return last->qscale;
     break;
 
@@ -683,8 +683,8 @@ int start_qs;
   /* no luck */
   return -1;
 }
-     
-    
+
+
 /*================================================================
  *
  *  SpecTypeLookup
diff --git a/converter/ppm/xim.h b/converter/ppm/xim.h
index d208e78f..116312bb 100644
--- a/converter/ppm/xim.h
+++ b/converter/ppm/xim.h
@@ -63,9 +63,9 @@ typedef struct XimImage {
     short tpics, npics;    /* number of images, total & left in file */
     short ncolors;         /*   "    "  colors in the color table */
     Color* colors;         /* colortable, one byte per r/g/b & pixel */
-    const char* author;    /* author credit, copyright, etc */
-    const char* date;      /* date image was made, grabbed, etc. */
-    const char* program;   /* program used to make this */
+    const char* author;         /* author credit, copyright, etc */
+    const char* date;           /* date image was made, grabbed, etc. */
+    const char* program;        /* program used to make this */
     short ncomments;       /* number of comments strings */
     char** comments;      /* pointers to null terminated strings */
     char* offset;         /* original offset in machine memory */
diff --git a/converter/ppm/ximtoppm.c b/converter/ppm/ximtoppm.c
index ffa28d7c..d844031c 100644
--- a/converter/ppm/ximtoppm.c
+++ b/converter/ppm/ximtoppm.c
@@ -22,7 +22,9 @@
 #include "shhopt.h"
 #include "nstring.h"
 
-struct cmdlineInfo {
+
+
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -34,8 +36,8 @@ struct cmdlineInfo {
 
 
 static void
-parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo *cmdlineP) {
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo *cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that many of the strings that this function returns in the
    *cmdlineP structure are actually in the supplied argv array.  And
@@ -57,7 +59,7 @@ parseCommandLine(int argc, char ** argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char**)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and all of *cmdlineP. */
 
     if (!alphaoutSpec)
@@ -100,6 +102,11 @@ ReadXimHeader(FILE *     const in_fp,
         pm_message("ReadXimHeader: unable to read file header" );
         return(0);
     }
+    /* Force broken ASCIIZ strings to at least be valid ASCIIZ */
+    a_head.author [sizeof(a_head.author)  - 1] = '\0';
+    a_head.date   [sizeof(a_head.date)    - 1] = '\0';
+    a_head.program[sizeof(a_head.program) - 1] = '\0';
+
     if (atoi(a_head.header_size) != sizeof(ImageHeader)) {
         pm_message("ReadXimHeader: header size mismatch" );
         return(0);
@@ -113,13 +120,15 @@ ReadXimHeader(FILE *     const in_fp,
     header->ncolors = atoi(a_head.num_colors);
     header->nchannels = atoi(a_head.num_channels);
     header->bytes_per_line = atoi(a_head.bytes_per_line);
-/*    header->npics = atoi(a_head.num_pictures);
-*/
+#if 0
+    header->npics = atoi(a_head.num_pictures);
+#endif
     header->bits_channel = atoi(a_head.bits_per_channel);
     header->alpha_flag = atoi(a_head.alpha_channel);
     pm_asprintf(&header->author,  a_head.author);
     pm_asprintf(&header->date,    a_head.date);
     pm_asprintf(&header->program, a_head.program);
+
     /* Do double checking for backwards compatibility */
     if (header->npics == 0)
         header->npics = 1;
@@ -188,7 +197,8 @@ ReadImageChannel(FILE *         const infp,
         }
         /* return to the beginning of the next image's buffer */
         if (fseek(infp, marker, 0) == -1) {
-            pm_message("ReadImageChannel: can't fseek to location in image buffer" );
+            pm_message("ReadImageChannel: can't fseek to location "
+                       "in image buffer");
             return(0);
         }
         free((char *)line);
@@ -297,28 +307,26 @@ ReadXimImage(FILE *     const in_fp,
 ***********************************************************************/
 
 static int
-ReadXim(in_fp, xim)
-    FILE *in_fp;
-    XimImage *xim;
-{
+ReadXim(FILE *     const in_fp,
+        XimImage * const xim) {
+
     if (!ReadXimHeader(in_fp, xim)) {
         pm_message("can't read xim header" );
-    return(0);
-    }
-    if (!ReadXimImage(in_fp, xim)) {
+        return 0;
+    } else if (!ReadXimImage(in_fp, xim)) {
         pm_message("can't read xim data" );
-    return(0);
-    }
-    return(1);
+        return 0;
+    } else
+        return 1;
 }
 
 
 
 int
-main(int argc,
-     char *argv[]) {
+main(int          argc,
+     const char **argv) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     FILE *ifP, *imageout_file, *alpha_file;
     XimImage xim;
     pixel *pixelrow, colormap[256];
@@ -330,7 +338,7 @@ main(int argc,
     pixval maxval;
     bool success;
 
-    ppm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
diff --git a/converter/ppm/xpmtoppm.c b/converter/ppm/xpmtoppm.c
index 0c9abcc0..c97b9fdc 100644
--- a/converter/ppm/xpmtoppm.c
+++ b/converter/ppm/xpmtoppm.c
@@ -606,7 +606,7 @@ readXpm3Header(FILE *             const ifP,
                ColorNameHash **   const colorNameHashPP) {
 /*----------------------------------------------------------------------------
   Read the header of the XPM file on stream *ifP.  Assume the
-  getLine() stream is presently positioned to the beginning of the
+  getLine() stream is currently positioned to the beginning of the
   file and it is a Version 3 XPM file.  Leave the stream positioned
   after the header.
 
@@ -721,7 +721,7 @@ readXpm1Header(FILE *           const ifP,
                ColorNameHash ** const colorNameHashPP) {
 /*----------------------------------------------------------------------------
   Read the header of the XPM file on stream *ifP.  Assume the
-  getLine() stream is presently positioned to the beginning of the
+  getLine() stream is currently positioned to the beginning of the
   file and it is a Version 1 XPM file.  Leave the stream positioned
   after the header.
 
diff --git a/doc/HISTORY b/doc/HISTORY
index 2c843f43..9d576841 100644
--- a/doc/HISTORY
+++ b/doc/HISTORY
@@ -4,7 +4,21 @@ Netpbm.
 CHANGE HISTORY 
 --------------
 
-20.06.28 BJH  Release 10.90.05
+20.06.28 BJH  Release 10.91.00
+
+              pamstretch-gen: Add -quiet (supposedly added in 10.86, but never
+              worked).
+
+              pamstereogram: Add -tileable.  Thanks Scott Pakin.
+
+              pcdovtoppm: implement -version, -plain, and -quiet.
+
+              pcdovtoppm: more secure temporary file handling.
+
+              pcdovtoppm: Improve the way it fails when 'hpcdtoppm' fails.
+
+              anytopnm, pnmmargin: Fail properly when unable to create
+              temporary file.  Broken in Netpbm 10.75 (June 2016).
 
               winicontoppm: Fix undefined behavior for various invalid input.
               Always broken.  Winicontoppm was new in Netpbm 9.3 (June 2000).
@@ -13,27 +27,21 @@ CHANGE HISTORY
               image.  Always broken.  Winicontoppm was new in Netpbm 9.3 (June
               2000).
 
-20.06.10 BJH  Release 10.90.04
-
               pjtoppm: Handle input stream with no transmission mode command.
               Always broken.  Pjtoppm was in primordial Netpbm (1991).
 
-              cameratopam: Fix buffer overrun.  Always present. (cameratopam
-              was new in Netpbm 10.28 (June 2005)).
-
-              ppmtompeg: Fix buffer overruns with very long names in input
-              parameter files.  Always broken.  Ppmtompeg was new in
-              Netpbm 8.4 (April 2000).
+              cameratopam: Handle I/O error on input file.  Always broken.
+              Cameratopam was new to Netpbm in Netpbm 10.25 (June 2005).
 
-              ximtoppm: Fix possible program crash due to invalid memory
-              reference.  Always broken.  ximtoppm was in primordial Netpbm,
-              ca 1989.
+              xbmtopbm: Recognize "unsigned short" as an extension of
+              XBM X10 format.
 
               pjtoppm: Fix handling of input with width unspecified or not
               positive.  Always broken.  (Pjtoppm was in primordial Netpbm, ca
               1991).
 
-20.05.29 BJH  Release 10.90.03
+              winicontopam: Fix crash with PNG icon.  Always broken.
+              Winicontopam was new in Netpbm 10.63 (June 2013).
 
               picttoppm: Fix bug with an input file that specifies a clip
               region (ClipRgn opcode) that is not contained within the
@@ -44,16 +52,33 @@ CHANGE HISTORY
               scaled.  Broken in Netpbm 10.34 (June 2006) or 10.35 (August
               2006).
 
-20.05.06 BJH  Release 10.90.02
-
               pbmtonokia: Fix incorrect output with -txt option.
 
               pbmtonokia: Fix incorrect output with newer compiler.
 
-20.04.20 BJH  Release 10.90.01
-
               pnmtorle: Fix incorrect command and filename in header.
-              Brokne in Netpbm 10.88 (September 2019).
+              Broken in Netpbm 10.88 (September 2019).
+
+              cameratopam: Fix buffer overrun.  Always present. (cameratopam
+              was new in Netpbm 10.28 (June 2005)).
+
+              cameratopam: Fix undefined behavior using 'swab' to swap bytes
+              in place.  Always present. (cameratopam was new in Netpbm 10.28
+              (June 2005)).
+
+              ppmtompeg: Fix buffer overruns with very long names in input
+              parameter files.  Always broken.  Ppmtompeg was new in
+              Netpbm 8.4 (April 2000).
+
+              ximtoppm: Fix possible program crash due to invalid memory
+              reference.  Always broken.  ximtoppm was in primordial Netpbm,
+              ca 1989.
+
+              pcdovtoppm: Fix bug: accepts anything starting with -s
+              as equivalent to -s.
+
+              pcdovtoppm: properly selects Bash as interpreter.  Broken in
+              Netpbm 9.9 (March 2001).
 
 20.03.26 BJH  Release 10.90.00
 
diff --git a/editor/pamflip/pamflip.c b/editor/pamflip/pamflip.c
index bc752208..d3aa76df 100644
--- a/editor/pamflip/pamflip.c
+++ b/editor/pamflip/pamflip.c
@@ -1007,7 +1007,7 @@ stitchCellsToOutput(outputMap *  const outputMapP,
                 outCol += outCellPamP->width;
             }
 
-            assert(outCol = outpamP->width);
+            assert(outCol == outpamP->width);
 
             pnm_writepamrow(outpamP, tupleRow);
         }
diff --git a/editor/pamstretch-gen b/editor/pamstretch-gen
index fec4469c..ee04821a 100755
--- a/editor/pamstretch-gen
+++ b/editor/pamstretch-gen
@@ -24,10 +24,6 @@ while true ; do
         shift
         ;;
         -q|-qu|-qui|-quie|-quiet|--q|--qu|--qui|--quie|--quiet )
-        quietopt="-plain"
-        shift
-        ;;
-        -q|-qu|-qui|-quie|-quiet|--q|--qu|--qui|--quie|--quiet )
         quietopt="-quiet"
         shift
         ;;
@@ -80,7 +76,7 @@ esac
 # in some exceptional cases adjustment is necessary because of
 # "-dropedge".
 
-report=$(pamscale -reportonly $1 $tempfile)
+report=$(pamscale $quietopt -reportonly $1 $tempfile)
 if [ $? -ne 0 ]; then
   echo "pamstretch-gen: pamscale -reportonly $1 (file) failed" 1>&2
   exit 1
diff --git a/editor/pnmcrop.c b/editor/pnmcrop.c
index 5e74190f..f07340eb 100644
--- a/editor/pnmcrop.c
+++ b/editor/pnmcrop.c
@@ -1264,9 +1264,9 @@ cropOneImage(struct CmdlineInfo const cmdline,
              FILE *             const bdfP,
              FILE *             const ofP) {
 /*----------------------------------------------------------------------------
-   Crop the image to which the stream *ifP is presently positioned
+   Crop the image to which the stream *ifP is currently positioned
    and write the results to *ofP.  If bdfP is non-null, use the image
-   to which stream *bdfP is presently positioned as the borderfile
+   to which stream *bdfP is currently positioned as the borderfile
    (the file that tells us where the existing borders are in the input
    image).  Leave *ifP and *bdfP positioned after the image.
 
diff --git a/editor/pnmmargin b/editor/pnmmargin
index 9dbe24b7..1b5370be 100755
--- a/editor/pnmmargin
+++ b/editor/pnmmargin
@@ -12,7 +12,7 @@
 # implied warranty.
 
 tempdir=$(mktemp -d "${TMPDIR:-/tmp}/netpbm.XXXXXXXX") ||
-    ( echo "Could not create temporary file. Exiting." 1>&2; exit 1; ) 
+    { echo "Could not create temporary file. Exiting." 1>&2; exit 1; }
 trap 'rm -rf $tempdir' 0 1 3 15
 
 tmp1=$tempdir/pnmm1
diff --git a/editor/pnmstitch.c b/editor/pnmstitch.c
index 4c4c708a..b27445b0 100644
--- a/editor/pnmstitch.c
+++ b/editor/pnmstitch.c
@@ -1322,10 +1322,10 @@ Output OutputMethods[] = {
 /* Stitcher Methods */
 
 /* These names are for the 8 parameters of a stitch, in any of the 3
-   methods this program presently implements.  Each is a subscript in
+   methods this program currently implements.  Each is a subscript in
    the parms[] array for the Stitcher object that represents a linear
-   stitching method.  
-   
+   stitching method.
+
    There are also other sets of names for the 8 parameters, such as
    Rotate_a.  I don't know why.  Maybe historical.
 */
diff --git a/generator/pamstereogram.c b/generator/pamstereogram.c
index 6e5f5ce0..9b861b51 100644
--- a/generator/pamstereogram.c
+++ b/generator/pamstereogram.c
@@ -16,7 +16,7 @@
  *
  * ----------------------------------------------------------------------
  *
- * Copyright (C) 2006-2015 Scott Pakin <scott+pbm@pakin.org>
+ * Copyright (C) 2006-2020 Scott Pakin <scott+pbm@pakin.org>
  *
  * All rights reserved.
  *
@@ -94,6 +94,7 @@ struct cmdlineInfo {
     enum outputType outputType;  /* Type of output file */
     unsigned int xbegin;         /* -xbegin option */
     unsigned int xbeginSpec;     /* -xbegin option count */
+    unsigned int tileable;       /* -tileable option */
 };
 
 
@@ -207,6 +208,8 @@ parseCommandLine(int                  argc,
             &planesSpec,              0);
     OPTENT3(0, "xbegin",          OPT_UINT,   &cmdlineP->xbegin,
             &cmdlineP->xbeginSpec,    0);
+    OPTENT3(0, "tileable",        OPT_FLAG,   NULL,
+            (unsigned int *)&cmdlineP->tileable,  0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
@@ -291,6 +294,11 @@ parseCommandLine(int                  argc,
     if (cmdlineP->makemask && cmdlineP->patfile)
         pm_error("You may not specify both -makemask and -patfile");
 
+    if (cmdlineP->tileable && cmdlineP->xbeginSpec)
+        pm_error("You may not specify both -tileable and -xbegin");
+    if (cmdlineP->tileable && !cmdlineP->patfile)
+        pm_error("-tileable is valid only with -patfile");
+
     if (cmdlineP->patfile && blackandwhite)
         pm_error("-blackandwhite is not valid with -patfile");
     if (cmdlineP->patfile && grayscale)
@@ -844,11 +852,12 @@ makeStereoRow(const struct pam * const inPamP,
               unsigned int       const dpi,
               unsigned int       const optWidth,
               unsigned int       const smoothing) {
+/*----------------------------------------------------------------------------
+  Given a row of the depth map inRow[], compute the sameL and sameR arrays,
+  which indicate for each pixel which pixel to its left and right it should be
+  colored the same as.
+-----------------------------------------------------------------------------*/
 
-/* Given a row of the depth map, compute the sameL and sameR arrays,
- * which indicate for each pixel which pixel to its left and right it
- * should be colored the same as.
- */
 #define Z(X) (inRow[X][0]/(double)inPamP->maxval)
 
     unsigned int col;
@@ -865,7 +874,7 @@ makeStereoRow(const struct pam * const inPamP,
 
         if (left >= 0 && right < inPamP->width) {
             bool isVisible;
-        
+
             if (sameL[right] != right) {
                 /* Right point already linked */
                 if (sameL[right] < left) {
@@ -1114,12 +1123,15 @@ static void
 makeImageRowMts(outGenerator *       const outGenP,
                 unsigned int         const row,
                 const unsigned int * const same,
-                unsigned int *       const sameFp,
+                unsigned int *       const colNumBuffer,
                 tuple *              const rowBuffer,
                 const tuple *        const outRow) {
 /*----------------------------------------------------------------------------
   Make a row of a mapped-texture stereogram.
 -----------------------------------------------------------------------------*/
+    unsigned int * const sameFp = colNumBuffer;
+        /* Fixed point of same[] */
+
     unsigned int * tuplesInCol;
         /* tuplesInCol[C] is the number of tuples averaged together to make
            Column C.
@@ -1165,7 +1177,6 @@ makeImageRowMts(outGenerator *       const outGenP,
 static void
 makeImageRow(outGenerator *       const outGenP,
              unsigned int         const row,
-             unsigned int         const optWidth,
              unsigned int         const xbegin,
              const unsigned int * const sameL,
              const unsigned int * const sameR,
@@ -1243,6 +1254,165 @@ invertHeightRow(const struct pam * const heightPamP,
 
 
 static void
+makeOneImageRow(unsigned int         const row,
+                outGenerator *       const outputGeneratorP,
+                bool                 const makeMask,
+                const unsigned int * const sameL,
+                const unsigned int * const sameR,
+                unsigned int *       const colNumBuffer,
+                unsigned int         const xbegin,
+                tuple *              const rowBuffer,
+                tuple *              const outRow) {
+
+    if (makeMask)
+        makeMaskRow(&outputGeneratorP->pam, xbegin, sameL, sameR, outRow);
+    else {
+        if (outputGeneratorP->textureP)
+            makeImageRowMts(outputGeneratorP, row, sameR, colNumBuffer,
+                            rowBuffer, outRow);
+        else
+            makeImageRow(outputGeneratorP, row,
+                         xbegin, sameL, sameR, outRow);
+    }
+}
+
+
+
+static void
+constructRowTileable(const struct pam *   const inPamP,
+                     outGenerator *       const outputGeneratorP,
+                     bool                 const makeMask,
+                     const unsigned int * const sameL,
+                     const unsigned int * const sameR,
+                     unsigned int         const row,
+                     tuple *              const outRow,
+                     tuple *              const outRowBuf1,
+                     tuple *              const outRowBuf2,
+                     unsigned int *       const colNumBuf2) {
+
+    tuple * const outRowMax = outRowBuf1;
+
+    unsigned int col;
+
+    /* Create two rows with extreme xbegin values and blend the second
+       into the first.  outRow[] serves as both the buffer for the xbegin=0
+       version and the merged output.  outRowMax[] is the buffer for the
+       xbegin=maximum case.
+    */
+    makeOneImageRow(row, outputGeneratorP, makeMask, sameL, sameR, colNumBuf2,
+                    0, outRowBuf2, outRow);
+
+    makeOneImageRow(row, outputGeneratorP, makeMask, sameL, sameR, colNumBuf2,
+                    inPamP->width - 1, outRowBuf2, outRowMax);
+
+    for (col = 0; col < inPamP->width; ++col) {
+        unsigned int plane;
+        unsigned int oplane;
+
+        if (outputGeneratorP->pam.have_opacity)
+            oplane = outputGeneratorP->pam.opacity_plane;
+
+        for (plane = 0; plane < outputGeneratorP->pam.color_depth; ++plane) {
+
+            sample samp, sampMax;
+
+            if (outputGeneratorP->pam.have_opacity) {
+                /* If one sample is fully transparent, use the
+                   other sample for both purposes
+                */
+                if (outRow[col][oplane] == 0)
+                    samp = sampMax = outRowMax[col][plane];
+                else if (outRowMax[col][oplane] == 0)
+                    samp = sampMax = outRow[col][plane];
+                else {
+                    samp    = outRow[col][plane];
+                    sampMax = outRowMax[col][plane];
+                }
+            } else {
+                samp    = outRow[col][plane];
+                sampMax = outRowMax[col][plane];
+            }
+
+            outRow[col][plane] =
+                (col*sampMax + (inPamP->width - col - 1)*samp) /
+                (inPamP->width - 1);
+        }
+        if (outputGeneratorP->pam.have_opacity) {
+            sample samp, sampMax;
+
+            /* Take the maximum alpha for partially transparent samples. */
+            samp    = outRow[col][oplane];
+            sampMax = outRowMax[col][oplane];
+            outRow[col][oplane] = MAX(samp, sampMax);
+        }
+    }
+}
+
+
+
+static void
+doRow(const struct pam * const inPamP,
+      outGenerator *     const outputGeneratorP,
+      double             const depthOfField,
+      double             const eyesep,
+      unsigned int       const dpi,
+      bool               const crossEyed,
+      bool               const makeMask,
+      bool               const tileable,
+      unsigned int       const magnifypat,
+      unsigned int       const smoothing,
+      unsigned int       const xbegin,
+      unsigned int       const row,
+      tuple *            const inRow,
+      tuple *            const outRowBuf0,
+      tuple *            const outRowBuf1,
+      tuple *            const outRowBuf2,
+      unsigned int *     const colNumBuf0,
+      unsigned int *     const colNumBuf1,
+      unsigned int *     const colNumBuf2) {
+
+    tuple *        const outRow = outRowBuf0;
+    unsigned int * const sameL  = colNumBuf0;
+        /* sameL[N] is the column number of a pixel to the
+           left forced to have the same color as the one in column N
+        */
+    unsigned int * const sameR = colNumBuf1;
+        /* sameR[N] is the column number of a pixel to the
+           right forced to have the same color as the one in column N
+        */
+
+    pnm_readpamrow(inPamP, inRow);
+
+    if (crossEyed)
+        /* Invert heights for cross-eyed (as opposed to wall-eyed)
+           people.
+        */
+        invertHeightRow(inPamP, inRow);
+
+    /* Determine color constraints. */
+    makeStereoRow(inPamP, inRow, sameL, sameR, depthOfField, eyesep, dpi,
+                  ROUNDU(eyesep * dpi)/(magnifypat * 2),
+                  smoothing);
+
+    /* Construct a single row. */
+    if (tileable) {
+        constructRowTileable(inPamP, outputGeneratorP, makeMask,
+                             sameL, sameR, row, outRow,
+                             outRowBuf1, outRowBuf2, colNumBuf2);
+
+    } else {
+        makeOneImageRow(row, outputGeneratorP, makeMask,
+                        sameL, sameR, colNumBuf2,
+                        xbegin, outRowBuf1, outRow);
+    }
+
+    /* Write the resulting row. */
+    pnm_writepamrow(&outputGeneratorP->pam, outRow);
+}
+
+
+
+static void
 makeImageRows(const struct pam * const inPamP,
               outGenerator *     const outputGeneratorP,
               double             const depthOfField,
@@ -1250,72 +1420,50 @@ makeImageRows(const struct pam * const inPamP,
               unsigned int       const dpi,
               bool               const crossEyed,
               bool               const makeMask,
+              bool               const tileable,
               unsigned int       const magnifypat,
               unsigned int       const smoothing,
               unsigned int       const xbegin) {
 
-    tuple * inRow;     /* One row of pixels read from the height-map file */
-    tuple * outRow;    /* One row of pixels to write to the height-map file */
-    unsigned int * sameR;
-        /* Malloced array: sameR[N] is the column number of a pixel to the
-           right forced to have the same color as the one in column N
-        */
-    unsigned int * sameL;
-        /* Malloced array: sameL[N] is the column number of a pixel to the
-           left forced to have the same color as the one in column N
-        */
-    unsigned int * sameRfp;
-        /* Malloced array: Fixed point of sameR[] */
-    tuple * rowBuffer;     /* Scratch row needed for texture manipulation */
+    tuple * inRow;    /* Buffer for use in reading from the height-map image */
+    tuple * outRowBuf0; /* Buffer for use in generating output rows */
+    tuple * outRowBuf1; /* Buffer for use in generating output rows */
+    tuple * outRowBuf2; /* Buffer for use in generating output rows */
+    unsigned int * colNumBuf0;
+    unsigned int * colNumBuf1;
+    unsigned int * colNumBuf2;
     unsigned int row;      /* Current row in the input and output files */
 
     inRow = pnm_allocpamrow(inPamP);
-    outRow = pnm_allocpamrow(&outputGeneratorP->pam);
-    MALLOCARRAY(sameR, inPamP->width);
-    if (sameR == NULL)
-        pm_error("Unable to allocate space for \"sameR\" array.");
-    MALLOCARRAY(sameL, inPamP->width);
-    if (sameL == NULL)
-        pm_error("Unable to allocate space for \"sameL\" array.");
-
-    MALLOCARRAY(sameRfp, inPamP->width);
-    if (sameRfp == NULL)
-        pm_error("Unable to allocate space for \"sameRfp\" array.");
-    rowBuffer = pnm_allocpamrow(&outputGeneratorP->pam);
+    outRowBuf0 = pnm_allocpamrow(&outputGeneratorP->pam);
+    outRowBuf1 = pnm_allocpamrow(&outputGeneratorP->pam);
+    outRowBuf2 = pnm_allocpamrow(&outputGeneratorP->pam);
+    MALLOCARRAY(colNumBuf0, inPamP->width);
+    if (colNumBuf0 == NULL)
+        pm_error("Unable to allocate space for %u column buffer",
+                 inPamP->width);
+    MALLOCARRAY(colNumBuf1, inPamP->width);
+    if (colNumBuf1 == NULL)
+        pm_error("Unable to allocate space for %u column buffer",
+                 inPamP->width);
+    MALLOCARRAY(colNumBuf2, inPamP->width);
+    if (colNumBuf2 == NULL)
+        pm_error("Unable to allocate space for %u column buffer",
+                 inPamP->width);
 
     for (row = 0; row < inPamP->height; ++row) {
-        pnm_readpamrow(inPamP, inRow);
-        if (crossEyed)
-            /* Invert heights for cross-eyed (as opposed to wall-eyed)
-               people.
-            */
-            invertHeightRow(inPamP, inRow);
-
-        /* Determine color constraints. */
-        makeStereoRow(inPamP, inRow, sameL, sameR, depthOfField, eyesep, dpi,
-                      ROUNDU(eyesep * dpi)/(magnifypat * 2),
-                      smoothing);
-
-        if (makeMask)
-            makeMaskRow(&outputGeneratorP->pam, xbegin, sameL, sameR, outRow);
-        else {
-            if (outputGeneratorP->textureP)
-                makeImageRowMts(outputGeneratorP, row, sameR, sameRfp,
-                                rowBuffer, outRow);
-            else
-                makeImageRow(outputGeneratorP, row,
-                             ROUNDU(eyesep * dpi)/(magnifypat * 2),
-                             xbegin, sameL, sameR, outRow);
-        }
-        /* Write the resulting row. */
-        pnm_writepamrow(&outputGeneratorP->pam, outRow);
+        doRow(inPamP, outputGeneratorP,  depthOfField, eyesep, dpi,
+              crossEyed, makeMask, tileable, magnifypat, smoothing, xbegin,
+              row,
+              inRow, outRowBuf0, outRowBuf1, outRowBuf2,
+              colNumBuf0, colNumBuf1, colNumBuf2);
     }
 
-    pnm_freepamrow(rowBuffer);
-    free(sameRfp);
-    free(sameL);
-    free(sameR);
-    pnm_freepamrow(outRow);
+    free(colNumBuf2);
+    free(colNumBuf1);
+    free(colNumBuf0);
+    pnm_freepamrow(outRowBuf1);
+    pnm_freepamrow(outRowBuf0);
     pnm_freepamrow(inRow);
 }
 
@@ -1361,8 +1509,8 @@ produceStereogram(FILE *             const ifP,
 
     makeImageRows(&inPam, outputGeneratorP,
                   cmdline.depth, cmdline.eyesep, cmdline.dpi,
-                  cmdline.crosseyed, cmdline.makemask, cmdline.magnifypat,
-                  cmdline.smoothing, xbegin);
+                  cmdline.crosseyed, cmdline.makemask, cmdline.tileable,
+                  cmdline.magnifypat, cmdline.smoothing, xbegin);
 
     if (cmdline.guidebottom)
         drawguides(cmdline.guidesize, &outputGeneratorP->pam,
diff --git a/generator/pbmtext.c b/generator/pbmtext.c
index e52a296e..7ea64857 100644
--- a/generator/pbmtext.c
+++ b/generator/pbmtext.c
@@ -30,6 +30,7 @@
 #include "pbm.h"
 #include "pbmfont.h"
 
+
 /* Max length of input text.  Valid for text which is part of the
    command line and also for text fed from standard input.
    Note that newline is counted as a character.
@@ -55,6 +56,7 @@ struct CmdlineInfo {
     unsigned int nomargins;  /* -nomargins option specified  */
     unsigned int dryrun;     /* -dry-run option specified */
     unsigned int textdump;   /* -text-dump option specified */
+    unsigned int entirefont; /* -load-entire-font option specified */
     unsigned int verbose;    /* -verbose option specified */
         /* undocumented option */
     unsigned int dumpsheet; /* font data sheet in PBM format for -font */
@@ -133,6 +135,7 @@ parseCommandLine(int argc, const char ** argv,
     OPTENT3(0, "dry-run",    OPT_FLAG,   NULL, &cmdlineP->dryrun,    0);
     OPTENT3(0, "text-dump",  OPT_FLAG,   NULL, &cmdlineP->textdump,  0);
     OPTENT3(0, "dump-sheet", OPT_FLAG,   NULL, &cmdlineP->dumpsheet, 0);
+    OPTENT3(0, "load-entire-font", OPT_FLAG,   NULL, &cmdlineP->entirefont, 0);
 
     /* Set the defaults */
     cmdlineP->font    = NULL;
@@ -166,6 +169,8 @@ parseCommandLine(int argc, const char ** argv,
 
     if (cmdlineP->font != NULL && cmdlineP->builtin != NULL)
         pm_error("You cannot specify both -font and -builtin");
+    else if (cmdlineP->font == NULL && cmdlineP->entirefont)
+        pm_error("You cannot specify -load-entire-font without -font");
 
     if (cmdlineP->textdump) {
         if (cmdlineP->dryrun)
@@ -206,12 +211,10 @@ reportFont(const struct font2 * const fontP) {
 
 
 
-
-
-
 static struct font2 *
-font2FromFile(const char * const fileName,
-              PM_WCHAR     const maxmaxglyph) {
+font2FromFile(const char *               const fileName,
+              PM_WCHAR                   const maxmaxglyph,
+              const struct pm_selector * const selectorP) {
 
     struct font2 * font2P;
 
@@ -224,7 +227,7 @@ font2FromFile(const char * const fileName,
         /* This is the normal program flow */
         pm_setjmpbuf(&jmpbuf);
 
-        font2P = pbm_loadfont2(fileName, maxmaxglyph);
+        font2P = pbm_loadfont2select(fileName, maxmaxglyph, selectorP);
 
         pm_setjmpbuf(NULL);
     } else {
@@ -241,23 +244,176 @@ font2FromFile(const char * const fileName,
 
 
 
+static bool
+codepointIsValid(struct font2 * const fontP,
+                 PM_WCHAR       const codepoint) {
+/*----------------------------------------------------------------------------
+  'codepoint' is a valid entry in the font indicated by 'fontP'.
+-----------------------------------------------------------------------------*/
+    bool retval;
+
+    assert(pm_selector_is_marked(fontP->selectorP, codepoint));
+
+    if (codepoint > fontP->maxglyph || fontP->glyph[codepoint] == NULL)
+        retval = false;
+    else retval = true;
+
+    return (retval);
+
+}
+
+
+
+static const char *
+charDescription(PM_WCHAR const codepoint) {
+/*----------------------------------------------------------------------------
+   Descriptive string for codepoint 'codepoint'.
+
+   Certain codepoints appear frequently in text files and cause problems when
+   missing in the font set, so we give those descriptions.  For other
+   codepoint, we just return a null string.
+-----------------------------------------------------------------------------*/
+
+  const char * name;
+
+  switch (codepoint) {
+  case '\r' : name="carriage return";  break;
+  case '\n' : name="line feed";        break; /* for future use */
+  case '\t' : name="tab";              break; /* for future use */
+  case ' '  : name="space";            break;
+  case 0xFEFF: name="byte order mark"; break;
+  default : name=""; break;
+  }
+
+  return name;
+}
+
+
+
+enum FixMode {SILENT, /* convert silently */
+              WARN,   /* output message to stderr */
+              QUIT    /* abort */ };
+
+
+
+static void
+reportAbsentGlyphs(bool                       const wchar,
+                   struct font2 *             const fontP,
+                   const struct pm_selector * const textSelectorP,
+                   unsigned int *             const missingCharCtP) {
+/*----------------------------------------------------------------------------
+   Compare the glyph entries in *fontP with the requests in *textSelectorP.
+
+   Note that we may need the space character as a substitute for missing
+   glyphs while the input text has no spaces.  In rare cases the font may not
+   have a space character.
+
+   Currently, this program reads the font file only once.  A future version
+   may opt to read it a second time to load the substitute glyph.
+-----------------------------------------------------------------------------*/
+    PM_WCHAR     codepoint;
+    unsigned int missingCharCt;
+
+    for (codepoint = textSelectorP->min, missingCharCt = 0;
+         codepoint <= textSelectorP->max; ++codepoint) {
+
+        if (pm_selector_is_marked(textSelectorP, codepoint) &&
+            !codepointIsValid(fontP, codepoint)) {
+            ++missingCharCt;
+            if (missingCharCt == 1)  { /* initial */
+                pm_message("failed to load glyph data for these code points "
+                           "in input:");
+            }
+
+            pm_message(wchar ? "+%05X %s" : "%02X %s",
+                       (unsigned int) codepoint,
+                       charDescription(codepoint));
+        }
+    }
+
+    *missingCharCtP = missingCharCt;
+}
+
+
+
 static void
-computeFont(struct CmdlineInfo const cmdline,
-            struct font2 **    const fontPP) {
+validateFont(bool                       const wchar,
+             struct font2 *             const fontP,
+             const struct pm_selector * const textSelectorP,
+             enum   FixMode             const fixmode,
+             bool                       const verbose,
+             bool *                     const hasAllCharsP) {
+/*----------------------------------------------------------------------------
+   If any glyphs required by the text indicated by *textSelectorP are missing
+   from font *fontP, issue a warning message or abort the program according to
+   'fixmode'.
+
+   Abort the program if one or more characters are missing and the space
+   character is one of them.
+
+   Return (if we return) as *hasAllCharsP whether the font has all the glyphs.
+-----------------------------------------------------------------------------*/
+    unsigned int missingCharCt;
+
+    assert (textSelectorP != NULL);
+    assert(pm_selector_marked_ct(textSelectorP) >= 0);
+
+    reportAbsentGlyphs(wchar, fontP, textSelectorP, &missingCharCt);
+
+    if (missingCharCt > 0) {
+        if (verbose)
+            pm_message("%u characters absent in font", missingCharCt);
+
+        if (fixmode == QUIT)
+            pm_error("aborting");
+        else if (!codepointIsValid(fontP, L' '))
+            pm_error ("replacement character (space) absent; aborting");
+        else
+            pm_message("undefined code points will be converted to space");
+    }
+
+    *hasAllCharsP = (missingCharCt == 0);
+}
+
 
-    struct font2 * font2P;
 
-    if (cmdline.font)
-        font2P = font2FromFile(cmdline.font,
-                               cmdline.wchar ? PM_FONT2_MAXGLYPH :
-                                               PM_FONT_MAXGLYPH);
-    else if (cmdline.builtin)
+static void
+computeFont(struct CmdlineInfo         const cmdline,
+            struct font2 **            const fontPP,
+            const struct pm_selector * const textSelectorP,
+            enum   FixMode             const fixmode,
+            bool *                     const fontHasAllCharsP) {
+
+    struct font2 *       font2P;
+    struct pm_selector * fontSelectorP;
+
+    if (cmdline.font) {
+        if(cmdline.entirefont)
+            fontSelectorP = NULL;
+        else if(!pm_selector_is_marked(textSelectorP, L' ')) {
+            pm_selector_copy(MAX(textSelectorP->max, L' '),
+                             textSelectorP, &fontSelectorP);
+            pm_selector_mark(fontSelectorP, L' ');
+        } else
+            fontSelectorP = (struct pm_selector *) textSelectorP;
+
+        font2P = font2FromFile(cmdline.font, cmdline.wchar ?
+                               PM_FONT2_MAXGLYPH : PM_FONT_MAXGLYPH,
+                               fontSelectorP);
+    } else if (cmdline.builtin)
         font2P = pbm_defaultfont2(cmdline.builtin);
     else
         font2P = pbm_defaultfont2(cmdline.wchar ? "bdf" : "bdf");
 
-    if (cmdline.verbose)
+    if (cmdline.verbose) {
         reportFont(font2P);
+        pm_message("%u code points found in text",
+                   pm_selector_marked_ct(textSelectorP));
+    }
+
+    validateFont(cmdline.wchar, font2P, textSelectorP, fixmode,
+                 cmdline.verbose,
+                 fontHasAllCharsP);
 
     *fontPP = font2P;
 }
@@ -266,9 +422,6 @@ computeFont(struct CmdlineInfo const cmdline,
 
 struct Text {
     PM_WCHAR **  textArray;  /* malloc'ed */
-        /* This is strictly characters that are in user's font - no control
-           characters, no undefined code points.
-        */
     unsigned int allocatedLineCount;
     unsigned int lineCount;
 };
@@ -309,28 +462,19 @@ freeTextArray(struct Text const text) {
 
 
 
-enum FixMode {SILENT, /* convert silently */
-              WARN,   /* output message to stderr */
-              QUIT    /* abort */ };
-
 
 static void
-fixControlChars(const PM_WCHAR  * const input,
-                struct font2    * const fontP,
-                const PM_WCHAR ** const outputP,
-                enum FixMode      const fixMode) {
+setupSelector(const PM_WCHAR *     const input,
+              const PM_WCHAR **    const outputP,
+              struct pm_selector * const selectorP) {
 /*----------------------------------------------------------------------------
-   Return a translation of input[] that can be rendered as glyphs in
-   the font 'fontP'.  Return it as newly malloced *outputP.
+   Read through input[] and record the codepoints encountered.  Return it as
+   newly malloced *outputP.
 
    Expand tabs to spaces.
 
    Remove any trailing newline.  (But leave intermediate ones as line
    delimiters).
-
-   Depending on value of fixMode, turn anything that isn't a code point
-   in the font to a single space (which isn't guaranteed to be in the
-   font either, of course).
 -----------------------------------------------------------------------------*/
     /* We don't know in advance how big the output will be because of the
        tab expansions.  So we make sure before processing each input
@@ -370,33 +514,19 @@ fixControlChars(const PM_WCHAR  * const input,
             unsigned int const nextTabStop =
                 (outCursor + tabSize) / tabSize * tabSize;
 
-            if (fontP->glyph[L' '] == NULL)
-                pm_error("space character not defined in font");
-
             while (outCursor < nextTabStop)
                 output[outCursor++] = L' ';
-        } else if (currentChar > fontP->maxglyph ||
-                   !fontP->glyph[currentChar]) {
-            if (currentChar > PM_FONT2_MAXGLYPH)
+
+            pm_selector_mark(selectorP, L' ');
+
+        } else 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");
-            else if (fixMode == QUIT)
-                pm_error("code point %X not defined in font",
-                         (unsigned int) currentChar );
-            else {
-                if (fixMode == WARN)
-                    pm_message("converting code point %X to space",
-                               (unsigned int) currentChar );
-                output[outCursor++] = ' ';
-            }
-        } else
+        else {
             output[outCursor++] = input[inCursor];
-
+            pm_selector_mark(selectorP, currentChar);
+        }
         assert(outCursor <= outputSize);
     }
     output[outCursor++] = L'\0';
@@ -437,7 +567,8 @@ getEdges(double               const currentPosition,
     double rightEdge;
 
     if (glyphP == NULL)
-        pm_error("Unrenderable char: %04X", (unsigned int) currentChar);
+        pm_error("encountered unrenderable char: %04X",
+                  (unsigned int) currentChar);
     else {
         leftEdge  =  (int) MIN(currentPosition + glyphP->x, currLeftEdge);
         rightEdge =  MAX(currentPosition + glyphP->x + glyphP->width,
@@ -475,8 +606,8 @@ advancePosition(double               const currentPosition,
             pm_error("Negative -space value too large");
         else
             pm_error("Abnormal horizontal advance value %d "
-                     "for code point 0x%lx.",
-                     glyphP->xadd, (unsigned long int) currentChar);
+                     "for code point +%05X",
+                     glyphP->xadd, (unsigned int) currentChar);
     }
     else if (currentPosition + advance > INT_MAX)
         pm_error("Image is too wide");
@@ -535,8 +666,8 @@ getLineDimensions(PM_WCHAR             const line[],
 
     for (cursor = 0; line[cursor] != L'\0'; ++cursor) {
         PM_WCHAR          const currentChar = line[cursor];
-        unsigned long int const glyphIndex  = (unsigned long int) currentChar;
-        struct glyph *    const glyphP      = fontP->glyph[glyphIndex];
+        unsigned int      const index       = (unsigned int) currentChar;
+        struct glyph *    const glyphP      = fontP->glyph[index];
 
         getEdges(currentPosition, currentChar, glyphP, leftEdge, rightEdge,
                  &leftEdge, &rightEdge);
@@ -593,9 +724,8 @@ getCharsWithinWidth(PM_WCHAR             const line[],
              currentWidth <= targetWidth && line[cursor] != L'\0';
              ++cursor) {
             PM_WCHAR const currentChar = line[cursor];
-            unsigned long int const glyphIndex =
-              (unsigned long int) currentChar;
-            struct glyph * const glyphP = fontP->glyph[glyphIndex];
+            unsigned int const index = (unsigned int) currentChar;
+            struct glyph * const glyphP = fontP->glyph[index];
 
             getEdges(currentPosition, currentChar, glyphP, leftEdge, rightEdge,
                      &leftEdge, &rightEdge);
@@ -694,9 +824,8 @@ insertCharacters(bit **         const bits,
 
         for (cursor = 0; lp.textArray[line][cursor] != '\0'; ++cursor) {
             PM_WCHAR const currentChar = lp.textArray[line][cursor];
-            unsigned long int const glyphIndex =
-                (unsigned long int)currentChar;
-            struct glyph * const glyphP = fontP->glyph[glyphIndex];
+            unsigned int const index = (unsigned int) currentChar;
+            struct glyph * const glyphP = fontP->glyph[index];
             int const toprow =
                 row + fontP->maxheight + fontP->y - glyphP->height - glyphP->y;
                 /* row number in image of top row in glyph */
@@ -943,10 +1072,9 @@ fgetNarrowWideString(PM_WCHAR *    const widestring,
 
 
 static void
-getText(PM_WCHAR       const cmdlineText[],
-        struct font2 * const fontP,
-        struct Text  * const inputTextP,
-        enum FixMode   const fixMode) {
+getText(PM_WCHAR             const cmdlineText[],
+        struct Text *        const inputTextP,
+        struct pm_selector * const selectorP) {
 /*----------------------------------------------------------------------------
    Get as *inputTextP the text to format, given that the text on the
    command line (one word per command line argument, separated by spaces),
@@ -969,8 +1097,8 @@ getText(PM_WCHAR       const cmdlineText[],
         MALLOCARRAY_NOFAIL(inputText.textArray, 1);
         inputText.allocatedLineCount = 1;
         inputText.lineCount = 1;
-        fixControlChars(cmdlineText, fontP,
-                        (const PM_WCHAR**)&inputText.textArray[0], fixMode);
+        setupSelector(cmdlineText, (const PM_WCHAR**) &inputText.textArray[0],
+                      selectorP);
         free((void *) cmdlineText);
     } else {
         /* Read text from stdin. */
@@ -978,7 +1106,7 @@ getText(PM_WCHAR       const cmdlineText[],
         unsigned int const lineBufTerm = LINEBUFSIZE - 1;
 
         unsigned int maxlines;
-            /* Maximum number of lines for which we presently have space in
+            /* Maximum number of lines for which we currently have space in
                the text array
             */
         PM_WCHAR *   buf;
@@ -1021,9 +1149,9 @@ getText(PM_WCHAR       const cmdlineText[],
                         if (textArray == NULL)
                             pm_error("out of memory");
                     }
-                    fixControlChars(buf, fontP,
-                                    (const PM_WCHAR **)&textArray[lineCount],
-                                    fixMode);
+                    setupSelector(buf,
+                                  (const PM_WCHAR **) &textArray[lineCount],
+                                  selectorP);
                     if (textArray[lineCount] == NULL)
                         pm_error("out of memory");
                     ++lineCount;
@@ -1064,6 +1192,33 @@ computeMargins(struct CmdlineInfo const cmdline,
 
 
 static void
+refineText(struct Text        const inputText,
+           struct font2 *     const fontP) {
+/*----------------------------------------------------------------------------
+   Replace missing characters with space
+
+   A future version of this program may provide various alternatives
+   here including simply deleting the offending character, based on a
+   command-line option
+-----------------------------------------------------------------------------*/
+    PM_WCHAR ** const textArray = inputText.textArray;
+
+    unsigned int lineNum;
+
+    for (lineNum = 0; lineNum < inputText.lineCount; ++lineNum) {
+        PM_WCHAR * const line = textArray[lineNum];
+
+        unsigned int cursor;
+
+        for (cursor = 0; line[cursor] != L'\0'; ++cursor)
+            if ( !codepointIsValid(fontP, line[cursor]) )
+                line[cursor] = L' ';
+    }
+}
+
+
+
+static void
 formatText(struct CmdlineInfo const cmdline,
            struct Text        const inputText,
            struct font2 *     const fontP,
@@ -1191,7 +1346,7 @@ renderText(unsigned int   const cols,
                      space, cols, rows, lspace, fixedAdvance);
 
     /* Free all font data */
-    pbm_destroybdffont2(fontP); 
+    pbm_destroybdffont2(fontP);
 
     {
         unsigned int row;
@@ -1224,36 +1379,31 @@ L"M \",/^_[`jpqy| M" };
 
 
 static void
-validateText(const PM_WCHAR ** const textArray,
-             struct font2    * const fontP) {
-/*----------------------------------------------------------------------------
-   Abort the program if there are characters in 'textArray' which cannot be
-   rendered in font *fontP.
------------------------------------------------------------------------------*/
-    const PM_WCHAR * output;
-    unsigned int textRow;
-
-    for (textRow = 0; textRow < 12; ++textRow)
-        fixControlChars(textArray[textRow], fontP, &output, QUIT);
-
-    free((PM_WCHAR *)output);
-}
+renderSheet(struct CmdlineInfo const cmdline,
+            FILE *             const ofP) {
 
+    struct Text const sheetText =
+        { (PM_WCHAR ** const) sheetTextArray, 12, 12};
+    static unsigned char const sheetRequestArray[16] = {
+         0x00, 0x00, 0x00, 0x00,  0xff, 0xff, 0xff, 0xff,
+         0xff, 0xff, 0xff, 0xff,  0xff, 0xff, 0xff, 0xfe};
 
+    struct pm_selector * selectorP;
+    struct font2 *       fontP;
+    bool                 fontIsComplete;
 
-static void
-renderSheet(struct font2 * const fontP,
-            FILE *         const ofP) {
+    pm_selector_create_fixed(sheetRequestArray, 32, 126,95, &selectorP);
 
-    int const cols  = fontP->maxwidth  * 16;
-    int const rows  = fontP->maxheight * 12;
-    struct Text const sheetText =
-        { (PM_WCHAR ** const) sheetTextArray, 12, 12};
+    computeFont(cmdline, &fontP, selectorP, QUIT, &fontIsComplete);
 
-    validateText(sheetTextArray, fontP);
+    {
+        unsigned int const cols  = fontP->maxwidth  * 16;
+        unsigned int const rows  = fontP->maxheight * 12;
 
-    renderText(cols, rows, fontP, 0, 0, sheetText, MAX(-(fontP->x),0),
-               0.0, 0, TRUE, ofP);
+        renderText(cols, rows, fontP, 0, 0, sheetText, MAX(-(fontP->x),0),
+                   0.0, 0, TRUE, ofP);
+    }
+    pm_selector_destroy(selectorP);
 }
 
 
@@ -1304,8 +1454,8 @@ textDumpOutput(struct Text   const lp,
 
 static void
 pbmtext(struct CmdlineInfo const cmdline,
-        struct font2 *     const fontP,
-        FILE *             const ofP) {
+        FILE *             const ofP,
+        bool               const wchar) {
 
     unsigned int rows, cols;
         /* Dimensions in pixels of the output image */
@@ -1315,19 +1465,30 @@ pbmtext(struct CmdlineInfo const cmdline,
     unsigned int hmargin0;
     struct Text inputText;
     struct Text formattedText;
+    struct font2 * fontP;
+    struct pm_selector * selectorP;
     unsigned int maxleftb, maxleftb0;
+    bool fontIsComplete;
+
+    pm_selector_create(wchar ? PM_FONT2_MAXGLYPH : PM_FONT_MAXGLYPH,
+                       &selectorP);
 
-    getText(cmdline.text, fontP, &inputText,
-            cmdline.verbose ? WARN : SILENT);
+    getText(cmdline.text, &inputText, selectorP);
+
+    if (pm_selector_marked_ct(selectorP) == 0)
+        pm_error("No input text.  Aborting.");
+
+    computeFont(cmdline, &fontP, selectorP, cmdline.verbose ? WARN : SILENT,
+                &fontIsComplete);
 
     computeMargins(cmdline, inputText, fontP, &vmargin, &hmargin0);
 
+    if (!fontIsComplete)
+        refineText(inputText, fontP);
+
     formatText(cmdline, inputText, fontP, hmargin0,
                &formattedText, &maxleftb0);
 
-    if (formattedText.lineCount == 0)
-        pm_error("No input text");
-
     computeImageHeight(formattedText, fontP, cmdline.lspace, vmargin, &rows);
 
     computeImageWidth(formattedText, fontP, cmdline.space,
@@ -1361,6 +1522,8 @@ pbmtext(struct CmdlineInfo const cmdline,
                    maxleftb, cmdline.space, cmdline.lspace, FALSE, ofP);
 
     freeTextArray(formattedText);
+
+    pm_selector_destroy(selectorP);
 }
 
 
@@ -1369,7 +1532,6 @@ int
 main(int argc, const char *argv[]) {
 
     struct CmdlineInfo cmdline;
-    struct font2 * fontP;
 
     pm_proginit(&argc, argv);
 
@@ -1389,12 +1551,10 @@ main(int argc, const char *argv[]) {
     if (cmdline.verbose)
         pm_message("LC_CTYPE is set to '%s'", setlocale(LC_CTYPE, NULL) );
 
-    computeFont(cmdline, &fontP);
-
     if (cmdline.dumpsheet)
-        renderSheet(fontP, stdout);
+        renderSheet(cmdline, stdout);
     else
-        pbmtext(cmdline, fontP, stdout);
+        pbmtext(cmdline, stdout, cmdline.wchar);
 
     pm_close(stdout);
 
diff --git a/generator/pbmtextps.c b/generator/pbmtextps.c
index f543618d..0c3656e7 100644
--- a/generator/pbmtextps.c
+++ b/generator/pbmtextps.c
@@ -190,7 +190,7 @@ parseCommandLine(int argc, const char ** argv,
     unsigned int leftmarginSpec, rightmarginSpec;
     unsigned int topmarginSpec, bottommarginSpec;
 
-    MALLOCARRAY(option_def, 100);
+    MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENTRY */
     OPTENT3(0, "resolution",    OPT_UINT,
diff --git a/generator/ppmforge.c b/generator/ppmforge.c
index 8fec9fee..114f7f18 100644
--- a/generator/ppmforge.c
+++ b/generator/ppmforge.c
@@ -631,7 +631,7 @@ createPlanetStuff(bool             const clouds,
     MALLOCARRAY(bxc, cols);
 
     if (u == NULL || u1 == NULL || bxf == NULL || bxc == NULL)
-        pm_error("Cannot allocate %d element interpolation tables.", cols);
+        pm_error("Cannot allocate %u element interpolation tables.", cols);
     {
         unsigned int j;
         for (j = 0; j < cols; j++) {
diff --git a/generator/ppmmake.c b/generator/ppmmake.c
index 2d4bbca8..7bac9601 100644
--- a/generator/ppmmake.c
+++ b/generator/ppmmake.c
@@ -46,7 +46,7 @@ parseCommandLine(int argc, char ** argv,
     unsigned int maxvalSpec;
     unsigned int option_def_index;
 
-    MALLOCARRAY(option_def, 100);
+    MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENTRY */
     OPTENT3(0,   "maxval",    OPT_UINT, &cmdlineP->maxval, &maxvalSpec,    0);
diff --git a/generator/ppmrough.c b/generator/ppmrough.c
index e749c9c2..626ee989 100644
--- a/generator/ppmrough.c
+++ b/generator/ppmrough.c
@@ -47,7 +47,7 @@ parseCommandLine(int argc, const char ** argv,
 
     unsigned int option_def_index;
 
-    MALLOCARRAY(option_def, 100);
+    MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENTRY */
     OPTENT3(0, "width",       OPT_UINT,   &cmdlineP->width,   NULL, 0);
diff --git a/lib/libpam.c b/lib/libpam.c
index a8f140b3..d19534e2 100644
--- a/lib/libpam.c
+++ b/lib/libpam.c
@@ -420,40 +420,49 @@ pnm_setpamrow(const struct pam * const pamP,
 #define MAX_VALUE_LENGTH 255
 
 static void
-parseHeaderLine(const char buffer[],
-                char label[MAX_LABEL_LENGTH+1],
-                char value[MAX_VALUE_LENGTH+1]) {
-
-    int buffer_curs;
+parseHeaderLine(const char * const buffer,
+                char *       const label,
+                char *       const value) {
+/*----------------------------------------------------------------------------
+   We truncate the labe to MAX_LABEL_LENGTH and the value to
+   MAX_VALUE_LENGTH.  There must be at least that much space (plus space
+   for a terminating NUL) at 'label' and 'value', respectively.
+-----------------------------------------------------------------------------*/
+    unsigned int bufferCurs;
 
-    buffer_curs = 0;
     /* Skip initial white space */
-    while (ISSPACE(buffer[buffer_curs])) buffer_curs++;
+    for (bufferCurs = 0; ISSPACE(buffer[bufferCurs]); ++bufferCurs) {}
 
     {
         /* Read off label, put as much as will fit into label[] */
-        int label_curs;
-        label_curs = 0;
-        while (!ISSPACE(buffer[buffer_curs]) && buffer[buffer_curs] != '\0') {
-            if (label_curs < MAX_LABEL_LENGTH)
-                label[label_curs++] = buffer[buffer_curs];
-            buffer_curs++;
+        unsigned int labelCurs;
+
+        for (labelCurs = 0;
+             !ISSPACE(buffer[bufferCurs]) && buffer[bufferCurs] != '\0';
+             ++bufferCurs) {
+            if (labelCurs < MAX_LABEL_LENGTH)
+                label[labelCurs++] = buffer[bufferCurs];
         }
-        label[label_curs] = '\0';  /* null terminate it */
+        label[labelCurs] = '\0';  /* null terminate it */
     }
 
     /* Skip white space between label and value */
-    while (ISSPACE(buffer[buffer_curs])) buffer_curs++;
+    while (ISSPACE(buffer[bufferCurs]))
+        ++bufferCurs;
 
-    /* copy value into value[] */
-    strncpy(value, buffer+buffer_curs, MAX_VALUE_LENGTH+1);
+    /* copy value into value[], truncating as necessary */
+    strncpy(value, buffer+bufferCurs, MAX_VALUE_LENGTH);
+    value[MAX_VALUE_LENGTH] = '\0';
 
     {
         /* Remove trailing white space from value[] */
-        int value_curs;
-        value_curs = strlen(value)-1;
-        while (value_curs >= 0 && ISSPACE(value[value_curs]))
-            value[value_curs--] = '\0';
+        unsigned int valueCurs;
+
+        for (valueCurs = strlen(value);
+             valueCurs > 0 && ISSPACE(value[valueCurs-1]);
+             --valueCurs);
+
+        value[valueCurs] = '\0';
     }
 }
 
diff --git a/lib/libpbmfont0.c b/lib/libpbmfont0.c
index 503c7ee7..9c876926 100644
--- a/lib/libpbmfont0.c
+++ b/lib/libpbmfont0.c
@@ -27,7 +27,6 @@
 #include "pbmfont.h"
 #include "pbmfontdata.h"
 
-
 struct font *
 pbm_defaultfont(const char * const name) {
 /*----------------------------------------------------------------------------
@@ -77,11 +76,12 @@ pbm_defaultfont2(const char * const requestedFontName) {
 
 
 static void
-selectFontType(const    char * const filename,
-               PM_WCHAR        const maxmaxglyph,
-               unsigned int    const isWide,
-               struct font  ** const fontPP,
-               struct font2 ** const font2PP) {
+selectFontType(const    char *            const filename,
+               PM_WCHAR                   const maxmaxglyph,
+               unsigned int               const isWide,
+               struct font  **            const fontPP,
+               struct font2 **            const font2PP,
+               const struct pm_selector * const selectorP) {
 
     FILE * fileP;
     struct font  * fontP  = NULL; /* initial value */
@@ -106,7 +106,7 @@ selectFontType(const    char * const filename,
 
     } else if (!strncmp(line, "STARTFONT", 9)) {
         if (isWide == TRUE)
-            font2P = pbm_loadbdffont2(filename, maxmaxglyph);
+            font2P = pbm_loadbdffont2select(filename, maxmaxglyph, selectorP);
         else
             fontP = pbm_loadbdffont(filename);
         if (fontP == NULL && font2P == NULL)
@@ -128,25 +128,49 @@ selectFontType(const    char * const filename,
 
 
 struct font *
-pbm_loadfont(const    char * const filename) {
-
+pbm_loadfont(const char * const filename) {
+/*----------------------------------------------------------------------------
+   Load font file named 'filename'.
+   Font file may be either a PBM sheet or BDF.
+   Supports 8 bit codepoints.
+-----------------------------------------------------------------------------*/
     struct font  * fontP;
     struct font2 * font2P;
 
-    selectFontType(filename, PM_FONT_MAXGLYPH, FALSE, &fontP, &font2P);
+    selectFontType(filename, PM_FONT_MAXGLYPH, FALSE, &fontP, &font2P, NULL);
     return fontP;
 }
 
 
 
 struct font2 *
-pbm_loadfont2(const    char * const filename,
-              PM_WCHAR        const maxmaxglyph) {
+pbm_loadfont2(const char * const filename,
+              PM_WCHAR     const maxmaxglyph) {
+/*----------------------------------------------------------------------------
+   Load font file named 'filename'.
+   Font file may be either a PBM sheet or BDF.
+   Supports codepoints above 256.
+-----------------------------------------------------------------------------*/
+    struct font  * fontP;
+    struct font2 * font2P;
+
+    selectFontType(filename, maxmaxglyph, TRUE, &fontP, &font2P, NULL);
+    return font2P;
+}
+
 
+struct font2 *
+pbm_loadfont2select(const  char *              const filename,
+                    PM_WCHAR                   const maxmaxglyph,
+                    const struct pm_selector * const selectorP) {
+/*----------------------------------------------------------------------------
+   Same as pbm_loadfont2(), but load only glyphs indicated by *selectorP
+-----------------------------------------------------------------------------*/
     struct font  * fontP;
     struct font2 * font2P;
 
-    selectFontType(filename, maxmaxglyph, TRUE, &fontP, &font2P);
+    selectFontType(filename, maxmaxglyph, TRUE, &fontP, &font2P, selectorP);
+
     return font2P;
 }
 
@@ -173,7 +197,7 @@ pbm_createbdffont2_base(struct font2 ** const font2PP,
     /*  Caller should overwrite following fields as necessary */
     font2P->oldfont = NULL;
     font2P->fcols = font2P->frows = 0;
-    font2P->selector = NULL;
+    font2P->selectorP = NULL;
     font2P->default_char = 0;
     font2P->default_char_defined = FALSE;
     font2P->total_chars = font2P->chars = 0;
@@ -187,23 +211,32 @@ pbm_createbdffont2_base(struct font2 ** const font2PP,
 
 
 static void
-destroyGlyphData(struct glyph ** const glyph,
-                 PM_WCHAR        const maxglyph) {
+destroyGlyphData(struct glyph **            const glyph,
+                 PM_WCHAR                   const maxglyph,
+                 const struct pm_selector * const selectorP) {
 /*----------------------------------------------------------------------------
   Free glyph objects and bitmap objects.
 
   This does not work when an object is "shared" through multiple pointers
   referencing an identical address and thus pointing to a common glyph
   or bitmap object.
+
+  If 'selectorP' is NULL, free all glyph and bitmap objects in the range
+  0 ... maxglyph.  If not, free only the objects which the selector
+  indicates as present.
 -----------------------------------------------------------------------------*/
 
+    PM_WCHAR const min = (selectorP != NULL) ? selectorP->min : 0;
+    PM_WCHAR const max =
+        (selectorP != NULL) ? MIN(selectorP->max, maxglyph) : maxglyph;
+
     PM_WCHAR i;
 
-    for(i = 0; i <= maxglyph; ++i) {
-        if (glyph[i]!=NULL) {
+    for (i = min; i <= max; ++i) {
+        if (pm_selector_is_marked(selectorP, i) && glyph[i]) {
             free((void *) (glyph[i]->bmap));
             free(glyph[i]);
-      }
+        }
     }
 }
 
@@ -214,17 +247,19 @@ pbm_destroybdffont2_base(struct font2 * const font2P) {
   Free font2 structure, but not the glyph data
 ---------------------------------------------------------------------------- */
 
-    free(font2P->selector);
-
     pm_strfree(font2P->name);
+
     pm_strfree(font2P->charset_string);
+
     free(font2P->glyph);
 
-    if (font2P->oldfont !=NULL)
-       pbm_freearray(font2P->oldfont, font2P->frows);
+    if (font2P->selectorP)
+        pm_selector_destroy(font2P->selectorP);
 
-    free((void *)font2P);
+    if (font2P->oldfont)
+       pbm_freearray(font2P->oldfont, font2P->frows);
 
+    free(font2P);
 }
 
 
@@ -239,8 +274,8 @@ pbm_destroybdffont2(struct font2 * const font2P) {
 ---------------------------------------------------------------------------- */
 
     if (font2P->load_fn != FIXED_DATA) {
-        destroyGlyphData(font2P->glyph, font2P->maxglyph);
-        pbm_destroybdffont2_base(font2P);
+        destroyGlyphData(font2P->glyph, font2P->maxglyph, font2P->selectorP);
+                         pbm_destroybdffont2_base(font2P);
     }
 }
 
@@ -254,7 +289,7 @@ pbm_destroybdffont(struct font * const fontP) {
   For freeing a structure created by pbm_loadbdffont() or pbm_loadpbmfont().
 ---------------------------------------------------------------------------- */
 
-    destroyGlyphData(fontP->glyph, PM_FONT_MAXGLYPH);
+    destroyGlyphData(fontP->glyph, PM_FONT_MAXGLYPH, NULL);
 
     if (fontP->oldfont !=NULL)
        pbm_freearray(fontP->oldfont, fontP->frows);
@@ -326,8 +361,7 @@ pbm_expandbdffont(const struct font * const fontP) {
     font2P->bit_format = PBM_FORMAT;
     font2P->total_chars = font2P->chars = nCharacters;
     font2P->load_fn = CONVERTED_TYPE1_FONT;
-    /* Caller should be overwrite the above to a more descriptive
-       value */
+    /* Caller should overwrite the above to a more descriptive value */
     return font2P;
 }
 
diff --git a/lib/libpbmfont1.c b/lib/libpbmfont1.c
index 4189f150..fe014150 100644
--- a/lib/libpbmfont1.c
+++ b/lib/libpbmfont1.c
@@ -47,7 +47,7 @@
   The characters in the border you see are irrelevant except for
   character size compuations.  The 12 x 8 array in the center is
   the font.  The top left character there belongs to code point
-  0, and the code points increase in standard reading order, so
+  32, and the code points increase in standard reading order, so
   the bottom right character is code point 127.  You can't define
   code points < 32 or > 127 with this font format.
 
diff --git a/lib/libpbmfont2.c b/lib/libpbmfont2.c
index b354e91b..1560b407 100644
--- a/lib/libpbmfont2.c
+++ b/lib/libpbmfont2.c
@@ -33,6 +33,208 @@
 #include "pbm.h"
 
 /*----------------------------------------------------------------------------
+  Font selector routines
+
+  The selector is a device consisting of a bitmap, min value, max value and
+  count.  It is used here to specify necessary fonts and record what entries
+  are valid in the glyph array.
+
+  This device may be used for other purposes.  In that case the code should
+  be put into an independent source file in the lib/util subdirectory.
+-----------------------------------------------------------------------------*/
+
+static void
+allocRecord(struct pm_selector * const selectorP,
+            unsigned int         const max) {
+
+    unsigned int const size = (max + 8) / 8;
+
+    MALLOCARRAY(selectorP->localRecord, size);
+
+    if (!selectorP->localRecord)
+        pm_error("Failed to allocate %u bytes of memory for font selector "
+                 "bitmap", size);
+
+    selectorP->record = selectorP->localRecord;
+}
+
+
+
+void
+pm_selector_create(unsigned int          const max,
+                   struct pm_selector ** const selectorPP) {
+
+    struct pm_selector * selectorP;
+
+    MALLOCVAR_NOFAIL(selectorP);
+
+    allocRecord(selectorP, max);
+
+    {
+        unsigned int byteIndex;
+        for (byteIndex = 0; byteIndex <= max/8; ++byteIndex)
+            selectorP->localRecord[byteIndex]= 0x00;
+    }
+
+    selectorP->maxmax = selectorP->min = max;
+    selectorP->max = 0;
+    selectorP->count = 0;
+
+    *selectorPP = selectorP;
+}
+
+
+
+void
+pm_selector_create_fixed(const unsigned char * const record,
+                         unsigned int          const min,
+                         unsigned int          const max,
+                         unsigned int          const count,
+                         struct pm_selector ** const selectorPP) {
+
+    struct pm_selector * selectorP;
+
+    MALLOCVAR_NOFAIL(selectorP);
+
+    selectorP->localRecord = NULL;
+    selectorP->record      = record;
+    selectorP->min         = min;
+    selectorP->max         = max;
+    selectorP->maxmax      = max;
+    selectorP->count       = count;
+
+    *selectorPP = selectorP;
+}
+
+
+
+void
+pm_selector_destroy(struct pm_selector * const selectorP) {
+
+    if (selectorP->localRecord)
+        free(selectorP->localRecord);
+
+    free(selectorP);
+}
+
+
+
+void
+pm_selector_copy(unsigned int               const max,
+                 const struct pm_selector * const srcSelectorP,
+                 struct pm_selector      ** const destSelectorPP) {
+
+    /* Create a new selector and copy into it the content of another */
+
+    struct pm_selector * destSelectorP;
+
+    if (max < srcSelectorP->max)
+        pm_error("internal error: attempt to copy a selector as "
+                 "another with a smaller max value %u -> %u",
+                 srcSelectorP->max, max);
+
+    MALLOCVAR_NOFAIL(destSelectorP);
+
+    destSelectorP->maxmax     = max;
+    destSelectorP->max        = srcSelectorP->max;
+    destSelectorP->min        = srcSelectorP->min;
+    destSelectorP->count      = srcSelectorP->count;
+
+    allocRecord(destSelectorP, max);
+
+    {
+        unsigned int const minByteIndex = srcSelectorP->min / 8;
+        unsigned int const maxByteIndex = srcSelectorP->max / 8;
+        unsigned int const maxmaxByteIndex = max / 8;
+
+        unsigned int byteIndex;
+
+        for (byteIndex = 0 ; byteIndex < minByteIndex; ++byteIndex)
+            destSelectorP->localRecord[byteIndex] = 0x00;
+        for (byteIndex = maxByteIndex + 1 ; byteIndex <= maxmaxByteIndex;
+             ++byteIndex)
+            destSelectorP->localRecord[byteIndex] = 0x00;
+        for (byteIndex = minByteIndex; byteIndex <= maxByteIndex; ++byteIndex)
+            destSelectorP->localRecord[byteIndex] =
+                srcSelectorP->record[byteIndex];
+    }
+
+    *destSelectorPP = destSelectorP;
+}
+
+
+
+void
+pm_selector_mark(struct pm_selector * const selectorP,
+                 unsigned int         const index) {
+/*----------------------------------------------------------------------------
+   Mark index 'index'.
+-----------------------------------------------------------------------------*/
+    unsigned int  byteIndex = index / 8;
+    unsigned int  bitIndex  = index % 8;
+    unsigned char mask = (0x01 <<7) >> bitIndex;
+
+    /* set bit on to indicate presence of this index */
+
+    if (!selectorP->localRecord)
+        pm_error("INTERNAL ERROR: attempt to mark in a fixed pm_selector");
+
+    if ((selectorP->localRecord[byteIndex] & mask) == 0x00) {
+        /* if bit is not already set */
+
+        selectorP->localRecord[byteIndex] |= mask;
+        ++selectorP->count;  /* increment count */
+
+        /* reset min and max */
+        if (selectorP->min > index)
+            selectorP->min = index;
+        if (selectorP->max < index)
+            selectorP->max = index;
+    }
+}
+
+/* There is no function for erasing a marked bit */
+
+
+int  /* boolean */
+pm_selector_is_marked(const struct pm_selector * const selectorP,
+                      unsigned int               const index) {
+/*----------------------------------------------------------------------------
+  Index 'index' is marked.
+-----------------------------------------------------------------------------*/
+    bool retval;
+
+    if (selectorP) {
+        unsigned int  const byteIndex = index / 8;
+        unsigned int  const bitIndex  = index % 8;
+        unsigned char const mask = (0x01 <<7) >> bitIndex;
+
+        if ( index < selectorP->min || index > selectorP->max)
+            retval = false;
+        else if ((selectorP->record[byteIndex] & mask) != 0x00)
+            retval = true;
+        else
+            retval = false;
+    } else {
+        /* All entries are set to "exist" */
+        retval = true;
+    }
+    return retval ? 1 : 0;
+}
+
+
+
+unsigned int
+pm_selector_marked_ct(const struct pm_selector * const selectorP) {
+/*----------------------------------------------------------------------------
+   Number of indices that are marked.
+-----------------------------------------------------------------------------*/
+    return selectorP->count;
+}
+
+
+
+/*----------------------------------------------------------------------------
   Routines for loading a BDF font file
 -----------------------------------------------------------------------------*/
 
@@ -354,21 +556,23 @@ readExpectedStatement(Readline *    const readlineP,
 static void
 skipCharacter(Readline * const readlineP) {
 /*----------------------------------------------------------------------------
-  In the BDF font file being read by readline object *readlineP, skip through
-  the end of the character we are presently in.
+  In the BDF font file being read by readline object *readlineP, skip
+  through to the end of the data for the character we are presently in.
+
+  At entry the stream must be positioned at the end of the ENCODING line.
 -----------------------------------------------------------------------------*/
-    bool endChar;
 
-    endChar = FALSE;
+    char * rc;
+    do {
+        rc = fgets(readlineP->line, MAXBDFLINE+1, readlineP->ifP);
+        readlineP->line[7] = '\0';
+
+    } while (rc != NULL && !streq(readlineP->line, "ENDCHAR"));
+
+    if (rc == NULL)
+        pm_error("End of file in the middle of a character (before "
+                 "ENDCHAR) in BDF font file.");
 
-    while (!endChar) {
-        bool eof;
-        readline_read(readlineP, &eof);
-        if (eof)
-            pm_error("End of file in the middle of a character (before "
-                     "ENDCHAR) in BDF font file.");
-        endChar = streq(readlineP->arg[0], "ENDCHAR");
-    }
 }
 
 
@@ -421,7 +625,7 @@ interpEncoding(const char **  const arg,
 
    'maxmaxglyph' is the maximum codepoint in the font.
 -----------------------------------------------------------------------------*/
-    bool gotCodepoint;
+    bool gotCodepoint = false;   /* initial value */
     bool badCodepoint;
     unsigned int codepoint;
 
@@ -429,12 +633,15 @@ interpEncoding(const char **  const arg,
         codepoint = wordToInt(arg[1]);
         gotCodepoint = true;
     } else {
-      if (wordToInt(arg[1]) == -1 && arg[2] != NULL) {
-            codepoint = wordToInt(arg[2]);
-            gotCodepoint = true;
-        } else
-            gotCodepoint = false;
+        if (wordToInt(arg[1]) == -1 && arg[2] != NULL) {
+            int const codepoint0 = wordToInt(arg[2]);
+            if (codepoint0 >= 0) {
+                codepoint = codepoint0;
+                gotCodepoint = true;
+            }
+        }
     }
+
     if (gotCodepoint) {
         if (codepoint > maxmaxglyph)
             badCodepoint = true;
@@ -538,112 +745,147 @@ validateGlyphLimits(const struct font2 * const font2P,
 
 
 static void
-processChars(Readline *     const readlineP,
-             struct font2 * const font2P) {
-/*----------------------------------------------------------------------------
-   Process the CHARS block in a BDF font file, assuming the file is positioned
-   just after the CHARS line.  Read the rest of the block and apply its
-   contents to *font2P.
------------------------------------------------------------------------------*/
-    unsigned int const nCharacters = wordToInt(readlineP->arg[1]);
-
-    unsigned int nCharsDone;
-    unsigned int nCharsValid;
-
-    for (nCharsDone = 0, nCharsValid = 0;
-         nCharsDone < nCharacters; ) {
-
+readStartchar(Readline * const readlineP,
+              const char ** charNameP) {
+        
+        const char * charName;
         bool eof;
 
         readline_read(readlineP, &eof);
         if (eof)
             pm_error("End of file after CHARS reading BDF font file");
 
-        if (streq(readlineP->arg[0], "COMMENT")) {
+        while (streq(readlineP->arg[0], "COMMENT")) {
+            readline_read(readlineP, &eof);
+            if (eof)
+                 pm_error("End of file after CHARS reading BDF font file");
             /* ignore */
-        } else if (!streq(readlineP->arg[0], "STARTCHAR"))
+        }
+
+        if (!streq(readlineP->arg[0], "STARTCHAR"))
             pm_error("%s detected where \'STARTCHAR\' expected "
                      "in BDF font file", readlineP->arg[0] );
-        else {
-            const char * charName;
-
-            struct glyph * glyphP;
-            unsigned int codepoint;
-            bool badCodepoint;
-
-            if (readlineP->wordCt < 2)
-                pm_error("Wrong number of arguments in STARTCHAR line "
-                         "in BDF font file");
+        else if (readlineP->wordCt < 2)
+            pm_error("Wrong number of arguments in STARTCHAR line "
+                      "in BDF font file");
             /* Character name may contain spaces: there may be more than
                three words in the line.
              */
+        else
             charName = pm_strdup(readlineP->arg[1]);
 
-            assert(streq(readlineP->arg[0], "STARTCHAR"));
+        *charNameP = charName;
+}
 
-            MALLOCVAR(glyphP);
 
-            if (glyphP == NULL)
-                pm_error("no memory for font glyph for '%s' character",
-                         charName);
 
-            readEncoding(readlineP, &codepoint, &badCodepoint,
-                         font2P->maxmaxglyph);
+static void
+readGlyph(Readline * const readlineP,
+          const char * const charName,
+          const struct font2 * const font2P,
+          struct glyph ** const glyphPP) {
 
-            if (badCodepoint)
-                skipCharacter(readlineP);
-            else {
-                if (codepoint < font2P->maxglyph) {
-                    if (font2P->glyph[codepoint] != NULL)
-                        pm_error("Multiple definition of code point %u "
-                                 "in BDF font file", (unsigned int) codepoint);
-                    else
-                        pm_message("Reverse order detected in BDF file. "
-                                   "Code point %u defined after %u",
-                                    (unsigned int) codepoint,
-                                    (unsigned int) font2P->maxglyph);
-                } else {
-                    /* Initialize all characters in the gap to nonexistent */
-                    unsigned int i;
-                    unsigned int const oldMaxglyph = font2P->maxglyph;
-                    unsigned int const newMaxglyph = codepoint;
+    struct glyph * glyphP;
+    MALLOCVAR(glyphP);
+    if (glyphP == NULL)
+        pm_error("no memory for font glyph for '%s' character",
+             charName);
 
-                    for (i = oldMaxglyph + 1; i < newMaxglyph; ++i)
-                        font2P->glyph[i] = NULL;
+    readExpectedStatement(readlineP, "SWIDTH", 3);
 
-                    font2P->maxglyph = newMaxglyph;
-                    }
+    readExpectedStatement(readlineP, "DWIDTH", 3);
+    glyphP->xadd = wordToInt(readlineP->arg[1]);
 
-                readExpectedStatement(readlineP, "SWIDTH", 3);
+    readExpectedStatement(readlineP, "BBX", 5);
+    glyphP->width  = wordToInt(readlineP->arg[1]);
+    glyphP->height = wordToInt(readlineP->arg[2]);
+    glyphP->x      = wordToInt(readlineP->arg[3]);
+    glyphP->y      = wordToInt(readlineP->arg[4]);
 
-                readExpectedStatement(readlineP, "DWIDTH", 3);
-                glyphP->xadd = wordToInt(readlineP->arg[1]);
+    validateGlyphLimits(font2P, glyphP, charName);
 
-                readExpectedStatement(readlineP, "BBX", 5);
-                glyphP->width  = wordToInt(readlineP->arg[1]);
-                glyphP->height = wordToInt(readlineP->arg[2]);
-                glyphP->x      = wordToInt(readlineP->arg[3]);
-                glyphP->y      = wordToInt(readlineP->arg[4]);
+    createBmap(glyphP->width, glyphP->height, readlineP, charName,
+               &glyphP->bmap);
 
-                validateGlyphLimits(font2P, glyphP, charName);
+    *glyphPP = glyphP;
+}
+
+
+
+static void
+processChars(Readline *     const readlineP,
+             struct font2 * const font2P) {
+/*----------------------------------------------------------------------------
+   Process the CHARS block in a BDF font file, assuming the file is positioned
+   just after the CHARS line.  Read the rest of the block and apply its
+   contents to *font2P.
+-----------------------------------------------------------------------------*/
+    unsigned int const nCharacters = wordToInt(readlineP->arg[1]);
+    unsigned int const nCharsWanted = (font2P->selectorP != NULL) ?
+        font2P->selectorP->count : nCharacters;
+
+    unsigned int nCharsEncountered;
+    unsigned int nCharsLoaded;
+
+    for (nCharsEncountered = 0, nCharsLoaded = 0;
+         nCharsEncountered < nCharacters && nCharsLoaded < nCharsWanted;
+         ++nCharsEncountered ) {
+
+        const char * charName;
+        unsigned int codepoint;
+        bool badCodepoint;
+
+        readStartchar(readlineP, &charName);
+
+        readEncoding(readlineP, &codepoint, &badCodepoint,
+                         font2P->maxmaxglyph);
+
+        if ( badCodepoint ) {
+            skipCharacter(readlineP);
+            pm_strfree (charName);
+            }
+        else if (!pm_selector_is_marked(font2P->selectorP, codepoint) ) {
+            skipCharacter(readlineP);
+            pm_strfree (charName);
+            font2P->maxglyph = codepoint;
+            }
+        else {
+            if (codepoint < font2P->maxglyph) {
+                if (font2P->glyph[codepoint] != NULL )
+                       pm_error("Multiple definition of code point %u "
+                                "in BDF font file", (unsigned int) codepoint);
+                else
+                       pm_message("Reverse order detected in BDF file. "
+                                  "Code point %u defined after %u",
+                                   (unsigned int) codepoint,
+                                   (unsigned int) font2P->maxglyph);
+            }
 
-                createBmap(glyphP->width, glyphP->height, readlineP, charName,
-                           &glyphP->bmap);
+            {
+            struct glyph * glyphP;
 
-                readExpectedStatement(readlineP, "ENDCHAR", 1);
+            readGlyph(readlineP, charName, font2P, &glyphP);
+            readExpectedStatement(readlineP, "ENDCHAR", 1);
 
-                assert(codepoint <= font2P->maxmaxglyph);
-                /* Ensured by readEncoding() */
+            assert(codepoint <= font2P->maxmaxglyph);
+            /* Ensured by readEncoding() */
 
-                font2P->glyph[codepoint] = glyphP;
-                pm_strfree(charName);
+            font2P->glyph[codepoint] = glyphP;
+            pm_strfree(charName);
 
-                ++nCharsValid;
+            font2P->maxglyph = codepoint;
+            ++nCharsLoaded;
             }
-            ++nCharsDone;
         }
     }
-    font2P->chars = nCharsValid;
+
+    /* Note that BDF file may have reached end before the largest entry
+       in selector was checked.  */
+    /*
+    if (font2P->selectorP->max > font2P->maxglyph)
+       font2P->maxglyph = font2P->selectorP->max;
+    */
+    font2P->chars       = nCharsLoaded;
     font2P->total_chars = nCharacters;
 }
 
@@ -717,12 +959,8 @@ loadCharsetString(const char *  const registry,
 }
 
 
-
-
 static unsigned int const maxTokenLen = 60;
 
-
-
 static void
 doCharsetRegistry(Readline *    const readlineP,
                   bool *        const gotRegistryP,
@@ -904,6 +1142,9 @@ processBdfFontLine(Readline     * const readlineP,
       else {
         validateWordCount(readlineP, 2);  /* CHARS n */
         processChars(readlineP, font2P);
+        if (font2P->selectorP != NULL &&
+            font2P->selectorP->count == font2P->chars)
+               *endOfFontP = true;
       }
     } else {
         /* ignore */
@@ -913,9 +1154,39 @@ processBdfFontLine(Readline     * const readlineP,
 
 
 
+static void
+initializeGlyphArray(struct font2 * const font2P,
+                     unsigned int   const maxmaxglyph) {
+/*----------------------------------------------------------------------------
+  Initialize glyph array based on entries in selector.
+  Note that only valid codepoints are set to NULL.
+  Entries for unused glyphs are left untouched.
+-----------------------------------------------------------------------------*/
+    const struct pm_selector * const selectorP = font2P->selectorP;
+    unsigned int const min = (selectorP == NULL) ? 0 : selectorP->min;
+    unsigned int const max =
+        (selectorP == NULL) ? font2P->maxglyph : selectorP->max;
+
+    unsigned int codepoint;
+
+    for (codepoint = min; codepoint <= max ; ++codepoint)
+        if (pm_selector_is_marked(selectorP, codepoint) == true)
+             font2P->glyph[codepoint] = NULL;
+
+    font2P->glyph[L' '] = NULL;
+        /* Clear the slot for space character.
+           It may not be defined in the font, but the program may try
+           to use space as a substitute char
+        */
+
+}
+
+
+
 struct font2 *
-pbm_loadbdffont2(const char * const filename,
-                 PM_WCHAR     const maxmaxglyph) {
+pbm_loadbdffont2select(const char *               const filename,
+                       PM_WCHAR                   const maxmaxglyph,
+                       const struct pm_selector * const selectorP) {
 /*----------------------------------------------------------------------------
    Read a BDF font file "filename" as a 'font2' structure.  A 'font2'
    structure is more expressive than a 'font' structure, most notably in that
@@ -943,8 +1214,14 @@ pbm_loadbdffont2(const char * const filename,
 
     font2P->maxglyph = 0;
         /* Initial value.  Increases as new characters are loaded */
-    font2P->glyph[0] = NULL;
-        /* Initial value.  Overwrite later if codepoint 0 is defined. */
+
+    if (font2P->selectorP == NULL) {
+        PM_WCHAR i;
+
+        for(i = 0; i <= maxmaxglyph; ++i)
+            font2P->glyph[i] = NULL;
+            /* Initial value.  Overwrite later if codepoint i is defined. */
+    }
 
     font2P->maxmaxglyph = maxmaxglyph;
 
@@ -955,6 +1232,9 @@ pbm_loadbdffont2(const char * const filename,
     font2P->chars = font2P->total_chars = 0;
     font2P->default_char = 0;
     font2P->default_char_defined = FALSE;
+    font2P->selectorP = (struct pm_selector * const) selectorP;
+
+    initializeGlyphArray(font2P, maxmaxglyph);
 
     readExpectedStatement(&readline, "STARTFONT", 2);
 
@@ -970,9 +1250,13 @@ pbm_loadbdffont2(const char * const filename,
     }
     fclose(ifP);
 
-    if(font2P->chars == 0)
+    if(font2P->total_chars == 0)
         pm_error("No glyphs found in BDF font file "
                  "in codepoint range 0 - %u", (unsigned int) maxmaxglyph);
+    if(font2P->chars == 0)
+        pm_error("Not any requested glyphs found in BDF font file "
+                 "in codepoint range 0 - %u", (unsigned int) maxmaxglyph);
+
 
     REALLOCARRAY(font2P->glyph, font2P->maxglyph + 1);
 
@@ -986,8 +1270,21 @@ pbm_loadbdffont2(const char * const filename,
 }
 
 
+struct font2 *
+pbm_loadbdffont2(const char * const filename,
+                 PM_WCHAR     const maxmaxglyph) {
+
+  return (pbm_loadbdffont2select(filename, maxmaxglyph, NULL));
+
+  return(0);
+}
+
+
+
+
 static struct font *
 font2ToFont(const struct font2 * const font2P) {
+
             struct font  * fontP;
             unsigned int   codePoint;
 
@@ -1001,18 +1298,10 @@ font2ToFont(const struct font2 * const font2P) {
     fontP->x = font2P->x;
     fontP->y = font2P->y;
 
-    for (codePoint = 0; codePoint <= font2P->maxglyph; ++codePoint)
-        fontP->glyph[codePoint] = font2P->glyph[codePoint];
-
-    /* font2P->maxglyph is typically 255 (PM_FONT_MAXGLYPH) or larger.
-       But in some rare cases it is smaller.
-       If an ASCII-only font is read, it will be 126 or 127.
-
-       Set remaining codepoints up to PM_FONT_MAXGLYPH, if any, to NULL
-    */
-
-    for ( ; codePoint <= PM_FONT_MAXGLYPH; ++codePoint)
-        fontP->glyph[codePoint] = NULL;
+    for (codePoint = 0; codePoint <= PM_FONT_MAXGLYPH; ++codePoint)
+        fontP->glyph[codePoint] =
+             pm_selector_is_marked(font2P->selectorP, codePoint) ?
+             font2P->glyph[codePoint] : NULL;
 
     /* Give values to legacy fields */
     fontP->oldfont = font2P->oldfont;
diff --git a/lib/libpm.c b/lib/libpm.c
index 47a2f498..bc922385 100644
--- a/lib/libpm.c
+++ b/lib/libpm.c
@@ -770,10 +770,10 @@ extractAfterLastSlash(const char * const fullPath,
     slashPos = strrchr(fullPath, '/');
 
     if (slashPos == NULL) {
-        strncpy(retval, fullPath, retvalSize);
+        strncpy(retval, fullPath, retvalSize-1);
         retval[retvalSize-1] = '\0';
     } else {
-        strncpy(retval, slashPos +1, retvalSize);
+        strncpy(retval, slashPos + 1, retvalSize-1);
         retval[retvalSize-1] = '\0';
     }
 }
diff --git a/lib/pbmfont.h b/lib/pbmfont.h
index c8b3934b..6adbe814 100644
--- a/lib/pbmfont.h
+++ b/lib/pbmfont.h
@@ -115,12 +115,12 @@ struct glyph {
 
 struct font {
     /* This describes a combination of font and character set.  Given
-       an code point in the range 0..255, this structure describes the
+       a code point in the range 0..255, this structure describes the
        glyph for that character.
     */
     unsigned int maxwidth, maxheight;
     int x;
-        /* The minimum value of glyph.font.  The left edge of the glyph
+        /* The minimum value of glyph.x .  The left edge of the glyph
            in the glyph set which advances furthest to the left. */
     int y;
         /* Amount of white space that should be added between lines of
@@ -137,10 +137,29 @@ struct font {
 };
 
 
+
+struct pm_selector {
+    unsigned int min;     /* smallest index requested */
+    unsigned int max;     /* largest index requested  */
+    unsigned int maxmax;  /* largest index possible  */
+    unsigned int count;   /* number bits set to 1 in 'record' */
+    const unsigned char * record;
+        /* Bit array 0: absent 1: existent size calculated from maxmax
+           This is for reading only; not updating.
+           Might be 'localRecord'; might be fixed object elsewhere.
+        */
+    unsigned char * localRecord;
+        /* Updateable record optionally pointed to by 'record'.
+           Null if none.  Malloc'ed storage we own otherwise.
+        */
+};
+
+
+
 struct font2 {
     /* Font structure for expanded character set.
-       Code points in the range 0...maxmaxglyph are loaded.
-       Loaded code point is in the range 0..maxglyph .
+       Code points in the range 0...maxmaxglyph may be loaded.
+       Actually loaded code point is in the range 0..maxglyph .
      */
 
     /* 'size' and 'len' are necessary in order to provide forward and
@@ -159,7 +178,7 @@ struct font2 {
     int maxwidth, maxheight;
 
     int x;
-         /* The minimum value of glyph.font.  The left edge of the glyph in
+         /* The minimum value of glyph.x .  The left edge of the glyph in
             the glyph set which advances furthest to the left.
          */
     int y;
@@ -177,14 +196,12 @@ struct font2 {
          */
 
     PM_WCHAR maxglyph;
-        /* max code point for glyphs, including vacant slots max value of
-           above i
+        /* max code point for glyphs, including vacant slots
+           max value of above i
         */
 
-    void * selector;
-        /* Reserved
-
-           Bit array or structure indicating which code points to load.
+    struct pm_selector * selectorP;
+        /* Structure with bit array indicating which code points to load.
 
            When NULL, all available code points up to maxmaxglyph, inclusive
            are loaded.
@@ -206,14 +223,15 @@ struct font2 {
         */
 
     unsigned int bit_format;
-        /* PBM_FORMAT:   glyph data: 1 byte per pixel (like P1, but not ASCII)
-           RPBM_FORMAT:  glyph data: 1 bit per pixel
+        /* PBM_FORMAT:  glyph data: 1 byte per pixel (like P1, but not ASCII)
+           RPBM_FORMAT: glyph data: 1 bit per pixel
            Currently only PBM_FORMAT is possible
         */
 
     unsigned int total_chars;
-        /* Number of glyphs defined in font file, as stated in the CHARS line
-           of the BDF file PBM sheet font.  Always 96
+        /* Number of glyphs defined in font file.
+           BDF file: as stated in the CHARS line.
+           PBM sheet font: always 96.
         */
 
     unsigned int chars;
@@ -237,7 +255,7 @@ struct font2 {
 
     PM_WCHAR default_char;
         /* Code index of what to show when there is no glyph for a requested
-           code Available in many BDF fonts between STARPROPERTIES -
+           code.  Available in many BDF fonts between STARPROPERTIES -
            ENDPROPERTIES.
 
            Set to value read from BDF font file.
@@ -306,6 +324,11 @@ struct font2 *
 pbm_loadfont2(const    char * const filename,
               PM_WCHAR        const maxmaxglyph);
 
+struct font2 *
+pbm_loadfont2select(const    char *            const filename,
+                    PM_WCHAR                   const maxmaxglyph,
+                    const struct pm_selector * const selectorP);
+
 struct font *
 pbm_loadpbmfont(const char * const filename);
 
@@ -320,9 +343,9 @@ pbm_loadbdffont2(const char * const filename,
                  PM_WCHAR     const maxmaxglyph);
 
 struct font2 *
-pbm_loadbdffont2_select(const char * const filename,
-                        PM_WCHAR     const maxmaxglyph,
-                        const void * const selector);
+pbm_loadbdffont2select(const char *               const filename,
+                       PM_WCHAR                   const maxmaxglyph,
+                       const struct pm_selector * const selectorP);
 
 void
 pbm_createbdffont2_base(struct font2 ** const font2P,
@@ -344,6 +367,38 @@ void
 pbm_dumpfont(struct font * const fontP,
              FILE *        const ofP);
 
+/* selector functions */
+
+void
+pm_selector_create(unsigned int          const max,
+                   struct pm_selector ** const selectorPP);
+
+void
+pm_selector_create_fixed(const unsigned char * const record,
+                         unsigned int          const min,
+                         unsigned int          const max,
+                         unsigned int          const count,
+                         struct pm_selector ** const selectorPP);
+
+void
+pm_selector_destroy(struct pm_selector * const selectorP);
+
+void
+pm_selector_copy(unsigned int               const max,
+                 const struct pm_selector * const srcSelectorP,
+                 struct pm_selector **      const destSelectorPP);
+
+void
+pm_selector_mark(struct pm_selector * const selectorP,
+                 unsigned int         const index);
+
+int  /* boolean */
+pm_selector_is_marked(const struct pm_selector * const selectorP,
+                      unsigned int               const index);
+
+unsigned int
+pm_selector_marked_ct(const struct pm_selector * const selectorP);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/pbmfontdata2.c b/lib/pbmfontdata2.c
index 11dd84e6..63dd36be 100644
--- a/lib/pbmfontdata2.c
+++ b/lib/pbmfontdata2.c
@@ -452,7 +452,7 @@ struct font2 const pbm_defaultBdffont2 = {
   255, NULL, 255,                 /* maxglyph, selector, maxmaxglyph */
   NULL, 0, 0,                     /* oldfont, fcols, frows */
   PBM_FORMAT,                     /* bit_format */
-  190, 190,                       /* total_chars, chars */
+  191, 191,                       /* total_chars, chars */
   FIXED_DATA,                     /* load_fn */
   32, 1,                          /* default_char, default_char_defined */
   (char *) "builtin bdf",         /* name */
diff --git a/lib/pm_system.h b/lib/pm_system.h
index dfcd5b3f..58e17f05 100644
--- a/lib/pm_system.h
+++ b/lib/pm_system.h
@@ -76,8 +76,15 @@ pm_accept_null(int    const pipetosuckFd,
 struct bufferDesc {
     /* This is just a parameter for the routines below */
     unsigned int    size;
+       /* For a read operation, number amount of space available to store
+          data read.  For a write operation, number of bytes of data available.
+       */
     unsigned char * buffer;
     unsigned int *  bytesTransferredP;
+        /* The function returns the number of bytes placed in the buffer or
+           extracted from the buffer here.  NULL if you don't want that
+           information.
+        */
 };
 
 
diff --git a/lib/util/mallocvar.h b/lib/util/mallocvar.h
index 00ba6484..23b28c40 100644
--- a/lib/util/mallocvar.h
+++ b/lib/util/mallocvar.h
@@ -24,30 +24,40 @@ extern "C" {
 
 static __inline__ void
 mallocProduct(void **      const resultP,
-              unsigned int const factor1,
+              size_t       const factor1,
               unsigned int const factor2) {
 /*----------------------------------------------------------------------------
    malloc a space whose size in bytes is the product of 'factor1' and
-   'factor2'.  But if that size cannot be represented as an unsigned int,
-   return NULL without allocating anything.  Also return NULL if the malloc
-   fails.
+   'factor2'.  But if the malloc fails, or that size is too large even to
+   request from malloc, return NULL without allocating anything.
 
    If either factor is zero, malloc a single byte.
-
-   Note that malloc() actually takes a size_t size argument, so the
-   proper test would be whether the size can be represented by size_t,
-   not unsigned int.  But there is no reliable indication available to
-   us, like UINT_MAX, of what the limitations of size_t are.  We
-   assume size_t is at least as expressive as unsigned int and that
-   nobody really needs to allocate more than 4GB of memory.
 -----------------------------------------------------------------------------*/
+    /* C99 introduces SIZE_MAX, the maximum size_t value.
+
+       Pre-C99, we do the best we can, assuming conventional encoding of
+       numbers and that size_t is unsigned.
+    */
+    size_t const sizeMax =
+#if defined(SIZE_MAX)
+        SIZE_MAX
+#else
+        ~((size_t)0)
+#endif
+        ;
+
     if (factor1 == 0 || factor2 == 0)
         *resultP = malloc(1);
     else {
-        if (UINT_MAX / factor2 < factor1)
+        /* N.B. The type of malloc's argument is size_t */
+        if ((size_t)factor2 != factor2)
             *resultP = NULL;
-        else
-            *resultP = malloc(factor1 * factor2);
+        else {
+            if (sizeMax / factor2 < factor1)
+                *resultP = NULL;
+            else
+                *resultP = malloc(factor1 * factor2);
+        }
     }
 }
 
@@ -55,18 +65,30 @@ mallocProduct(void **      const resultP,
 
 static __inline__ void
 reallocProduct(void **      const blockP,
-               unsigned int const factor1,
+               size_t       const factor1,
                unsigned int const factor2) {
 
+    size_t const sizeMax =
+#if defined(SIZE_MAX)
+        SIZE_MAX
+#else
+        ~((size_t)0)
+#endif
+        ;
+
     void * const oldBlockP = *blockP;
 
     void * newBlockP;
 
-    if (UINT_MAX / factor2 < factor1)
+    /* N.B. The type of realloc's argument is size_t */
+    if ((size_t)factor2 != factor2)
         newBlockP = NULL;
-    else
-        newBlockP = realloc(oldBlockP, factor1 * factor2);
-
+    else {
+        if (sizeMax / factor2 < factor1)
+            newBlockP = NULL;
+        else
+            newBlockP = realloc(oldBlockP, factor1 * factor2);
+    }
     if (newBlockP)
         *blockP = newBlockP;
     else {
diff --git a/other/pamfix.c b/other/pamfix.c
index e40f51f4..4f4eedfc 100644
--- a/other/pamfix.c
+++ b/other/pamfix.c
@@ -109,7 +109,7 @@ analyzeRaster(const struct pam * const pamP,
               bool               const verbose) {
 /*----------------------------------------------------------------------------
    Go through the raster at which the stream described by *tweakedPamP is
-   presently positioned and count how many rows can be successfully read
+   currently positioned and count how many rows can be successfully read
    (including validating the samples against pamP->maxval) and determine the
    highest sample value in those rows.
 
diff --git a/test/Test-Order b/test/Test-Order
index a696529b..f907c29b 100644
--- a/test/Test-Order
+++ b/test/Test-Order
@@ -120,12 +120,16 @@ pamtopdbimg.test
 pbmtog3.test
 411toppm.test
 eyuvtoppm.test
+rawtoppm.test
 
 pbm-misc-converters.test
 
 # Miscellaneous utility tests
 
 ppmdfont.test
+pamfix.test
+pamvalidate.test
+pamexec.test
 
 # Round-trip tests : editors
 
@@ -145,6 +149,10 @@ enlarge-reduce-roundtrip.test
 cut-cat-roundtrip.test
 pamhue-roundtrip.test
 
+# Round-trip tests: miscellaneous utility
+
+pamexec-roundtrip.test
+
 # Round-trip tests : lossless converters
 
 ppmtoarbtxt-roundtrip.test
@@ -179,6 +187,7 @@ pi3-roundtrip.test
 pict-roundtrip.test
 png-roundtrip.test
 png-roundtrip2.test
+pj-roundtrip.test
 ps-roundtrip.test
 ps-flate-roundtrip.test
 ps-alt-roundtrip.test
diff --git a/test/pamendian-roundtrip.ok b/test/pamendian-roundtrip.ok
new file mode 100644
index 00000000..50450617
--- /dev/null
+++ b/test/pamendian-roundtrip.ok
@@ -0,0 +1,4 @@
+Test 1: Should print '0 0 0 : 0'
+0 0 0 : 0
+Test 2 should print echo '0 0 0 0 0 : 0'
+0 0 0 0 0 : 0
diff --git a/test/pamendian-roundtrip.test b/test/pamendian-roundtrip.test
new file mode 100755
index 00000000..aed03c76
--- /dev/null
+++ b/test/pamendian-roundtrip.test
@@ -0,0 +1,22 @@
+#! /bin/bash
+# This script tests: pamendian
+# Also requires: pamdepth pgmtopbm pamseq
+
+echo "Test 1: Should print '0 0 0 : 0'" 
+
+tmpdir=${tmpdir:-/tmp}
+test0_pam=${tmpdir}/test0.pam
+
+pamseq 1 65535 > ${test0_pam}
+pamendian < ${test0_pam} | pamendian |\
+  cmp -s ${test0_pam} -
+  echo ${PIPESTATUS[@]} ":" $?
+
+rm ${test0_pam}
+
+
+echo "Test 2 should print echo '0 0 0 0 0 : 0'" 
+
+pamdepth 65535 testgrid.pbm | pamendian | pamendian | \
+  pgmtopbm -th -val=0.5 | cmp -s - testgrid.pbm
+  echo ${PIPESTATUS[@]} ":" $?
\ No newline at end of file
diff --git a/test/pamexec-roundtrip.ok b/test/pamexec-roundtrip.ok
new file mode 100644
index 00000000..604ab5de
--- /dev/null
+++ b/test/pamexec-roundtrip.ok
@@ -0,0 +1,10 @@
+Test 1: should print stdin: PPM RAW 17 22 3 255 RGB six times
+stdin: PPM RAW 17 22 3 255 RGB
+stdin: PPM RAW 17 22 3 255 RGB
+stdin: PPM RAW 17 22 3 255 RGB
+stdin: PPM RAW 17 22 3 255 RGB
+stdin: PPM RAW 17 22 3 255 RGB
+stdin: PPM RAW 17 22 3 255 RGB
+Test 2: should print '0 0 : 0' twice
+0 0 : 0
+0 0 : 0
diff --git a/test/pamexec-roundtrip.test b/test/pamexec-roundtrip.test
new file mode 100755
index 00000000..fce7b6b5
--- /dev/null
+++ b/test/pamexec-roundtrip.test
@@ -0,0 +1,25 @@
+#! /bin/bash
+# This script tests: pamexec
+# Also requires: ppmpat ppmmake pamfile
+
+tmpdir=${tmpdir:-/tmp}
+test_ppm=${tmpdir}/test_ppm
+
+echo "Test 1: should print stdin: PPM RAW 17 22 3 255 RGB six times"
+
+( ppmmake rgb:0/255/127 17 22
+  ppmpat -g2 --color=rgb:143/188/143,rgb:161/161/161 17 22
+  ppmpat -g3 --color=rgb:224/255/255,rgb:255/130/171,rgb:255/48/48 17 22
+  ppmpat -madras --color=rgb:181/181/181,rgb:51/62/99,rgb:205/193/197 17 22
+  ppmpat -tartan --color=rgb:238/233/191,rgb:84/84/84,rgb:255/160/122 17 22
+  ppmpat -argyle2 --color=rgb:205/104/57,rgb:119/136/153,rgb:255/255/255 17 22
+) | tee ${test_ppm} | pamfile -all -machine
+
+echo "Test 2: should print '0 0 : 0' twice"
+
+pamexec "ppmtoppm " ${test_ppm} | cmp -s ${test_ppm} -  
+  echo ${PIPESTATUS[@]} ":" $?
+pamexec "cat " ${test_ppm} | cmp -s ${test_ppm} -  
+  echo ${PIPESTATUS[@]} ":" $?
+
+rm ${test_ppm}
diff --git a/test/pamexec.ok b/test/pamexec.ok
new file mode 100644
index 00000000..4bfa5202
--- /dev/null
+++ b/test/pamexec.ok
@@ -0,0 +1,10 @@
+Test 1 : Should print 10 stdin: PBM RAW 21 24 1 1 BLACKANDWHITE twice
+     10 stdin: PBM RAW 21 24 1 1 BLACKANDWHITE
+     10 stdin: PBM RAW 21 24 1 1 BLACKANDWHITE
+Test 2: Should print 1791121103 989 twice
+1791121103 989
+1791121103 989
+Test 3: Should print 2983705297 810 twice
+2983705297 810
+2983705297 810
+Test Invalid: Should not print anything
diff --git a/test/pamexec.test b/test/pamexec.test
new file mode 100755
index 00000000..acf162c3
--- /dev/null
+++ b/test/pamexec.test
@@ -0,0 +1,38 @@
+#! /bin/bash
+# This script tests: pamexec
+# Also requires: pbmtext pamfile pbmminkowski pbmtog3 g3topbm
+
+tmpdir=${tmpdir:-/tmp}
+test_pbm=${tmpdir}/test.pbm
+combined_pbm=${tmpdir}/combined.pbm
+
+for i in `seq 0 9`; do echo $i | pbmtext -builtin=fixed > ${test_pbm}$i; done
+cat ${test_pbm}[0123456789] > ${combined_pbm}
+
+echo "Test 1 : Should print 10 stdin: PBM RAW 21 24 1 1 BLACKANDWHITE twice"
+
+cat ${combined_pbm} | pamfile -all -mach | uniq -c 
+pamexec "pamfile -mach" ${combined_pbm}  | uniq -c
+
+echo "Test 2: Should print 1791121103 989 twice"
+
+for i in `seq 0 9`; do pbmminkowski ${test_pbm}$i   ; done | cksum
+pamexec "pbmminkowski" ${combined_pbm} | cksum
+
+rm ${test_pbm}[0123456789]
+
+echo "Test 3: Should print 2983705297 810 twice"
+
+pamexec "pbmtog3 -no | g3topbm" ${combined_pbm}  | cksum
+cat ${combined_pbm}  | cksum
+
+echo "Invalid command" 1>&2
+echo "Errors message should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+echo "Test Invalid: Should not print anything"
+
+pamexec "false" ${combined_pbm}
+pamexec "pamfile | false" ${combined_pbm}
+
+rm ${combined_pbm}
\ No newline at end of file
diff --git a/test/pamfix.ok b/test/pamfix.ok
new file mode 100644
index 00000000..7302f91e
--- /dev/null
+++ b/test/pamfix.ok
@@ -0,0 +1,68 @@
+Test 1
+P1
+5 5
+01010
+10101
+01010
+10101
+01010
+P1
+5 4
+01010
+10101
+01010
+00001
+P1
+5 4
+01010
+10101
+01010
+00001
+P1
+5 1
+01010
+Test 2
+P2
+3 3
+7
+0 1 2 
+3 4 5 
+6 7 0 
+P2
+3 2
+7
+0 1 2 
+3 4 5 
+P2
+3 2
+7
+0 1 2 
+3 4 5 
+P2
+3 3
+8
+0 1 2 
+3 4 5 
+6 7 8 
+P2
+3 3
+7
+0 1 2 
+3 4 5 
+6 7 7 
+P2
+3 3
+8
+0 1 2 
+3 4 8 
+0 0 0 
+P2
+3 3
+7
+0 1 2 
+3 4 7 
+0 0 0 
+Test invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
diff --git a/test/pamfix.test b/test/pamfix.test
new file mode 100755
index 00000000..e6021b56
--- /dev/null
+++ b/test/pamfix.test
@@ -0,0 +1,66 @@
+#! /bin/bash
+# This script tests: pamfix
+# Also requires:
+
+# Test 1.
+echo "Test 1"
+
+pbmmake -g 5 5 | pamfix -truncate -plain
+
+echo -e "P1\n5 5\n01010\n10101\n01010\n00001\n1" |\
+  pamfix -truncate -plain
+
+echo -e "P1\n5 5\n01010\n10101\n01010\n0000\n1" |\
+  pamfix -truncate -plain
+
+echo -e "P1\n5 5\n01010\n10102\n01010\n00001\n1" |\
+  pamfix -truncate -plain
+
+# Test 2
+
+echo "Test 2"
+
+echo -e "P2\n3 3\n7\n0 1 2\n3 4 5\n6 7 0" |\
+  pamfix -truncate -plain
+
+echo -e "P2\n3 3\n7\n0 1 2\n3 4 5\n6 7" |\
+  pamfix -truncate -plain
+echo -e "P2\n3 3\n7\n0 1 2\n3 4 5\n6 7 8" |\
+  pamfix -truncate -plain
+
+echo -e "P2\n3 3\n7\n0 1 2\n3 4 5\n6 7 8" |\
+  pamfix -change -plain
+
+echo -e "P2\n3 3\n7\n0 1 2\n3 4 5\n6 7 8" |\
+ pamfix -clip -plain
+
+echo -e "P2\n3 3\n7\n0 1 2\n3 4 8\n0 0 0" |\
+  pamfix -change -truncate -plain
+
+echo -e "P2\n3 3\n7\n0 1 2\n3 4 8\n0 0 0" |\
+  pamfix -clip -truncate -plain
+
+# Test Invalid
+
+echo "Test invalid"
+
+test_out=${tmpdir}/test_out
+
+echo 1>&2
+echo "Invalid command-line combination, invalid input" 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+echo -e "P2\n3 2\n7\n0 1 2\n6 7 8" | pamfix -change -clip > ${test_out} || \
+  echo -n "Expected failure 1";
+  test -s ${test_out}; echo " "$?
+
+echo -e "P1\n5 5" | pamfix -truncate -plain > ${test_out} || \
+  echo -n "Expected failure 2";
+  test -s ${test_out}; echo " "$?
+
+echo -e "P2\n3 3\255" | pamfix -truncate -plain > ${test_out} || \
+  echo -n "Expected failure 3";
+  test -s ${test_out}; echo " "$?
+
+rm ${test_out}
diff --git a/test/pamvalidate.ok b/test/pamvalidate.ok
new file mode 100644
index 00000000..98b0f70a
--- /dev/null
+++ b/test/pamvalidate.ok
@@ -0,0 +1,13 @@
+valid
+P1
+5 5
+01010
+10101
+01010
+00000
+11111
+not valid: Should print 0 four times
+0
+0
+0
+0
diff --git a/test/pamvalidate.test b/test/pamvalidate.test
new file mode 100755
index 00000000..46dd1bfa
--- /dev/null
+++ b/test/pamvalidate.test
@@ -0,0 +1,17 @@
+#! /bin/bash
+# This script tests: pamvalidate
+# Also requires:
+
+echo "valid"
+echo -e "P1\n5 5\n01010\n10101\n01010\n00000\n11111\n" | pamvalidate -plain
+
+echo "not valid: Should print 0 four times"
+echo -e "P1\n5 5\n01010\n10101\n01010\n00000\n1111\n"  | pamvalidate | wc -c
+
+echo -e "P1\n5 5\n01010\n10102\n01010\n00001\n11111\n" | pamvalidate | wc -c
+
+echo -e "P1\n5\n01010\n10101\n01010\n00000\n11111\n" | pamvalidate | wc -c
+
+echo -e "P1\n5 5" | pamvalidate | wc -c
+
+
diff --git a/test/pbmtext-iso88591.ok b/test/pbmtext-iso88591.ok
index b48fb277..842c435d 100644
--- a/test/pbmtext-iso88591.ok
+++ b/test/pbmtext-iso88591.ok
@@ -1,6 +1,6 @@
 Test 1
-3806607098 5110
-3806607098 5110
+2066913605 5110
+2066913605 5110
 Test 2
 2858870527 192
 2858870527 192
diff --git a/test/pbmtext-iso88591.test b/test/pbmtext-iso88591.test
index 96b286ac..69e6ec90 100755
--- a/test/pbmtext-iso88591.test
+++ b/test/pbmtext-iso88591.test
@@ -2,20 +2,13 @@
 # This script tests: pbmtext
 # Also requires:
 
-# This test requires the iconv command and an iso-8859-1 locale
-# Skip this test if they are not available
+# This test requires an iso-8859-1 locale
+# Skip this test if it is not available
 
 LANG=C
 LC_ALL=C
 export LANG LC_ALL
 
-iconv /dev/null
-if [ $? -ne 0  ]
-  then echo "iconv command not available." 1>&2
-       echo "Skipping." 1>&2
-       exit 80;
-fi
-
 tmpdir=${tmpdir:-/tmp}
 iso88591_locale_list=${tmpdir}/iso88591_locale_list
 
@@ -51,16 +44,15 @@ locale_for_test=${locale_to_test};
 
 
 # Two rows
-# Should print 3806607098 5110 twice
-
+# Should print 2066913605 5110 twice
 echo "Test 1"
 
 awk 'BEGIN { for (i=32; i<=126;++i) printf("%c",i); print ""; \
-             for (i=160;i<=255;++i) printf("%c",i); }' | \
+             for (i=161;i<=255;++i) printf("%c",i); }' | \
     pbmtext -builtin bdf | cksum
 
 awk 'BEGIN { for (i=32; i<=126;++i) printf("%c",i); print ""; \
-             for (i=160;i<=255;++i) printf("%c",i); }' | \
+             for (i=161;i<=255;++i) printf("%c",i); }' | \
     LC_ALL=${locale_for_test} pbmtext -builtin bdf -wchar | cksum
 
 
diff --git a/test/pbmtext-utf8.ok b/test/pbmtext-utf8.ok
index 4bc7b00d..84743a09 100644
--- a/test/pbmtext-utf8.ok
+++ b/test/pbmtext-utf8.ok
@@ -5,7 +5,7 @@ Test 2
 2920616515 2301
 2920616515 2301
 Test 3
-0 0 0 0 : 0
+0 0 0 : 0
 Test 4
  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
diff --git a/test/pbmtext-utf8.test b/test/pbmtext-utf8.test
index c92dd38a..1db7d849 100755
--- a/test/pbmtext-utf8.test
+++ b/test/pbmtext-utf8.test
@@ -7,8 +7,8 @@ LC_ALL=C
 export LANG LC_ALL
 
 
-# This test requires the iconv command and a working UTF-8 locale 
-# Skip this test if they are not available
+# This test requires a working UTF-8 locale 
+# Skip this test if it is are not available
 
 iconv /dev/null
 if [ $? -ne 0  ]
@@ -61,8 +61,8 @@ awk 'BEGIN { for (i=32; i<=126;++i) printf("%c",i); print ""; \
     pbmtext -builtin bdf | cksum
 
 awk 'BEGIN { for (i=32; i<=126;++i) printf("%c",i); print ""; \
-             for (i=161;i<=255;++i) printf("%c",i);  }' | \
-    iconv -f iso8859-1 -t utf-8 | \
+             for (i=161;i<=191;++i) printf("%c%c",194,i);     \
+             for (i=128;i<=191;++i) printf("%c%c",195,i); }' | \
     LC_ALL=${locale_for_test} pbmtext -builtin bdf -wchar | cksum
 
 
@@ -84,17 +84,18 @@ output=${tmpdir}/output
 # Test 3.
 # Two rows
 # Compare with cmp.
-# Should print 0
+# Should print 0 0 0 : 0
 
 echo "Test 3"
 
 awk 'BEGIN { for (i=32; i<=126;++i) printf("%c",i); print ""; \
-             for (i=161;i<=255;++i) printf("%c",i); print "" }' | \
-    iconv -f iso8859-1 -t utf-8 > ${output}
+             for (i=161;i<=191;++i) printf("%c%c",194,i);      \
+             for (i=128;i<=191;++i) printf("%c%c",195,i); print ""}' \
+    > ${output}
 
 awk 'BEGIN { for (i=32; i<=126;++i) printf("%c",i); print ""; \
-             for (i=161;i<=255;++i) printf("%c",i); print "" }' | \
-    iconv -f iso8859-1 -t utf-8 | \
+             for (i=161;i<=191;++i) printf("%c%c",194,i);      \
+             for (i=128;i<=191;++i) printf("%c%c",195,i); print ""}' | \
     LC_ALL=${locale_for_test} pbmtext -builtin bdf -wchar -text-dump | \
     cmp --quiet - ${output}
 
@@ -123,8 +124,7 @@ echo "Test 5 Invalid"
 long_txt=${tmpdir}/long.txt
 test_out=${tmpdir}/test_out
 
-head -c 4999 /dev/zero | tr '\0' '\276' | \
-  iconv -f iso-8859-1 -t utf-8 > ${long_txt}
+head -c 4999 /dev/zero | sed 's@\x00@\xc2\xbe@g' > ${long_txt}
 cat ${long_txt} | wc -c
 
 cat ${long_txt} | \
diff --git a/test/pj-roundtrip.ok b/test/pj-roundtrip.ok
new file mode 100644
index 00000000..a13b01a7
--- /dev/null
+++ b/test/pj-roundtrip.ok
@@ -0,0 +1,4 @@
+Test 1. Should print:  0 0 0 0 : 0
+0 0 0 0 : 0
+Test 2. Should print:  0 0 0 0 0 : 0
+0 0 0 0 0 : 0
diff --git a/test/pj-roundtrip.test b/test/pj-roundtrip.test
new file mode 100755
index 00000000..3394a4d2
--- /dev/null
+++ b/test/pj-roundtrip.test
@@ -0,0 +1,22 @@
+#! /bin/bash
+# This script tests: ppmtopj pjtoppm
+# Also requires: pamseq pnmremap pamtopnm pamdepth ppmtopgm pgmtopbm
+
+echo "Test 1. Should print:  0 0 0 0 : 0"
+
+tmpdir=${tmpdir:-/tmp}
+test8_ppm=${tmpdir}/testimg8.ppm
+
+pamseq 3 1 | pnmremap -map - testimg.ppm | pamtopnm -assume > ${test8_ppm}
+
+ppmtopj ${test8_ppm} | pjtoppm | pamdepth 1 | \
+  cmp -s - ${test8_ppm} > /dev/null
+  echo ${PIPESTATUS[@]} ":" $?
+
+rm ${test8_ppm}
+
+echo "Test 2. Should print:  0 0 0 0 0 : 0"
+
+ppmtopj testgrid.pbm | pjtoppm | ppmtopgm | pgmtopbm | \
+  cmp -s - testgrid.pbm > /dev/null
+  echo ${PIPESTATUS[@]} ":" $?
diff --git a/test/rawtoppm.ok b/test/rawtoppm.ok
new file mode 100644
index 00000000..c61e75aa
--- /dev/null
+++ b/test/rawtoppm.ok
@@ -0,0 +1,23 @@
+Test 1: should print '0 0 : 0'
+0 0 : 0
+Test 2: should print '0 0 : 0' five times
+0 0 : 0
+0 0 : 0
+0 0 : 0
+0 0 : 0
+0 0 : 0
+Test 3: should print '0 0 0 : 0' five times
+0 0 0 : 0
+0 0 0 : 0
+0 0 0 : 0
+0 0 0 : 0
+0 0 0 : 0
+Test 4
+P3
+5 5
+255
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 5  5 5 5  5 9 9  9 9 9
+0 1 2  3 4 0  1 2 3  4 0 1  2 3 4
+0 1 2  3 4 1  2 3 4  5 2 3  4 5 6
+9 8 7  6 5 4  3 2 1  0 0 0  0 0 0
diff --git a/test/rawtoppm.test b/test/rawtoppm.test
new file mode 100755
index 00000000..3c309259
--- /dev/null
+++ b/test/rawtoppm.test
@@ -0,0 +1,72 @@
+#! /bin/bash
+# This script tests: rawtoppm
+# Also requires: pamcut ppmtorgb3 rgb3toppm ppmtoppm
+
+# Test 1
+
+echo "Test 1: should print '0 0 : 0'"
+
+rawtoppm -headerskip 15 227 149 testimg.ppm | cmp -s - testimg.ppm
+  echo ${PIPESTATUS[@]} ":" $?
+
+# Test 2
+echo "Test 2: should print '0 0 : 0' five times"
+
+tmpdir=${tmpdir:-/tmp}
+test0_ppm=${tmpdir}/test0.ppm
+
+for i in 0 1 10 99 220
+  do
+  pamcut -cropright $i testimg.ppm > ${test0_ppm}
+  rawtoppm -headerskip 15 -rowskip $((i * 3)) $((227 - i)) 149 testimg.ppm | \
+  cmp -s ${test0_ppm} -
+  echo ${PIPESTATUS[@]} ":" $?
+  done  
+
+rm ${test0_ppm}
+
+
+# Test 3
+echo "Test 3: should print '0 0 0 : 0' five times"
+
+ppmtorgb3 testimg.ppm
+
+rgb3toppm testimg.red testimg.blu testimg.grn | \
+  rawtoppm -headerskip 15 -rbg 227 149  | cmp -s - testimg.ppm
+  echo ${PIPESTATUS[@]} ":" $?
+
+rgb3toppm testimg.grn testimg.red testimg.blu | \
+  rawtoppm -headerskip 15 -grb 227 149 | cmp -s - testimg.ppm
+  echo ${PIPESTATUS[@]} ":" $?
+
+rgb3toppm testimg.grn testimg.blu testimg.red | \
+  rawtoppm -headerskip 15 -gbr 227 149 | cmp -s - testimg.ppm
+  echo ${PIPESTATUS[@]} ":" $?
+
+rgb3toppm testimg.blu testimg.red testimg.grn | \
+  rawtoppm -headerskip 15 -brg 227 149 | cmp -s - testimg.ppm
+  echo ${PIPESTATUS[@]} ":" $?
+
+rgb3toppm testimg.blu testimg.grn testimg.red | \
+  rawtoppm -headerskip 15 -bgr 227 149 | cmp -s - testimg.ppm
+  echo ${PIPESTATUS[@]} ":" $?
+
+# Test 4
+echo "Test 4"
+
+test1_ppm=${tmpdir}/test1.ppm
+
+cat <<EOF > ${test1_ppm}
+P3
+5 5
+9
+0 0 0  0 0 0  0 0 0  0 0 0  0 0 0
+0 0 0  0 0 5  5 5 5  5 9 9  9 9 9
+0 1 2  3 4 0  1 2 3  4 0 1  2 3 4
+0 1 2  3 4 1  2 3 4  5 2 3  4 5 6
+9 8 7  6 5 4  3 2 1  0 0 0  0 0 0
+EOF
+
+ppmtoppm < ${test1_ppm} | rawtoppm -headerskip 9 5 5 -plain
+
+rm ${test1_ppm} testimg.red testimg.grn testimg.blu
diff --git a/urt/scanargs.c b/urt/scanargs.c
index f3af3342..1dcdd235 100644
--- a/urt/scanargs.c
+++ b/urt/scanargs.c
@@ -1,24 +1,24 @@
-/* 
+/*
  * $Id: scanargs.c,v 3.0.1.3 1992/02/27 21:18:14 spencer Exp $
- * 		Version 7 compatible
- * 	Argument scanner, scans argv style argument list.
- * 
- * 	Some stuff is a kludge because sscanf screws up
- * 
- * 	Gary Newman - 10/4/1979 - Ampex Corp. 
- * 
- * 	Modified by Spencer W. Thomas, Univ. of Utah, 5/81 to
- * 	add args introduced by 	a flag, add qscanargs call,
- * 	allow empty flags.
- * 
- * 	If you make improvements we'd like to get them too.
- * 	Jay Lepreau	lepreau@utah-20, decvax!harpo!utah-cs!lepreau
- * 	Spencer Thomas	thomas@utah-20, decvax!harpo!utah-cs!thomas 
- * 
- *	(I know the code is ugly, but it just grew, you see ...)
- * 
- * Modified by:	Spencer W. Thomas
- * 	Date:	Feb 25 1983
+ *              Version 7 compatible
+ *      Argument scanner, scans argv style argument list.
+ *
+ *      Some stuff is a kludge because sscanf screws up
+ *
+ *      Gary Newman - 10/4/1979 - Ampex Corp.
+ *
+ *      Modified by Spencer W. Thomas, Univ. of Utah, 5/81 to
+ *      add args introduced by  a flag, add qscanargs call,
+ *      allow empty flags.
+ *
+ *      If you make improvements we'd like to get them too.
+ *      Jay Lepreau     lepreau@utah-20, decvax!harpo!utah-cs!lepreau
+ *      Spencer Thomas  thomas@utah-20, decvax!harpo!utah-cs!thomas
+ *
+ *      (I know the code is ugly, but it just grew, you see ...)
+ *
+ * Modified by: Spencer W. Thomas
+ *      Date:   Feb 25 1983
  * 1. Fixed scanning of optional args.  Now args introduced by a flag
  *    must follow the flag which introduces them and precede any other
  *    flag argument.  It is still possible for a flag introduced
@@ -26,11 +26,11 @@
  *    earlier in the format string.  This implies that flags may not
  *    be conditional upon other flags, and a message will be generated
  *    if this is attempted.
- * 
+ *
  * 2. Usage message can be formatted by inserting newlines, tabs and
  *    spaces into the format string.  This is especially useful for
  *    long argument lists.
- * 
+ *
  * 3. Added n/N types for "numeric" args.  These args are scanned
  *    using the C language conventions - a number starting 0x is
  *    hexadecimal, a number starting with 0 is octal, otherwise it is
@@ -49,7 +49,7 @@
 #include "rle_config.h"
 #include "rle.h"
 
-/* 
+/*
  * An explicit assumption is made in this code that all pointers look
  * alike, except possible char * pointers.
  */
@@ -59,19 +59,19 @@ typedef int *ptr;
 #define NO 0
 #define ERROR(msg)  {fprintf(stderr, "%s\n", msg); goto error; }
 
-/* 
+/*
  * Storage allocation macros
  */
-#define NEW( type, cnt )	(type *) malloc( (cnt) * sizeof( type ) )
-#define RENEW( type, ptr, cnt )	(type *) realloc( ptr, (cnt) * sizeof( type ) )
+#define NEW( type, cnt )        (type *) malloc( (cnt) * sizeof( type ) )
+#define RENEW( type, ptr, cnt ) (type *) realloc( ptr, (cnt) * sizeof( type ) )
 
 static CONST_DECL char * prformat( CONST_DECL char *, int );
 static int isnum( CONST_DECL char *, int, int );
-static int	_do_scanargs( int argc, char **argv, CONST_DECL char *format,
-			      va_list argl );
-void		scan_usage( char **, CONST_DECL char * );
+static int      _do_scanargs( int argc, char **argv, CONST_DECL char *format,
+                              va_list argl );
+void            scan_usage( char **, CONST_DECL char * );
 
-/* 
+/*
  * Argument list is (argc, argv, format, ... )
  */
 int
@@ -84,8 +84,8 @@ scanargs ( int argc, char **argv, CONST_DECL char *format, ... )
     va_end( argl );
     return retval;
 }
-    
-/* 
+
+/*
  * This routine is necessary because of a pyramid compiler botch that
  * uses parameter registers in a varargs routine.  The extra
  * subroutine call isolates the args on the register stack so they
@@ -94,583 +94,583 @@ scanargs ( int argc, char **argv, CONST_DECL char *format, ... )
 
 static int
 _do_scanargs( argc, argv, format, argl )
-int     argc;			/* Actual arguments */
+int     argc;                   /* Actual arguments */
 char  **argv;
 CONST_DECL char   *format;
 va_list argl;
 {
 
-    int    check;			/* check counter to be sure all argvs
-					   are processed */
+    int    check;                       /* check counter to be sure all argvs
+                                           are processed */
     register CONST_DECL char  *cp;
     int    cnt;
-    int	    optarg = 0;			/* where optional args start */
-    int	    nopt = 0;
-    char    tmpflg,			/* temp flag */
-	    typchr;			/* type char from format string */
+    int     optarg = 0;                 /* where optional args start */
+    int     nopt = 0;
+    char    tmpflg,                     /* temp flag */
+            typchr;                     /* type char from format string */
     char    c;
-    bool  * arg_used;			/* array of flags */
-    ptr	    aptr = 0;			/* pointer to return loc */
+    bool  * arg_used;                   /* array of flags */
+    ptr     aptr = 0;                   /* pointer to return loc */
 
     bool    required;
-    int	    excnt;			/* which flag is set */
-    bool    exflag;			/* when set, one of a set of exclusive
-					   flags is set */
-
-    bool    list_of;			/* set if parsing off a list of args */
-    bool    comma_list;			/* set if AT&T style multiple args */
-    bool    no_usage;			/* If set, don't print usage msg. */
-    bool    help = NO;			/* If set, always print usage. */
-    int	  * cnt_arg = 0;		/* where to stuff list count */
-    int	    list_cnt;			/* how many in list */
+    int     excnt;                      /* which flag is set */
+    unsigned int exflag;                /* How many of a set of exclusive
+                                           flags is set */
+
+    bool    list_of;                    /* set if parsing off a list of args */
+    bool    comma_list;                 /* set if AT&T style multiple args */
+    bool    no_usage;                   /* If set, don't print usage msg. */
+    bool    help = NO;                  /* If set, always print usage. */
+    int   * cnt_arg = 0;                /* where to stuff list count */
+    int     list_cnt;                   /* how many in list */
     /* These are used to build return lists */
     char ** strlist = 0;
     int   * intlist = 0;
     long  * longlist = 0;
     float * fltlist = 0;
     double *dbllist = 0;
-    char  * argp;			/* Pointer to argument. */
+    char  * argp;                       /* Pointer to argument. */
 
-    CONST_DECL char   *ncp;		/* remember cp during flag scanning */
-    static char   cntrl[7] = "%  %1s";	/* control string for scanf's */
-    char    junk[2];			/* junk buffer for scanf's */
+    CONST_DECL char   *ncp;             /* remember cp during flag scanning */
+    static char   cntrl[7] = "%  %1s";  /* control string for scanf's */
+    char    junk[2];                    /* junk buffer for scanf's */
 
     /* Set up for argument counting. */
     arg_used = NEW( bool, argc );
     if (arg_used == NULL)
     {
-	fprintf(stderr, "malloc failed in scanargs, exiting\n");
-	exit(-1);
+        fprintf(stderr, "malloc failed in scanargs, exiting\n");
+        exit(-1);
     }
     else
     {
-	for (cnt=0; cnt<argc; cnt++)
-	    arg_used[cnt] = NO;
+        for (cnt=0; cnt<argc; cnt++)
+            arg_used[cnt] = NO;
     }
     check = 0;
 
     /* Scan for -help in arg list. */
     for ( cnt=1; cnt<argc; cnt++ )
-	if ( strcmp( argv[cnt], "-help" ) == 0 )
-	{
-	    check += cnt;
-	    arg_used[cnt] = YES;
-	    if ( argc == 2 )
-	    {
-		scan_usage( argv, format );
-		return 0;
-	    }
-	    else
-		help = YES;
-	}
+        if ( strcmp( argv[cnt], "-help" ) == 0 )
+        {
+            check += cnt;
+            arg_used[cnt] = YES;
+            if ( argc == 2 )
+            {
+                scan_usage( argv, format );
+                return 0;
+            }
+            else
+                help = YES;
+        }
 
     /* If format string ends in @, don't print a usage message. */
     no_usage = *(format + strlen( format ) - 1) == '&';
 
     cp = format;
-    /* 
+    /*
      * Skip program name
      */
     while ( *cp != ' ' && *cp != '\t' && *cp != '\n' && *cp != '\0' )
-	cp++;
+        cp++;
 
     while (*cp)
     {
-	required = NO;			/* reset per-arg flags */
-	list_of = NO;
-	comma_list = NO;
-	list_cnt = 0;
-	switch (*(cp++))
-	{
-	    default: 			/* all other chars */
-		break;
-	    case ' ':			/* separators */
-	    case '\t':
-	    case '\n':
-		optarg = 0;		/* end of optional arg string */
-		break;
-
-	    case '(':			/* Surrounds a comment. */
-	    {
-		int depth = 1;		/* Count parenthesis depth. */
-		while ( *cp && depth > 0 )
-		    switch ( *(cp++) )
-		    {
-		    case '(':	depth++;		break;
-		    case ')':	depth--;		break;
-		    }
-		break;
-	    }
-
-	    case '!': 			/* required argument */
-		required = YES;
-	    case '%': 			/* not required argument */
-reswitch:				/* after finding '*' or ',' */
-		switch (typchr = *(cp++))
-		{
-		    case ',':		/* argument is AT&T list of things */
-			comma_list = YES;
-		    case '*':		/* argument is list of things */
-			list_of = YES;
-			list_cnt = 0;	/* none yet */
-			cnt_arg = va_arg( argl, int *);	/* item count * here */
-			goto reswitch;	/* try again */
-
-		    case '$':		/* "rest" of argument list */
-			while ( argc > 1 && !arg_used[argc-1] )
-			    argc--;	/* find last used argument */
-			*va_arg( argl, int * ) = argc;
-			break;
-
-		    case '&':		/* Return unused args. */
-			/* Count how many.  Always include argv[0]. */
-			for ( nopt = cnt = 1; cnt < argc; cnt++ )
-			    if ( !arg_used[cnt] )
-				nopt++;
-			if ( nopt == 1 )
-			    nopt = 0;	/* Special case for no args. */
-			if ( nopt > 0 )
-			{
-			    strlist = NEW( char *, nopt + 1 );
-			    /* Copy program name, for sure. */
-			    strlist[0] = argv[0];
-			    for ( nopt = cnt = 1; cnt < argc; cnt++ )
-				if ( !arg_used[cnt] )
-				{
-				    strlist[nopt++] = argv[cnt];
-				    check += cnt;
-				    arg_used[cnt] = 1;
-				}
-			    strlist[nopt] = NULL;
-			}
-			else
-			    strlist = NULL;	/* No args, return empty. */
-
-			/* Return count and arg list. */
-			*va_arg( argl, int * ) = nopt;
-			*va_arg( argl, char *** ) = strlist;
-			break;
-
-		    case '-': 		/* argument is flag */
-			if (optarg > 0)
-			    ERROR("Format error: flag conditional on flag not allowed");
-
-		    /* go back to label */
-			ncp = cp-1;	/* remember */
-			cp -= 3;
-			for (excnt = exflag = 0
-				; *cp != ' ' && !(*cp=='-' &&(cp[-1]=='!'||cp[-1]=='%'));
-				(--cp, excnt++))
-			{
-			    for (cnt = optarg+1; cnt < argc; cnt++)
-			    {
-			    /* flags all start with - */
-				if (*argv[cnt] == '-' && !arg_used[cnt] &&
-					!ISDIGIT(argv[cnt][1]))
-				    if (*(argv[cnt] + 1) == *cp)
-				    {
-					if (*(argv[cnt] + 2) != 0)
-					    ERROR ("extra flags ignored");
-					if (exflag)
-					    ERROR ("more than one exclusive flag chosen");
-					exflag++;
-					required = NO;
-					check += cnt;
-					arg_used[cnt] = 1;
-					nopt = cnt;
-					*va_arg( argl, int *) |= (1 << excnt);
-					break;
-				    }
-			    }
-			}
-			if (required)
-			    ERROR ("flag argument missing");
-			cp = ncp;
-			/* 
-			 * If none of these flags were found, skip any
-			 * optional arguments (in the varargs list, too).
-			 */
-			if (!exflag)
-			{
-			    (void)va_arg( argl, int * );/* skip the arg, too */
-			    while (*++cp && ! ISSPACE(*cp))
-				if (*cp == '!' || *cp == '%')
-				{
-				    if ( *++cp == '*' || *cp == ',' )
-				    {
-					cp++;
-					(void)va_arg( argl, int * );
-				    }
-				    /* 
-				     * Assume that char * might be a
-				     * different size, but that all
-				     * other pointers are same size.
-				     */
-				    if ( *cp == 's' )
-					(void)va_arg( argl, char * );
-				    else
-					(void)va_arg( argl, ptr );
-				}
-			}
-			else
-			{
-			    optarg = nopt;
-			    cp++;	/* skip over - */
-			}
-
-			break;
-
-		    case 's': 		/* char string */
-		    case 'd': 		/* decimal # */
-		    case 'o': 		/* octal # */
-		    case 'x': 		/* hexadecimal # */
-		    case 'n':		/* "number" in C syntax */
-		    case 'f': 		/* floating # */
-		    case 'D': 		/* long decimal # */
-		    case 'O': 		/* long octal # */
-		    case 'X': 		/* long hexadecimal # */
-		    case 'N':		/* long number in C syntax */
-		    case 'F': 		/* double precision floating # */
+        required = NO;                  /* reset per-arg flags */
+        list_of = NO;
+        comma_list = NO;
+        list_cnt = 0;
+        switch (*(cp++))
+        {
+            default:                    /* all other chars */
+                break;
+            case ' ':                   /* separators */
+            case '\t':
+            case '\n':
+                optarg = 0;             /* end of optional arg string */
+                break;
+
+            case '(':                   /* Surrounds a comment. */
+            {
+                int depth = 1;          /* Count parenthesis depth. */
+                while ( *cp && depth > 0 )
+                    switch ( *(cp++) )
+                    {
+                    case '(':   depth++;                break;
+                    case ')':   depth--;                break;
+                    }
+                break;
+            }
+
+            case '!':                   /* required argument */
+                required = YES;
+            case '%':                   /* not required argument */
+reswitch:                               /* after finding '*' or ',' */
+                switch (typchr = *(cp++))
+                {
+                    case ',':           /* argument is AT&T list of things */
+                        comma_list = YES;
+                    case '*':           /* argument is list of things */
+                        list_of = YES;
+                        list_cnt = 0;   /* none yet */
+                        cnt_arg = va_arg( argl, int *); /* item count * here */
+                        goto reswitch;  /* try again */
+
+                    case '$':           /* "rest" of argument list */
+                        while ( argc > 1 && !arg_used[argc-1] )
+                            argc--;     /* find last used argument */
+                        *va_arg( argl, int * ) = argc;
+                        break;
+
+                    case '&':           /* Return unused args. */
+                        /* Count how many.  Always include argv[0]. */
+                        for ( nopt = cnt = 1; cnt < argc; cnt++ )
+                            if ( !arg_used[cnt] )
+                                nopt++;
+                        if ( nopt == 1 )
+                            nopt = 0;   /* Special case for no args. */
+                        if ( nopt > 0 )
+                        {
+                            strlist = NEW( char *, nopt + 1 );
+                            /* Copy program name, for sure. */
+                            strlist[0] = argv[0];
+                            for ( nopt = cnt = 1; cnt < argc; cnt++ )
+                                if ( !arg_used[cnt] )
+                                {
+                                    strlist[nopt++] = argv[cnt];
+                                    check += cnt;
+                                    arg_used[cnt] = 1;
+                                }
+                            strlist[nopt] = NULL;
+                        }
+                        else
+                            strlist = NULL;     /* No args, return empty. */
+
+                        /* Return count and arg list. */
+                        *va_arg( argl, int * ) = nopt;
+                        *va_arg( argl, char *** ) = strlist;
+                        break;
+
+                    case '-':           /* argument is flag */
+                        if (optarg > 0)
+                            ERROR("Format error: flag conditional on flag not allowed");
+
+                    /* go back to label */
+                        ncp = cp-1;     /* remember */
+                        cp -= 3;
+                        for (excnt = exflag = 0
+                                ; *cp != ' ' && !(*cp=='-' &&(cp[-1]=='!'||cp[-1]=='%'));
+                                (--cp, excnt++))
+                        {
+                            for (cnt = optarg+1; cnt < argc; cnt++)
+                            {
+                            /* flags all start with - */
+                                if (*argv[cnt] == '-' && !arg_used[cnt] &&
+                                        !ISDIGIT(argv[cnt][1]))
+                                    if (*(argv[cnt] + 1) == *cp)
+                                    {
+                                        if (*(argv[cnt] + 2) != 0)
+                                            ERROR ("extra flags ignored");
+                                        if (exflag)
+                                            ERROR ("more than one exclusive flag chosen");
+                                        exflag++;
+                                        required = NO;
+                                        check += cnt;
+                                        arg_used[cnt] = 1;
+                                        nopt = cnt;
+                                        *va_arg( argl, int *) |= (1 << excnt);
+                                        break;
+                                    }
+                            }
+                        }
+                        if (required)
+                            ERROR ("flag argument missing");
+                        cp = ncp;
+                        /*
+                         * If none of these flags were found, skip any
+                         * optional arguments (in the varargs list, too).
+                         */
+                        if (!exflag)
+                        {
+                            (void)va_arg( argl, int * );/* skip the arg, too */
+                            while (*++cp && ! ISSPACE(*cp))
+                                if (*cp == '!' || *cp == '%')
+                                {
+                                    if ( *++cp == '*' || *cp == ',' )
+                                    {
+                                        cp++;
+                                        (void)va_arg( argl, int * );
+                                    }
+                                    /*
+                                     * Assume that char * might be a
+                                     * different size, but that all
+                                     * other pointers are same size.
+                                     */
+                                    if ( *cp == 's' )
+                                        (void)va_arg( argl, char * );
+                                    else
+                                        (void)va_arg( argl, ptr );
+                                }
+                        }
+                        else
+                        {
+                            optarg = nopt;
+                            cp++;       /* skip over - */
+                        }
+
+                        break;
+
+                    case 's':           /* char string */
+                    case 'd':           /* decimal # */
+                    case 'o':           /* octal # */
+                    case 'x':           /* hexadecimal # */
+                    case 'n':           /* "number" in C syntax */
+                    case 'f':           /* floating # */
+                    case 'D':           /* long decimal # */
+                    case 'O':           /* long octal # */
+                    case 'X':           /* long hexadecimal # */
+                    case 'N':           /* long number in C syntax */
+                    case 'F':           /* double precision floating # */
 #if defined(sgi) && !defined(mips)
-			/* Fix for broken SGI IRIS 2400/3000 floats */
-			if ( typchr == 'F' ) typchr = 'f';
+                        /* Fix for broken SGI IRIS 2400/3000 floats */
+                        if ( typchr == 'F' ) typchr = 'f';
 #endif /* sgi */
-			for (cnt = optarg+1; cnt < argc; cnt++)
-			{
-			    argp = argv[cnt];
-
-			    if ( isnum( argp, typchr, comma_list ) )
-			    {
-				;	/* it's ok, then */
-			    }
-			    else if ( *argp == '-' && argp[1] != '\0' )
-				if ( optarg > 0 ) /* end optional args? */
-				{
-				    /* Eat the arg, too, if necessary */
-				    if ( list_cnt == 0 ) {
-					if ( typchr == 's' )
-					    (void)va_arg( argl, char * );
-					else
-					    (void)va_arg( argl, ptr );
+                        for (cnt = optarg+1; cnt < argc; cnt++)
+                        {
+                            argp = argv[cnt];
+
+                            if ( isnum( argp, typchr, comma_list ) )
+                            {
+                                ;       /* it's ok, then */
+                            }
+                            else if ( *argp == '-' && argp[1] != '\0' )
+                                if ( optarg > 0 ) /* end optional args? */
+                                {
+                                    /* Eat the arg, too, if necessary */
+                                    if ( list_cnt == 0 ) {
+                                        if ( typchr == 's' )
+                                            (void)va_arg( argl, char * );
+                                        else
+                                            (void)va_arg( argl, ptr );
                     }
-				    break;
-				}
-				else
-				    continue;
-			    else if ( typchr != 's' )
-				continue;	/* not number, keep looking */
-			    
-			    /* 
-			     * Otherwise usable argument may already
-			     * be used.  (Must check this after
-			     * checking for flag, though.)
-			     */
-			    if (arg_used[cnt]) continue;
-
-			    /* 
-			     * If it's a comma-and-or-space-separated
-			     * list then count how many, and separate
-			     * the list into an array of strings.
-			     */
-			    if ( comma_list )
-			    {
-				register char * s;
-				int pass;
-
-				/*
-				 * Copy the string so we remain nondestructive
-				 */
-				s = NEW( char, strlen(argp)+1 );
-				strcpy( s, argp );
-				argp = s;
-
-				/* 
-				 * On pass 0, just count them.  On
-				 * pass 1, null terminate each string 
-				 */
-				for ( pass = 0; pass <= 1; pass++ )
-				{
-				    for ( s = argp; *s != '\0'; )
-				    {
-					if ( pass )
-					    strlist[list_cnt] = s;
-					while ( (c = *s) != '\0' && c != ' ' &&
-						c != '\t' && c != ',' )
-					    s++;
-					if ( pass )
-					    *s = '\0';
-
-					list_cnt++;	/* count separators */
-					/* 
-					 * Two commas in a row give a null
-					 * string, but two spaces
-					 * don't.  Also skip spaces
-					 * after a comma.
-					 */
-					if ( c != '\0' )
-					    while ( *++s == ' ' || *s == '\t' )
-						;
-				    }
-				    if ( pass == 0 )
-				    {
-					strlist = NEW( char *, list_cnt );
-					list_cnt = 0;
-				    }
-				}
-			    }
-			    else if ( list_of )
-				list_cnt++;   /* getting them one at a time */
-			    /* 
-			     * If it's either type of list, then alloc
-			     * storage space for the returned values
-			     * (except that comma-separated string
-			     * lists already are done).
-			     */
-			    if ( list_of )
-			    {
-				if ( list_cnt == 1 || comma_list )
-				    switch( typchr )
-				    {
-					case 's':
-					    if ( !comma_list )
-						strlist = NEW( char *, 1 );
-					    aptr = (ptr) &strlist[0];
-					    break;
-					case 'n':
-					case 'd':
-					case 'o':
-					case 'x':
-					    intlist = NEW( int, list_cnt );
-					    aptr = (ptr) &intlist[0];
-					    break;
-					case 'N':
-					case 'D':
-					case 'O':
-					case 'X':
-					    longlist = NEW( long, list_cnt );
-					    aptr = (ptr) &longlist[0];
-					    break;
-					case 'f':
-					    fltlist = NEW( float, list_cnt );
-					    aptr = (ptr) &fltlist[0];
-					    break;
-					case 'F':
-					    dbllist = NEW( double, list_cnt );
-					    aptr = (ptr) &dbllist[0];
-					    break;
-				    }
-				else
-				    switch( typchr )
-				    {
-					case 's':
-					    strlist = RENEW( char *, strlist,
-							     list_cnt );
-					    aptr = (ptr) &strlist[list_cnt-1];
-					    break;
-					case 'n':
-					case 'd':
-					case 'o':
-					case 'x':
-					    intlist = RENEW( int, intlist,
-							     list_cnt );
-					    aptr = (ptr) &intlist[list_cnt-1];
-					    break;
-					case 'N':
-					case 'D':
-					case 'O':
-					case 'X':
-					    longlist = RENEW( long, longlist,
-							      list_cnt );
-					    aptr = (ptr) &longlist[list_cnt-1];
-					    break;
-					case 'f':
-					    fltlist = RENEW( float, fltlist,
-							     list_cnt );
-					    aptr = (ptr) &fltlist[list_cnt-1];
-					    break;
-					case 'F':
-					    dbllist = RENEW( double, dbllist,
-							     list_cnt );
-					    aptr = (ptr) &dbllist[list_cnt-1];
-					    break;
-				    }
-			    }
-			    else
-				aptr = va_arg( argl, ptr );
-
-			    if ( typchr == 's' )
-			    {
-				if ( ! comma_list )
-				    *(char **)aptr = argp;
-			    }
-			    else
-			    {
-				nopt = 0;
-				do {
-				    /* 
-				     * Need to update aptr if parsing
-				     * a comma list
-				     */
-				    if ( comma_list && nopt > 0 )
-				    {
-					argp = strlist[nopt];
-					switch( typchr )
-					{
-					    case 'n':
-					    case 'd':
-					    case 'o':
-					    case 'x':
-						aptr = (ptr) &intlist[nopt];
-						break;
-					    case 'N':
-					    case 'D':
-					    case 'O':
-					    case 'X':
-						aptr = (ptr) &longlist[nopt];
-						break;
-					    case 'f':
-						aptr = (ptr) &fltlist[nopt];
-						break;
-					    case 'F':
-						aptr = (ptr) &dbllist[nopt];
-						break;
-					}
-				    }
-				    /* 
-				     * Do conversion for n and N types
-				     */
-				    tmpflg = typchr;
-				    if (typchr == 'n' || typchr == 'N' ) {
-					if (*argp != '0')
-					    tmpflg = 'd';
-					else if (*(argp+1) == 'x' ||
-						 *(argp+1) == 'X')
-					{
-					    tmpflg = 'x';
-					    argp += 2;
-					}
-					else
-					    tmpflg = 'o';
+                                    break;
+                                }
+                                else
+                                    continue;
+                            else if ( typchr != 's' )
+                                continue;       /* not number, keep looking */
+
+                            /*
+                             * Otherwise usable argument may already
+                             * be used.  (Must check this after
+                             * checking for flag, though.)
+                             */
+                            if (arg_used[cnt]) continue;
+
+                            /*
+                             * If it's a comma-and-or-space-separated
+                             * list then count how many, and separate
+                             * the list into an array of strings.
+                             */
+                            if ( comma_list )
+                            {
+                                register char * s;
+                                int pass;
+
+                                /*
+                                 * Copy the string so we remain nondestructive
+                                 */
+                                s = NEW( char, strlen(argp)+1 );
+                                strcpy( s, argp );
+                                argp = s;
+
+                                /*
+                                 * On pass 0, just count them.  On
+                                 * pass 1, null terminate each string
+                                 */
+                                for ( pass = 0; pass <= 1; pass++ )
+                                {
+                                    for ( s = argp; *s != '\0'; )
+                                    {
+                                        if ( pass )
+                                            strlist[list_cnt] = s;
+                                        while ( (c = *s) != '\0' && c != ' ' &&
+                                                c != '\t' && c != ',' )
+                                            s++;
+                                        if ( pass )
+                                            *s = '\0';
+
+                                        list_cnt++;     /* count separators */
+                                        /*
+                                         * Two commas in a row give a null
+                                         * string, but two spaces
+                                         * don't.  Also skip spaces
+                                         * after a comma.
+                                         */
+                                        if ( c != '\0' )
+                                            while ( *++s == ' ' || *s == '\t' )
+                                                ;
+                                    }
+                                    if ( pass == 0 )
+                                    {
+                                        strlist = NEW( char *, list_cnt );
+                                        list_cnt = 0;
+                                    }
+                                }
+                            }
+                            else if ( list_of )
+                                list_cnt++;   /* getting them one at a time */
+                            /*
+                             * If it's either type of list, then alloc
+                             * storage space for the returned values
+                             * (except that comma-separated string
+                             * lists already are done).
+                             */
+                            if ( list_of )
+                            {
+                                if ( list_cnt == 1 || comma_list )
+                                    switch( typchr )
+                                    {
+                                        case 's':
+                                            if ( !comma_list )
+                                                strlist = NEW( char *, 1 );
+                                            aptr = (ptr) &strlist[0];
+                                            break;
+                                        case 'n':
+                                        case 'd':
+                                        case 'o':
+                                        case 'x':
+                                            intlist = NEW( int, list_cnt );
+                                            aptr = (ptr) &intlist[0];
+                                            break;
+                                        case 'N':
+                                        case 'D':
+                                        case 'O':
+                                        case 'X':
+                                            longlist = NEW( long, list_cnt );
+                                            aptr = (ptr) &longlist[0];
+                                            break;
+                                        case 'f':
+                                            fltlist = NEW( float, list_cnt );
+                                            aptr = (ptr) &fltlist[0];
+                                            break;
+                                        case 'F':
+                                            dbllist = NEW( double, list_cnt );
+                                            aptr = (ptr) &dbllist[0];
+                                            break;
+                                    }
+                                else
+                                    switch( typchr )
+                                    {
+                                        case 's':
+                                            strlist = RENEW( char *, strlist,
+                                                             list_cnt );
+                                            aptr = (ptr) &strlist[list_cnt-1];
+                                            break;
+                                        case 'n':
+                                        case 'd':
+                                        case 'o':
+                                        case 'x':
+                                            intlist = RENEW( int, intlist,
+                                                             list_cnt );
+                                            aptr = (ptr) &intlist[list_cnt-1];
+                                            break;
+                                        case 'N':
+                                        case 'D':
+                                        case 'O':
+                                        case 'X':
+                                            longlist = RENEW( long, longlist,
+                                                              list_cnt );
+                                            aptr = (ptr) &longlist[list_cnt-1];
+                                            break;
+                                        case 'f':
+                                            fltlist = RENEW( float, fltlist,
+                                                             list_cnt );
+                                            aptr = (ptr) &fltlist[list_cnt-1];
+                                            break;
+                                        case 'F':
+                                            dbllist = RENEW( double, dbllist,
+                                                             list_cnt );
+                                            aptr = (ptr) &dbllist[list_cnt-1];
+                                            break;
+                                    }
+                            }
+                            else
+                                aptr = va_arg( argl, ptr );
+
+                            if ( typchr == 's' )
+                            {
+                                if ( ! comma_list )
+                                    *(char **)aptr = argp;
+                            }
+                            else
+                            {
+                                nopt = 0;
+                                do {
+                                    /*
+                                     * Need to update aptr if parsing
+                                     * a comma list
+                                     */
+                                    if ( comma_list && nopt > 0 )
+                                    {
+                                        argp = strlist[nopt];
+                                        switch( typchr )
+                                        {
+                                            case 'n':
+                                            case 'd':
+                                            case 'o':
+                                            case 'x':
+                                                aptr = (ptr) &intlist[nopt];
+                                                break;
+                                            case 'N':
+                                            case 'D':
+                                            case 'O':
+                                            case 'X':
+                                                aptr = (ptr) &longlist[nopt];
+                                                break;
+                                            case 'f':
+                                                aptr = (ptr) &fltlist[nopt];
+                                                break;
+                                            case 'F':
+                                                aptr = (ptr) &dbllist[nopt];
+                                                break;
+                                        }
+                                    }
+                                    /*
+                                     * Do conversion for n and N types
+                                     */
+                                    tmpflg = typchr;
+                                    if (typchr == 'n' || typchr == 'N' ) {
+                                        if (*argp != '0')
+                                            tmpflg = 'd';
+                                        else if (*(argp+1) == 'x' ||
+                                                 *(argp+1) == 'X')
+                                        {
+                                            tmpflg = 'x';
+                                            argp += 2;
+                                        }
+                                        else
+                                            tmpflg = 'o';
                     }
-				    if (typchr == 'N')
-					tmpflg = toupper( tmpflg );
-
-
-				    /* put in conversion */
-				    if ( isupper( tmpflg ) )
-				    {
-					cntrl[1] = 'l';
-					cntrl[2] = tolower( tmpflg );
-				    }
-				    else
-				    {
-					cntrl[1] = tmpflg;
-					cntrl[2] = ' ';
-				    }
-				    if (sscanf (argp, cntrl, aptr, junk) != 1)
-					ERROR ("Bad numeric argument");
-				} while ( comma_list && ++nopt < list_cnt );
-			    }
-			    check += cnt;
-			    arg_used[cnt] = 1;
-			    required = NO;
-			    /*
-			     * If not looking for multiple args,
-			     * then done, otherwise, keep looking.
-			     */
-			    if ( !( list_of && !comma_list ) )
-				break;
-			    else
-				continue;
-			}
-			if (required)
-			    switch (typchr)
-			    {
-				case 'x': 
-				case 'X': 
-				    ERROR ("missing hexadecimal argument");
-				case 's': 
-				    ERROR ("missing string argument");
-				case 'o': 
-				case 'O': 
-				    ERROR ("missing octal argument");
-				case 'd': 
-				case 'D': 
-				    ERROR ("missing decimal argument");
-				case 'f': 
-				case 'F': 
-				    ERROR ("missing floating argument");
-				case 'n':
-				case 'N':
-				    ERROR ("missing numeric argument");
-			    }
-			if ( list_cnt > 0 )
-			{
-			    *cnt_arg = list_cnt;
-			    switch ( typchr )
-			    {
-				case 's':
-				    *va_arg( argl, char *** ) = strlist;
-				    break;
-				case 'n':
-				case 'd':
-				case 'o':
-				case 'x':
-				    *va_arg( argl, int ** ) = intlist;
-				    break;
-				case 'N':
-				case 'D':
-				case 'O':
-				case 'X':
-				    *va_arg( argl, long ** ) = longlist;
-				    break;
-				case 'f':
-				    *va_arg( argl, float ** ) = fltlist;
-				    break;
-				case 'F':
-				    *va_arg( argl, double **) = dbllist;
-				    break;
-			    }
-			    if ( typchr != 's' && comma_list )
-				free( (char *) strlist );
-			}
-			else if ( cnt >= argc )
-			{
-			    /* Fell off end looking, so must eat the arg */
-			    if ( typchr == 's' )
-				(void)va_arg( argl, char * );
-			    else
-				(void)va_arg( argl, ptr );
-			}
-			break;
-		    default: 		/* error */
-			fprintf (stderr,
-				 "scanargs: Corrupt or invalid format spec\n");
-			return 0;
-		}
-	}
+                                    if (typchr == 'N')
+                                        tmpflg = toupper( tmpflg );
+
+
+                                    /* put in conversion */
+                                    if ( isupper( tmpflg ) )
+                                    {
+                                        cntrl[1] = 'l';
+                                        cntrl[2] = tolower( tmpflg );
+                                    }
+                                    else
+                                    {
+                                        cntrl[1] = tmpflg;
+                                        cntrl[2] = ' ';
+                                    }
+                                    if (sscanf (argp, cntrl, aptr, junk) != 1)
+                                        ERROR ("Bad numeric argument");
+                                } while ( comma_list && ++nopt < list_cnt );
+                            }
+                            check += cnt;
+                            arg_used[cnt] = 1;
+                            required = NO;
+                            /*
+                             * If not looking for multiple args,
+                             * then done, otherwise, keep looking.
+                             */
+                            if ( !( list_of && !comma_list ) )
+                                break;
+                            else
+                                continue;
+                        }
+                        if (required)
+                            switch (typchr)
+                            {
+                                case 'x':
+                                case 'X':
+                                    ERROR ("missing hexadecimal argument");
+                                case 's':
+                                    ERROR ("missing string argument");
+                                case 'o':
+                                case 'O':
+                                    ERROR ("missing octal argument");
+                                case 'd':
+                                case 'D':
+                                    ERROR ("missing decimal argument");
+                                case 'f':
+                                case 'F':
+                                    ERROR ("missing floating argument");
+                                case 'n':
+                                case 'N':
+                                    ERROR ("missing numeric argument");
+                            }
+                        if ( list_cnt > 0 )
+                        {
+                            *cnt_arg = list_cnt;
+                            switch ( typchr )
+                            {
+                                case 's':
+                                    *va_arg( argl, char *** ) = strlist;
+                                    break;
+                                case 'n':
+                                case 'd':
+                                case 'o':
+                                case 'x':
+                                    *va_arg( argl, int ** ) = intlist;
+                                    break;
+                                case 'N':
+                                case 'D':
+                                case 'O':
+                                case 'X':
+                                    *va_arg( argl, long ** ) = longlist;
+                                    break;
+                                case 'f':
+                                    *va_arg( argl, float ** ) = fltlist;
+                                    break;
+                                case 'F':
+                                    *va_arg( argl, double **) = dbllist;
+                                    break;
+                            }
+                            if ( typchr != 's' && comma_list )
+                                free( (char *) strlist );
+                        }
+                        else if ( cnt >= argc )
+                        {
+                            /* Fell off end looking, so must eat the arg */
+                            if ( typchr == 's' )
+                                (void)va_arg( argl, char * );
+                            else
+                                (void)va_arg( argl, ptr );
+                        }
+                        break;
+                    default:            /* error */
+                        fprintf (stderr,
+                                 "scanargs: Corrupt or invalid format spec\n");
+                        return 0;
+                }
+        }
     }
 
     /*  Count up empty flags */
     for (cnt=1; cnt<argc; cnt++)
-	if (argv[cnt][0] == '-' && argv[cnt][1] == '-' && argv[cnt][2] == 0
-	    && !arg_used[cnt] )
-	    check += cnt;
+        if (argv[cnt][0] == '-' && argv[cnt][1] == '-' && argv[cnt][2] == 0
+            && !arg_used[cnt] )
+            check += cnt;
 
     /* sum from 1 to N = n*(n+1)/2 used to count up checks */
     if (check != (((argc - 1) * argc) / 2))
-	ERROR ("extra arguments not processed");
+        ERROR ("extra arguments not processed");
 
     /* If -help, always print usage. */
     if ( help )
-	scan_usage( argv, format );
+        scan_usage( argv, format );
 
     free(arg_used);
     return 1;
 
-error: 
+error:
     if ( !no_usage )
-	scan_usage( argv, format );
+        scan_usage( argv, format );
     free(arg_used);
     return 0;
 }
@@ -685,35 +685,35 @@ CONST_DECL char * format;
     fprintf (stderr, "usage : ");
     if (*(cp = format) != ' ')
     {
-	if ( *cp == '%' )
-	{
-	    /* 
-	     * This is bogus, but until everyone can agree on a name
-	     * for (rindex/strrchr) ....
-	     */
-	    for ( cp = argv[0]; *cp != '\0'; cp++ )
-		;			/* find the end of the string */
-	    for ( ; cp > argv[0] && *cp != '/'; cp-- )
-		;			/* find the last / */
-	    if ( *cp == '/' )
-		cp++;
-	    fprintf( stderr, "%s", cp );
-
-	    cp = format + 1;		/* reset to where it should be */
-	}
-	while (putc (*cp++, stderr) != ' ');
+        if ( *cp == '%' )
+        {
+            /*
+             * This is bogus, but until everyone can agree on a name
+             * for (rindex/strrchr) ....
+             */
+            for ( cp = argv[0]; *cp != '\0'; cp++ )
+                ;                       /* find the end of the string */
+            for ( ; cp > argv[0] && *cp != '/'; cp-- )
+                ;                       /* find the last / */
+            if ( *cp == '/' )
+                cp++;
+            fprintf( stderr, "%s", cp );
+
+            cp = format + 1;            /* reset to where it should be */
+        }
+        while (putc (*cp++, stderr) != ' ');
     }
     else
-	fprintf (stderr, "?? ");
+        fprintf (stderr, "?? ");
     while (*cp == ' ')
-	cp++;
+        cp++;
     (void)prformat (cp, NO);
 }
 
 static CONST_DECL char *
 prformat (format, recurse)
 CONST_DECL char   *format;
-int 	recurse;
+int     recurse;
 {
     register CONST_DECL char  *cp;
     bool    required, comma_list;
@@ -721,142 +721,142 @@ int 	recurse;
 
     cp = format;
     if (recurse)
-	putc (' ', stderr);
+        putc (' ', stderr);
 
     required = NO;
     list_of = 0;
     comma_list = NO;
     while (*cp)
     {
-	switch (*cp)
-	{
-	    default:
-	    	cp++;
-		break;
-	    case ' ':
-	    case '\n':
-	    case '\t':
-		/* allow annotations */
-		for ( ; format < cp; format++ )
-		    putc( *format, stderr );
-		putc(*cp, stderr);
-		format = ++cp;
-		break;
-
-	    case '(':
-		/* Parentheses surround an arbitrary (parenthesis
-		 * balanced) comment.
-		 */
-		for ( ; format < cp; format++ )
-		    putc( *format, stderr );
-		for ( cp++, depth = 1; *cp && depth > 0; )
-		{
-		    /* Don't print last close paren. */
-		    if ( *cp != ')' || depth > 1 )
-			putc( *cp, stderr );
-		    switch( *(cp++) )
-		    {
-		    case '(':	depth++;		break;
-		    case ')':	depth--;		break;
-		    }
-		}
-		format = cp;
-		break;
-
-	    case '!': 
-		required = YES;
-	    case '%': 
+        switch (*cp)
+        {
+            default:
+                cp++;
+                break;
+            case ' ':
+            case '\n':
+            case '\t':
+                /* allow annotations */
+                for ( ; format < cp; format++ )
+                    putc( *format, stderr );
+                putc(*cp, stderr);
+                format = ++cp;
+                break;
+
+            case '(':
+                /* Parentheses surround an arbitrary (parenthesis
+                 * balanced) comment.
+                 */
+                for ( ; format < cp; format++ )
+                    putc( *format, stderr );
+                for ( cp++, depth = 1; *cp && depth > 0; )
+                {
+                    /* Don't print last close paren. */
+                    if ( *cp != ')' || depth > 1 )
+                        putc( *cp, stderr );
+                    switch( *(cp++) )
+                    {
+                    case '(':   depth++;                break;
+                    case ')':   depth--;                break;
+                    }
+                }
+                format = cp;
+                break;
+
+            case '!':
+                required = YES;
+            case '%':
 reswitch:
-		switch (*++cp)
-		{
-		    case ',':
-			comma_list++;
-		    case '*':
-			list_of++;
-			goto reswitch;
-
-		    case '$':		/* "rest" of argument list */
-			if (!required)
-			    putc ('[', stderr);
-			for (; format < cp - 1 - list_of; format++)
-			    putc (*format, stderr);
-			fputs( " ...", stderr );
-			if ( !required )
-			    putc( ']', stderr );
-			break;
-
-		    case '-': 		/* flags */
-			if (!required)
-			    putc ('[', stderr);
-			putc ('-', stderr);
-
-			if (cp - format > 2 + list_of)
-			    putc ('{', stderr);
-			cp = format;
-			while (*cp != '%' && *cp != '!')
-			    putc (*cp++, stderr);
-			if (cp - format > 1 + list_of)
-			    putc ('}', stderr);
-			cp += 2;	/* skip !- or %- */
-			if (*cp && !ISSPACE(*cp))
-			    cp = prformat (cp, YES);
-					/* this is a recursive call */
-
-			cp--;	/* don't ignore next character */
-
-			if (!required)
-			    putc (']', stderr);
-			break;
-		    case 's': 		/* char string */
-		    case 'd': 		/* decimal # */
-		    case 'o': 		/* octal # */
-		    case 'x': 		/* hexadecimal # */
-		    case 'f': 		/* floating # */
-		    case 'D': 		/* long decimal # */
-		    case 'O': 		/* long octal # */
-		    case 'X': 		/* long hexadecimal # */
-		    case 'F': 		/* double precision floating # */
-		    case 'n':		/* numeric arg (C format) */
-		    case 'N':		/* long numeric arg */
-			if (!required)
-			    putc ('[', stderr);
-			for (; format < cp - 1 - list_of; format++)
-			    putc (*format, stderr);
-			if ( list_of != 0 )
-			{
-			    if ( comma_list )
-				putc( ',', stderr );
-			    else
-				putc( ' ', stderr );
-			    fputs( "...", stderr );
-			}
-			if (!required)
-			    putc (']', stderr);
-			break;
-		    default: 
-			break;
-		}
-		required = NO;
-		list_of = NO;
-		comma_list = NO;
-		if (*cp)		/* check for end of string */
-		    format = ++cp;
-		if (*cp && !ISSPACE(*cp))
-		    putc (' ', stderr);
-	}
-	if (recurse && ISSPACE(*cp))
-	    break;
+                switch (*++cp)
+                {
+                    case ',':
+                        comma_list = YES;
+                    case '*':
+                        list_of++;
+                        goto reswitch;
+
+                    case '$':           /* "rest" of argument list */
+                        if (!required)
+                            putc ('[', stderr);
+                        for (; format < cp - 1 - list_of; format++)
+                            putc (*format, stderr);
+                        fputs( " ...", stderr );
+                        if ( !required )
+                            putc( ']', stderr );
+                        break;
+
+                    case '-':           /* flags */
+                        if (!required)
+                            putc ('[', stderr);
+                        putc ('-', stderr);
+
+                        if (cp - format > 2 + list_of)
+                            putc ('{', stderr);
+                        cp = format;
+                        while (*cp != '%' && *cp != '!')
+                            putc (*cp++, stderr);
+                        if (cp - format > 1 + list_of)
+                            putc ('}', stderr);
+                        cp += 2;        /* skip !- or %- */
+                        if (*cp && !ISSPACE(*cp))
+                            cp = prformat (cp, YES);
+                                        /* this is a recursive call */
+
+                        cp--;   /* don't ignore next character */
+
+                        if (!required)
+                            putc (']', stderr);
+                        break;
+                    case 's':           /* char string */
+                    case 'd':           /* decimal # */
+                    case 'o':           /* octal # */
+                    case 'x':           /* hexadecimal # */
+                    case 'f':           /* floating # */
+                    case 'D':           /* long decimal # */
+                    case 'O':           /* long octal # */
+                    case 'X':           /* long hexadecimal # */
+                    case 'F':           /* double precision floating # */
+                    case 'n':           /* numeric arg (C format) */
+                    case 'N':           /* long numeric arg */
+                        if (!required)
+                            putc ('[', stderr);
+                        for (; format < cp - 1 - list_of; format++)
+                            putc (*format, stderr);
+                        if ( list_of != 0 )
+                        {
+                            if ( comma_list )
+                                putc( ',', stderr );
+                            else
+                                putc( ' ', stderr );
+                            fputs( "...", stderr );
+                        }
+                        if (!required)
+                            putc (']', stderr);
+                        break;
+                    default:
+                        break;
+                }
+                required = NO;
+                list_of = NO;
+                comma_list = NO;
+                if (*cp)                /* check for end of string */
+                    format = ++cp;
+                if (*cp && !ISSPACE(*cp))
+                    putc (' ', stderr);
+        }
+        if (recurse && ISSPACE(*cp))
+            break;
     }
     if (!recurse)
     {
-	for ( ; format < cp; format++ )
-	    putc( *format, stderr );
-	putc ('\n', stderr);
+        for ( ; format < cp; format++ )
+            putc( *format, stderr );
+        putc ('\n', stderr);
     }
     return (cp);
 }
 
-/* 
+/*
  * isnum - determine whether a string MIGHT represent a number.
  * typchr indicates the type of argument we are looking for, and
  * determines the legal character set.  If comma_list is YES, then
@@ -873,46 +873,46 @@ int comma_list;
 
     switch( typchr )
     {
-	case 'n':
-	case 'N':
-	    allowed = " \t,+-x0123456789abcdefABCDEF";
-	    break;
-	case 'd':
-	case 'D':
-	    allowed = " \t,+-0123456789";
-	    break;
-	case 'o':
-	case 'O':
-	    allowed = " \t,01234567";
-	    break;
-	case 'x':
-	case 'X':
-	    allowed = " \t,0123456789abcdefABCDEF";
-	    break;
-	case 'f':
-	case 'F':
-	    allowed = " \t,+-eE.0123456789";
-	    break;
-	case 's':			/* only throw out decimal numbers */
-	default:
-	    allowed = " \t,+-.0123456789";
-	    break;
+        case 'n':
+        case 'N':
+            allowed = " \t,+-x0123456789abcdefABCDEF";
+            break;
+        case 'd':
+        case 'D':
+            allowed = " \t,+-0123456789";
+            break;
+        case 'o':
+        case 'O':
+            allowed = " \t,01234567";
+            break;
+        case 'x':
+        case 'X':
+            allowed = " \t,0123456789abcdefABCDEF";
+            break;
+        case 'f':
+        case 'F':
+            allowed = " \t,+-eE.0123456789";
+            break;
+        case 's':                       /* only throw out decimal numbers */
+        default:
+            allowed = " \t,+-.0123456789";
+            break;
     }
     digits = allowed;
     while ( *digits != '0' )
-	digits++;
+        digits++;
     if ( ! comma_list )
-	allowed += 3;		      /* then don't allow space, tab, comma */
+        allowed += 3;                 /* then don't allow space, tab, comma */
 
     while ( *str != '\0' )
     {
-    	for ( cp = allowed; *cp != '\0' && *cp != *str; cp++ )
-    	    ;
-    	if ( *cp == '\0' )
-	    return NO;		     /* if not in allowed chars, not number */
-	if ( cp - digits >= 0 )
-	    hasdigit = YES;
-	str++;
+        for ( cp = allowed; *cp != '\0' && *cp != *str; cp++ )
+            ;
+        if ( *cp == '\0' )
+            return NO;               /* if not in allowed chars, not number */
+        if ( cp - digits >= 0 )
+            hasdigit = YES;
+        str++;
     }
     return hasdigit;
 }
diff --git a/version.mk b/version.mk
index 63bc6717..a664dcd9 100644
--- a/version.mk
+++ b/version.mk
@@ -1,3 +1,3 @@
 NETPBM_MAJOR_RELEASE = 10
-NETPBM_MINOR_RELEASE = 90
-NETPBM_POINT_RELEASE = 5
+NETPBM_MINOR_RELEASE = 91
+NETPBM_POINT_RELEASE = 0