about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Makefile.common10
-rw-r--r--Makefile.version4
-rw-r--r--buildtools/libopt.c10
-rw-r--r--converter/other/Makefile2
-rw-r--r--converter/other/giftopnm.c4
-rw-r--r--converter/other/hdifftopam.c2
-rw-r--r--converter/other/jpeg2000/libjasper/Makefile.common2
-rw-r--r--converter/other/pamtogif.c1864
-rw-r--r--converter/other/pamtopnm.c59
-rw-r--r--converter/other/pamtosvg/curve.h8
-rw-r--r--converter/other/pamtosvg/fit.c1127
-rw-r--r--converter/other/pgmtopbm.c5
-rw-r--r--converter/other/pgmtoppm.c343
-rw-r--r--converter/other/pngtopnm.c22
-rw-r--r--converter/other/pnmtoddif.c4
-rw-r--r--converter/other/pnmtojpeg.c698
-rw-r--r--converter/other/pnmtopalm/Makefile3
-rw-r--r--converter/other/pnmtopng.c16
-rw-r--r--converter/pbm/Makefile4
-rw-r--r--converter/pbm/cmuwmtopbm.c181
-rw-r--r--converter/pbm/mgrtopbm.c171
-rw-r--r--converter/pbm/pbmtocmuwm.c167
-rw-r--r--converter/pbm/pbmtogem.c6
-rw-r--r--converter/pbm/pbmtogo.c10
-rw-r--r--converter/pbm/pbmtoicon.c252
-rw-r--r--converter/pbm/pbmtomgr.c192
-rw-r--r--converter/pbm/pbmtopi3.c6
-rw-r--r--converter/pbm/pbmtoptx.c6
-rw-r--r--converter/pbm/pbmtox10bm45
-rw-r--r--converter/pbm/pbmtox10bm.c120
-rw-r--r--converter/pbm/pbmtoxbm.c394
-rw-r--r--converter/pbm/pbmtoybm.c6
-rw-r--r--converter/pbm/xbmtopbm.c567
-rw-r--r--converter/pgm/pgmtofs.c6
-rw-r--r--converter/pgm/pgmtolispm.c6
-rw-r--r--converter/ppm/ppmtogif.c1544
-rw-r--r--converter/ppm/ppmtoilbm.c42
-rw-r--r--converter/ppm/ppmtomitsu.c844
-rw-r--r--converter/ppm/ppmtomitsu.test12
-rw-r--r--converter/ppm/ppmtompeg/Makefile10
-rw-r--r--converter/ppm/ppmtompeg/bframe.c1
-rw-r--r--converter/ppm/ppmtompeg/bsearch.c1
-rw-r--r--converter/ppm/ppmtompeg/frames.c58
-rw-r--r--converter/ppm/ppmtompeg/headers/bitio.h4
-rw-r--r--converter/ppm/ppmtompeg/headers/block.h44
-rw-r--r--converter/ppm/ppmtompeg/headers/frame.h16
-rw-r--r--converter/ppm/ppmtompeg/headers/frames.h168
-rw-r--r--converter/ppm/ppmtompeg/headers/iframe.h118
-rw-r--r--converter/ppm/ppmtompeg/headers/motion_search.h3
-rw-r--r--converter/ppm/ppmtompeg/headers/mpeg.h5
-rw-r--r--converter/ppm/ppmtompeg/headers/mproto.h8
-rw-r--r--converter/ppm/ppmtompeg/headers/parallel.h2
-rw-r--r--converter/ppm/ppmtompeg/headers/prototypes.h9
-rw-r--r--converter/ppm/ppmtompeg/headers/subsample.h39
-rw-r--r--converter/ppm/ppmtompeg/iframe.c209
-rw-r--r--converter/ppm/ppmtompeg/jpeg.c1
-rw-r--r--converter/ppm/ppmtompeg/mheaders.c712
-rw-r--r--converter/ppm/ppmtompeg/mpeg.c116
-rw-r--r--converter/ppm/ppmtompeg/pframe.c2
-rw-r--r--converter/ppm/ppmtompeg/psearch.c2
-rw-r--r--converter/ppm/ppmtompeg/subsample.c1
-rw-r--r--converter/ppm/ppmtopict.c7
-rw-r--r--converter/ppm/sldtoppm.c726
-rw-r--r--converter/ppm/spctoppm.c7
-rw-r--r--doc/HISTORY103
-rw-r--r--doc/INSTALL30
-rw-r--r--doc/USERDOC16
-rw-r--r--editor/Makefile2
-rw-r--r--editor/pamaddnoise.c4
-rw-r--r--editor/pambackground.c302
-rw-r--r--editor/pamditherbw.c2
-rw-r--r--editor/pammasksharpen.c5
-rw-r--r--editor/pamperspective.c328
-rw-r--r--editor/pbmreduce.c15
-rw-r--r--editor/pnmcrop.c86
-rwxr-xr-xeditor/pnmflip1
-rw-r--r--editor/pnmnlfilt.c123
-rw-r--r--editor/pnmremap.c2
-rw-r--r--editor/pnmrotate.c45
-rw-r--r--editor/pnmshear.c167
-rw-r--r--editor/ppmchange.c16
-rw-r--r--editor/ppmshift.c219
-rw-r--r--editor/ppmspread.c216
-rw-r--r--generator/pbmtextps.c63
-rw-r--r--generator/pbmupc.c17
-rw-r--r--generator/pgmcrater.c7
-rw-r--r--generator/pgmnoise.c115
-rw-r--r--generator/ppmforge.c5
-rw-r--r--generator/ppmpat.c54
-rw-r--r--lib/Makefile4
-rw-r--r--lib/libpam.c56
-rw-r--r--lib/libpamcolor.c32
-rw-r--r--lib/libpammap.c45
-rw-r--r--lib/libpgm1.c1
-rw-r--r--lib/libpm.c14
-rw-r--r--lib/libpnm3.c148
-rw-r--r--lib/libppmcmap.c8
-rw-r--r--lib/libppmcolor.c17
-rw-r--r--lib/libppmd.c10
-rw-r--r--lib/libppmfloyd.c41
-rw-r--r--lib/libsystem.c29
-rw-r--r--lib/pam.h33
-rw-r--r--lib/pammap.h8
-rw-r--r--lib/pm.h3
-rw-r--r--lib/pnm.h11
-rw-r--r--lib/ppm.h17
-rw-r--r--lib/ppmdraw.h24
-rw-r--r--lib/ppmfloyd.h18
-rw-r--r--lib/util/Makefile2
-rw-r--r--lib/util/wordaccess.h3
-rw-r--r--lib/util/wordaccess_64_le.h2
-rw-r--r--lib/util/wordaccess_gcc3_le.h2
-rw-r--r--other/pamx/Makefile251
-rw-r--r--other/pamx/image.c92
-rw-r--r--other/pamx/image.h5
-rw-r--r--other/pamx/pamx.c50
-rw-r--r--other/ppmsvgalib.c2
-rw-r--r--pm_config.in.h29
-rw-r--r--urt/Makefile3
119 files changed, 7565 insertions, 6171 deletions
diff --git a/Makefile.common b/Makefile.common
index 26b5242f..ed9f2066 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -61,13 +61,13 @@
 #   libjpeg.  All header files from the Netpbm source tree take precedence
 #   over these.
 
-# In addition, there is CADD, which is extra C compilation flags and
+# In addition, there is CADD, which is extra C compilation options and
 # is intended to be set on a make command line (e.g. 'make CADD=-g')
-# for flags that apply just to a particular build.
+# for options that apply just to a particular build.
 
 # In addition, there is CFLAGS_PERSONAL, which is extra C
-# compilation flags and is expected to be set via environment variable
-# for flags that are particular to the person doing the build and not
+# compilation options and is expected to be set via environment variable
+# for options that are particular to the person doing the build and not
 # specific to Netpbm.
 
 include $(SRCDIR)/Makefile.version
@@ -330,7 +330,7 @@ $(PORTBINARIES) $(MATHBINARIES): %: %.o $(NETPBMLIB) $(LIBOPT)
 
 %.o2: %.c importinc
 # Note that the user may have configured -I options into CFLAGS.
-	$(CC) -c $(INCLUDES) -DNDEBUG $(CFLAGS) \
+	$(CC) -c $(INCLUDES) -DNDEBUG $(CPPFLAGS) $(CFLAGS) \
 	  "-Dmain=main_$*" \
           $(CFLAGS_MERGE) $(CFLAGS_PERSONAL) $(CADD) -o $@ $<
 
diff --git a/Makefile.version b/Makefile.version
new file mode 100644
index 00000000..08ea8f35
--- /dev/null
+++ b/Makefile.version
@@ -0,0 +1,4 @@
+NETPBM_MAJOR_RELEASE = 10
+NETPBM_MINOR_RELEASE = 37
+NETPBM_POINT_RELEASE = 0
+
diff --git a/buildtools/libopt.c b/buildtools/libopt.c
index 3dcb1f73..e0bfde7e 100644
--- a/buildtools/libopt.c
+++ b/buildtools/libopt.c
@@ -11,8 +11,8 @@
   filename to be searched for in the linker's default search path, and
   generate a -l option, but no -L.
 
-  If an argument doesn't make sense as a library filespec, it is
-  copied verbatim, blank delimited, to the output string.
+  If an argument doesn't make sense as a library filespec, we copy
+  it verbatim, blank delimited, to the output string.
 
   The "lib" part of the library name, which we call the prefix, may be
   other than "lib".  The list of recognized values is compiled in as
@@ -52,11 +52,11 @@
 
      NETPBMLIB=../lib/libnetpbm.so
      ...
-     pbmmake: pbmmake.o $(PBMLIB)
-             ld -o pbmmake pbmmake.o `libopt $(PBMLIB)` --rpath=/lib/netpbm
+     pbmmake: pbmmake.o $(NETPBMLIB)
+             ld -o pbmmake pbmmake.o `libopt $(NETPBMLIB)` --rpath=/lib/netpbm
 
   Caveat: "-L../lib -lnetpbm" is NOT exactly the same as
-  "../pbm/libnetpbm.so" on any system.  All of the -l libraries are
+  "../lib/libnetpbm.so" on any system.  All of the -l libraries are
   searched for in all of the -L directories.  So you just might get a
   different library with the -L/-l version than if you specify the
   library file explicitly.
diff --git a/converter/other/Makefile b/converter/other/Makefile
index 6cde424d..0273c523 100644
--- a/converter/other/Makefile
+++ b/converter/other/Makefile
@@ -79,7 +79,7 @@ endif
 
 PORTBINARIES =  bmptopnm fitstopnm \
 		gemtopnm giftopnm hdifftopam infotopam \
-		pamtodjvurle pamtofits \
+		pamtodjvurle pamtofits pamtogif \
 		pamtohdiff pamtohtmltbl pamtopfm pamtopnm pamtouil \
 		pamtoxvmini \
 		pbmtopgm pfmtopam \
diff --git a/converter/other/giftopnm.c b/converter/other/giftopnm.c
index d3d02fde..d7d54775 100644
--- a/converter/other/giftopnm.c
+++ b/converter/other/giftopnm.c
@@ -652,7 +652,7 @@ termStack(struct stack * const stackP) {
    max_dataVal.  The first byte in the stream tells you what dataWidth
    is.
 
-   LZW codes 0 - max_dataVal are direct codes.  Each on represents
+   LZW codes 0 - max_dataVal are direct codes.  Each one represents
    the true data element whose value is that of the LZW code itself.
    No decompression is required.
 
@@ -805,7 +805,7 @@ expandCodeOntoStack(struct decompressor * const decompP,
            represents and push it onto the code stack so the
            leftmost code is on top.  Set decompP->firstcode to the
            first (leftmost) code in that string.
-            */
+        */
 
         unsigned int stringCount;
         stringCount = 0;
diff --git a/converter/other/hdifftopam.c b/converter/other/hdifftopam.c
index 444d6068..0f1a5ca3 100644
--- a/converter/other/hdifftopam.c
+++ b/converter/other/hdifftopam.c
@@ -96,7 +96,7 @@ main(int argc, char *argv[]) {
     tuple * outrow;
     tuple * prevrow;
 
-    pnm_init( &argc, argv );
+    pnm_init(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
diff --git a/converter/other/jpeg2000/libjasper/Makefile.common b/converter/other/jpeg2000/libjasper/Makefile.common
index 7737f2c0..d2cb7d42 100644
--- a/converter/other/jpeg2000/libjasper/Makefile.common
+++ b/converter/other/jpeg2000/libjasper/Makefile.common
@@ -26,7 +26,7 @@ INCLUDES = -I$(JASPERSRCDIR)/include -Iimportinc
 DEFS = -DHAVE_LIBM=1 -DSTDC_HEADERS=1 -DHAVE_FCNTL_H=1 -DHAVE_LIMITS_H=1 -DHAVE_UNISTD_H=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STDDEF_H=1 -DEXCLUDE_BMP_SUPPORT -DEXCLUDE_RAS_SUPPORT -DEXCLUDE_MIF_SUPPORT -DEXCLUDE_JPG_SUPPORT -DEXCLUDE_PGX_SUPPORT -DEXCLUDE_PNM_SUPPORT
 
 $(LIB_OBJECTS):%.o:%.c
-	$(CC) -c $(CFLAGS) $(INCLUDES) $(DEFS) $(CADD) $<
+	$(CC) -c $(CPPFLAGS) $(CFLAGS) $(INCLUDES) $(DEFS) $(CADD) $<
 
 $(LIB_OBJECTS): importinc
 
diff --git a/converter/other/pamtogif.c b/converter/other/pamtogif.c
new file mode 100644
index 00000000..ef3441cb
--- /dev/null
+++ b/converter/other/pamtogif.c
@@ -0,0 +1,1864 @@
+/*=============================================================================
+                              pamtogif
+===============================================================================
+  Convert a Netpbm image to GIF
+
+  History and copyright information is at the end of the file.
+=============================================================================*/
+
+#include <assert.h>
+#include <string.h>
+
+#include "mallocvar.h"
+#include "shhopt.h"
+#include "nstring.h"
+#include "pam.h"
+#include "pammap.h"
+
+#define MAXCMAPSIZE 256
+
+static unsigned int const gifMaxval = 255;
+
+static bool verbose;
+
+typedef int stringCode;
+    /* A code to be place in the GIF raster.  It represents
+       a string of one or more pixels.  You interpret this in the context
+       of a current code size.  The lower half of the values representable
+       in the current code size represent singleton strings and the value
+       is simply the value of the one pixel in the string.  The first two
+       values in the upper half of the range are the clear code and EOF
+       code, respectively.  The rest of the values represent multi-pixel
+       strings.  The mapping between value and the sequence of pixels
+       changes throughout the image.
+
+       A variable of this type sometimes has the value -1 instead of
+       a string code due to cheesy programming.
+
+       Ergo, this data structure must be signed and at least BITS bits
+       wide plus sign bit.
+
+       TODO: Some variables that should be of this type are defined as
+             "long".
+    */
+
+
+struct cmap {
+    /* This is the information for the GIF colormap (aka palette). */
+
+    struct pam pam;
+        /* Gives depth and maxval for colors in color[] */
+    tuple color[MAXCMAPSIZE];
+        /* Maps a color index, as is found in the raster part of the
+           GIF, to color.
+        */
+    int perm[MAXCMAPSIZE], permi[MAXCMAPSIZE];
+        /* perm[i] is the position in the sorted colormap of the color which
+           is at position i in the unsorted colormap.  permi[] is the inverse
+           function of perm[].
+           
+           The sort colormap is the one that goes into the GIF.  The
+           unsorted one is the one that is hashed so we can find colors
+           in it.
+        */
+    unsigned int cmapSize;
+        /* Number of entries in the GIF colormap.  I.e. number of colors
+           in the image, plus possibly one fake transparency color.
+        */
+    bool haveTransparent;
+        /* The colormap contains an entry for transparent pixels */
+    unsigned int transparent;
+        /* color index number in GIF palette of the color that is to
+           be transparent.  This is a post-sort index.
+
+           Meaningful only if 'haveTransparent' is true.
+        */
+    tuplehash tuplehash;
+        /* A hash table to translate color to GIF (presort) colormap index. */
+};
+
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char *input_filespec; /* Filespec of input file */
+    const char *alphacolor;     /* -alphacolor option value or default */
+    unsigned int interlace;     /* -interlace option value */
+    unsigned int sort;          /* -sort option value */
+    const char *mapfile;        /* -mapfile option value.  NULL if none. */
+    const char *transparent;    /* -transparent option value.  NULL if none. */
+    const char *comment;        /* -comment option value; NULL if none */
+    unsigned int nolzw;         /* -nolzw option */
+    unsigned int verbose;
+};
+
+
+static unsigned int
+nSignificantBits(unsigned int const arg) {
+
+    unsigned int i;
+
+    i = 0;
+   
+    while (arg >> i != 0)
+        ++i;
+
+    return i;
+}
+
+
+
+static unsigned int
+pamAlphaPlane(struct pam * const pamP) {
+
+    unsigned int alphaPlane;
+
+    if (STREQ(pamP->tuple_type, "RGB_ALPHA"))
+        alphaPlane = 3;
+    else if (STREQ(pamP->tuple_type, "GRAYSCALE_ALPHA"))
+        alphaPlane = 2;
+    else if (STREQ(pamP->tuple_type, "BLACKANDWHITE_ALPHA"))
+        alphaPlane = 2;
+    else
+        alphaPlane = 0;
+    
+    if (alphaPlane >= pamP->depth)
+        pm_error("Tuple type is '%s', but depth (%u) is less than %u",
+                 pamP->tuple_type, pamP->depth, alphaPlane + 1);
+
+    return alphaPlane;
+}
+
+
+
+static void
+parseCommandLine(int argc, char ** argv,
+                 struct cmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Parse the program arguments (given by argc and argv) into a form
+   the program can deal with more easily -- a cmdline_info structure.
+   If the syntax is invalid, issue a message and exit the program via
+   pm_error().
+
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;  /* malloc'ed */
+    optStruct3 opt;  /* set by OPTENT3 */
+    unsigned int option_def_index;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0,   "interlace",   OPT_FLAG,   
+            NULL,                       &cmdlineP->interlace, 0);
+    OPTENT3(0,   "sort",        OPT_FLAG,   
+            NULL,                       &cmdlineP->sort, 0);
+    OPTENT3(0,   "nolzw",       OPT_FLAG,   
+            NULL,                       &cmdlineP->nolzw, 0);
+    OPTENT3(0,   "mapfile",     OPT_STRING, 
+            &cmdlineP->mapfile,        NULL, 0);
+    OPTENT3(0,   "transparent", OPT_STRING, 
+            &cmdlineP->transparent,    NULL, 0);
+    OPTENT3(0,   "comment",     OPT_STRING, 
+            &cmdlineP->comment,        NULL, 0);
+    OPTENT3(0,   "alphacolor",  OPT_STRING, 
+            &cmdlineP->alphacolor,     NULL, 0);
+    OPTENT3(0,   "verbose",     OPT_FLAG, 
+            NULL,                       &cmdlineP->verbose, 0);
+    
+    /* Set the defaults */
+    cmdlineP->mapfile = NULL;
+    cmdlineP->transparent = NULL;  /* no transparency */
+    cmdlineP->comment = NULL;      /* no comment */
+    cmdlineP->alphacolor = "rgb:0/0/0";      
+        /* We could say "black" here, but then we depend on the color names
+           database existing.
+        */
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (argc-1 == 0) 
+        cmdlineP->input_filespec = "-";
+    else if (argc-1 != 1)
+        pm_error("Program takes zero or one argument (filename).  You "
+                 "specified %d", argc-1);
+    else
+        cmdlineP->input_filespec = argv[1];
+}
+
+
+
+/*
+ * Write out a word to the GIF file
+ */
+static void
+Putword(int const w, FILE * const fp) {
+
+    fputc( w & 0xff, fp );
+    fputc( (w / 256) & 0xff, fp );
+}
+
+
+
+static int
+closestColor(tuple         const color,
+             struct pam *  const pamP,
+             struct cmap * const cmapP) {
+/*----------------------------------------------------------------------------
+   Return the pre-sort colormap index of the color in the colormap *cmapP
+   that is closest to the color 'color', whose format is specified by 
+   *pamP.
+
+   Also add 'color' to the colormap hash, with the colormap index we
+   are returning.  Caller must ensure that the color is not already in
+   there.
+-----------------------------------------------------------------------------*/
+    unsigned int const nComp = pamP->depth >= 3 ? 3 : 1;
+        /* Number of color components (not alpha) in 'color' */
+    
+    unsigned int i;
+    unsigned int imin, dmin;
+    bool fits;
+
+    dmin = UINT_MAX;
+    imin = 0;
+    for (i = 0; i < cmapP->cmapSize; ++i) {
+        unsigned int distance;
+        unsigned int plane;
+
+        for (distance = 0, plane = 0; plane < nComp; ++plane)
+            /* Divide by 4 is to avoid arithmetic overflow */
+            distance += SQR(color[plane] - cmapP->color[i][plane]) / 4;
+
+        if (distance < dmin) {
+            dmin = distance;
+            imin = i; 
+        } 
+    }
+    pnm_addtotuplehash(pamP, cmapP->tuplehash, color, imin, &fits);
+
+    return imin;
+}
+
+
+
+enum pass {MULT8PLUS0, MULT8PLUS4, MULT4PLUS2, MULT2PLUS1};
+
+
+typedef struct {
+    struct pam pam;
+        /* Description of input file/image.  The position of the file
+           is also part of the state of this rowReader.
+        */
+    pm_filepos rasterPos;
+        /* Position in file fileP of the start of the raster */
+    bool interlace;
+        /* We're accessing the image in interlace fashion */
+    bool eof;
+        /* The image is at EOF (we have returned all of the rows) */
+    unsigned int nextRow;
+        /* Number of row to which input file is positioned;
+           meaningless if 'eof'.
+        */
+    enum pass pass;
+        /* The interlace pass.  Undefined if !interlace */
+    tuple * discardBuffer;
+        /* A bitbucket for rows we read in order to advance the file
+           position.
+        */
+} rowReader;
+
+
+
+static rowReader *
+rowReader_create(struct pam * const pamP,
+                 pm_filepos   const rasterPos,
+                 bool         const interlace) {
+
+    rowReader * rdrP;
+
+    MALLOCVAR_NOFAIL(rdrP);
+
+    rdrP->pam         = *pamP;
+    rdrP->rasterPos   = rasterPos;
+    rdrP->interlace   = interlace;
+    rdrP->eof         = FALSE;
+    rdrP->pass        = MULT8PLUS0;
+
+    pm_seek2(rdrP->pam.file, &rasterPos, sizeof(rasterPos));
+    rdrP->nextRow = 0;
+
+    rdrP->discardBuffer = pnm_allocpamrow(&rdrP->pam);
+
+    return rdrP;
+}
+
+
+
+static void
+rowReader_destroy(rowReader * const rdrP) {
+
+    pnm_freepamrow(rdrP->discardBuffer);
+    free(rdrP);
+}
+
+
+
+static void
+rowReaderSkipRows(rowReader *  const rdrP,
+                  unsigned int const rowCount,
+                  bool *       const eofP) {
+/*----------------------------------------------------------------------------
+   Skip over the next 'rowCount' rows of the input file.
+
+   Iff there aren't at least 'rowCount' rows left, return *eofP == TRUE.
+-----------------------------------------------------------------------------*/
+    if (rdrP->nextRow + rowCount >= rdrP->pam.height)
+        *eofP = TRUE;
+    else {
+        /* This could be made faster if need be by adding a libnetpbm
+           row skip function.  Except with the plain formats, that could
+           just compute the next row position and fseek() to it.
+           pnm_readpamrow() with NULL for the output pointer would be a
+           good interface for a row skip function.
+        */
+        unsigned int i;
+
+        *eofP = FALSE;
+
+        for (i = 0; i < rowCount; ++i)
+            pnm_readpamrow(&rdrP->pam, rdrP->discardBuffer);
+
+        rdrP->nextRow += rowCount;
+    }
+}
+
+
+
+static void
+rowReaderGotoNextInterlaceRow(rowReader * const rdrP) {
+/*----------------------------------------------------------------------------
+  Position reader to the next row in the interlace pattern, assuming it
+  is now positioned immediately after the current row.
+-----------------------------------------------------------------------------*/
+    bool endOfPass;
+
+    /* There are 4 passes:
+       MULT8PLUS0: Rows 0, 8, 16, 24, 32, etc.
+       MULT8PLUS4: Rows 4, 12, 20, 28, etc.
+       MULT4PLUS2: Rows 2, 6, 10, 14, etc.
+       MULT2PLUS1: Rows 1, 3, 5, 7, 9, etc.
+    */
+    
+    switch (rdrP->pass) {
+    case MULT8PLUS0:
+        rowReaderSkipRows(rdrP, 7, &endOfPass);
+        break;
+    case MULT8PLUS4:
+        rowReaderSkipRows(rdrP, 7, &endOfPass);
+        break;
+    case MULT4PLUS2:
+        rowReaderSkipRows(rdrP, 3, &endOfPass);
+        break;
+    case MULT2PLUS1:
+        rowReaderSkipRows(rdrP, 1, &endOfPass);
+        break;
+    }
+
+    /* Note that if there are more than 4 rows, the sequence of passes
+       is sequential, but when there are fewer than 4, reading may skip
+       e.g. from MULT8PLUS0 to MULT4PLUS2.
+    */
+    while (endOfPass && !rdrP->eof) {
+        pm_seek2(rdrP->pam.file, &rdrP->rasterPos, sizeof(rdrP->rasterPos));
+        rdrP->nextRow = 0;
+
+        switch (rdrP->pass) {
+        case MULT8PLUS0:
+            rdrP->pass = MULT8PLUS4;
+            rowReaderSkipRows(rdrP, 4, &endOfPass);
+            break;
+        case MULT8PLUS4:
+            rdrP->pass = MULT4PLUS2;
+            rowReaderSkipRows(rdrP, 2, &endOfPass);
+            break;
+        case MULT4PLUS2:
+            rdrP->pass = MULT2PLUS1;
+            rowReaderSkipRows(rdrP, 1, &endOfPass);
+            break;
+        case MULT2PLUS1:
+            rdrP->eof = TRUE;
+            break;
+        }
+    }
+}
+
+
+
+
+static void
+rowReaderGotoNextStraightRow(rowReader * const rdrP) {
+/*----------------------------------------------------------------------------
+  Position reader to the next row in a straight, non-interlace
+  pattern, assuming the file is now positioned immediately after the
+  current row.
+
+  This is trivial, since the next row _is_ immediately after the current
+  row, except in the case that there are no more rows.
+-----------------------------------------------------------------------------*/
+    if (rdrP->nextRow >= rdrP->pam.height)
+        rdrP->eof = TRUE;
+}
+
+
+
+static void
+rowReader_read(rowReader * const rdrP,
+               tuple *     const tuplerow) {
+
+    if (rdrP->eof)
+        pm_error("INTERNAL ERROR: rowReader attempted to read beyond end "
+                 "of image");
+
+    pnm_readpamrow(&rdrP->pam, tuplerow);
+    ++rdrP->nextRow;
+    
+    if (rdrP->interlace)
+        rowReaderGotoNextInterlaceRow(rdrP);
+    else
+        rowReaderGotoNextStraightRow(rdrP);
+}
+
+
+
+static unsigned int
+gifPixel(struct pam *   const pamP,
+         tuple          const tuple,
+         unsigned int   const alphaPlane,
+         sample         const alphaThreshold, 
+         struct cmap *  const cmapP) {
+/*----------------------------------------------------------------------------
+   Return as *colorIndexP the colormap index of the tuple 'tuple',
+   whose format is described by *pamP, using colormap *cmapP.
+
+   'alphaThreshold' is the alpha level below which we consider a
+   pixel transparent for GIF purposes.
+-----------------------------------------------------------------------------*/
+    unsigned int colorIndex;
+
+    if (alphaPlane && tuple[alphaPlane] < alphaThreshold &&
+        cmapP->haveTransparent)
+        colorIndex = cmapP->transparent;
+    else {
+        int presortColorindex;
+        int found;
+
+        pnm_lookuptuple(pamP, cmapP->tuplehash, tuple,
+                        &found, &presortColorindex);
+        
+        if (!found)
+            presortColorindex = closestColor(tuple, pamP, cmapP);
+
+        colorIndex = cmapP->perm[presortColorindex];
+    }
+    return colorIndex;
+}
+
+
+
+static void
+writeTransparentColorIndexExtension(FILE *       const ofP,
+                                    unsigned int const transColorIndex) {
+/*----------------------------------------------------------------------------
+   Write out extension for transparent color index.
+-----------------------------------------------------------------------------*/
+    fputc('!',  ofP);
+    fputc(0xf9, ofP);
+    fputc(4,    ofP);
+    fputc(1,    ofP);
+    fputc(0,    ofP);
+    fputc(0,    ofP);
+    fputc(transColorIndex, ofP);
+    fputc(0,    ofP);
+}
+
+
+
+static void
+writeCommentExtension(FILE * const ofP,
+                      char   const comment[]) {
+/*----------------------------------------------------------------------------
+   Write out extension for a comment
+-----------------------------------------------------------------------------*/
+    unsigned int const maxSegmentSize = 255;
+
+    const char * segment;
+    
+    fputc('!',  ofP);   /* Identifies an extension */
+    fputc(0xfe, ofP);   /* Identifies a comment */
+
+    /* Write it out in segments no longer than 255 characters */
+    for (segment = &comment[0]; 
+         segment < comment + strlen(comment); 
+         segment += maxSegmentSize) {
+
+        unsigned int const lengthThisSegment =
+            MIN(maxSegmentSize, strlen(segment));
+
+        fputc(lengthThisSegment, ofP);
+
+        fwrite(segment, 1, lengthThisSegment, ofP);
+    }
+
+    fputc(0, ofP);   /* No more comment blocks in this extension */
+}
+
+
+
+/***************************************************************************
+ *
+ *  GIFCOMPR.C       - GIF Image compression routines
+ *
+ *  Lempel-Ziv compression based on 'compress'.  GIF modifications by
+ *  David Rowley (mgardi@watdcsu.waterloo.edu)
+ *
+ ***************************************************************************/
+
+/*
+ * General DEFINEs
+ */
+
+#define BITS    12
+
+#define HSIZE  5003            /* 80% occupancy */
+
+/*
+ *
+ * GIF Image compression - modified 'compress'
+ *
+ * Based on: compress.c - File compression ala IEEE Computer, June 1984.
+ *
+ * By Authors:  Spencer W. Thomas       (decvax!harpo!utah-cs!utah-gr!thomas)
+ *              Jim McKie               (decvax!mcvax!jim)
+ *              Steve Davies            (decvax!vax135!petsd!peora!srd)
+ *              Ken Turkowski           (decvax!decwrl!turtlevax!ken)
+ *              James A. Woods          (decvax!ihnp4!ames!jaw)
+ *              Joe Orost               (decvax!vax135!petsd!joe)
+ *
+ */
+
+
+static stringCode const maxCodeLimitLzw = (stringCode)1 << BITS;
+       /* One beyond the largest string code that can exist in GIF */ 
+       /* Used only in assertions  */
+
+
+struct hashTableEntry {
+    long fcode;   /* -1 means unused slot */
+    unsigned int ent;
+};    
+
+
+
+/***************************************************************************
+*                          BYTE OUTPUTTER                 
+***************************************************************************/
+
+typedef struct {
+    FILE * fileP;  /* The file to which to output */
+    unsigned int count;
+        /* Number of bytes so far in the current data block */
+    unsigned char buffer[256];
+        /* The current data block, under construction */
+} byteBuffer;
+
+
+
+static byteBuffer *
+byteBuffer_create(FILE * const fileP) {
+
+    byteBuffer * byteBufferP;
+
+    MALLOCVAR_NOFAIL(byteBufferP);
+
+    byteBufferP->fileP = fileP;
+    byteBufferP->count = 0;
+
+    return byteBufferP;
+}
+
+
+
+static void
+byteBuffer_destroy(byteBuffer * const byteBufferP) {
+
+    free(byteBufferP);
+}
+
+
+
+static void
+byteBuffer_flush(byteBuffer * const byteBufferP) {
+/*----------------------------------------------------------------------------
+   Write the current data block to the output file, then reset the current 
+   data block to empty.
+-----------------------------------------------------------------------------*/
+    if (byteBufferP->count > 0 ) {
+        if (verbose)
+            pm_message("Writing %u byte block", byteBufferP->count);
+        fputc(byteBufferP->count, byteBufferP->fileP);
+        fwrite(byteBufferP->buffer, 1, byteBufferP->count, byteBufferP->fileP);
+        byteBufferP->count = 0;
+    }
+}
+
+
+
+static void
+byteBuffer_flushFile(byteBuffer * const byteBufferP) {
+    
+    fflush(byteBufferP->fileP);
+    
+    if (ferror(byteBufferP->fileP))
+        pm_error("error writing output file");
+}
+
+
+
+static void
+byteBuffer_out(byteBuffer *  const byteBufferP,
+               unsigned char const c) {
+/*----------------------------------------------------------------------------
+  Add a byte to the end of the current data block, and if it is now 254
+  characters, flush the data block to the output file.
+-----------------------------------------------------------------------------*/
+    byteBufferP->buffer[byteBufferP->count++] = c;
+    if (byteBufferP->count >= 254)
+        byteBuffer_flush(byteBufferP);
+}
+
+
+
+/***************************************************************************
+*                          GIF CODE OUTPUTTER                 
+***************************************************************************/
+
+typedef struct {
+    byteBuffer * byteBufferP;
+    unsigned int initBits;
+    unsigned int nBits;
+        /* Number of bits to put in output for each code */
+    stringCode maxCode;                  /* maximum code, given n_bits */
+    stringCode maxCodeLimit;
+        /* LZW: One beyond the largest string code that can exist in GIF.
+           Uncompressed: a ceiling to prevent code size from ratcheting up.
+           In either case, output code never reaches this value.
+        */  
+    unsigned long curAccum;
+    int curBits;
+    unsigned int codeCount;
+        /* Number of codes that have been output to this buffer (doesn't
+           matter if they have gone out the other side yet or not) since
+           the last flush (or ever, if no last flush).  The main use of this
+           is debugging -- when something fails, you can see in a debugger
+           where in the image it was, then set a trap for there.
+        */
+} codeBuffer;
+
+
+
+static codeBuffer *
+codeBuffer_create(FILE *       const ofP,
+                  unsigned int const initBits,
+                  bool         const lzw) {
+
+    codeBuffer * codeBufferP;
+
+    MALLOCVAR_NOFAIL(codeBufferP);
+
+    codeBufferP->initBits    = initBits;
+    codeBufferP->nBits       = codeBufferP->initBits;
+    codeBufferP->maxCode     = (1 << codeBufferP->nBits) - 1;
+    codeBufferP->maxCodeLimit = lzw ?
+        (stringCode)1 << BITS : (stringCode) (1 << codeBufferP->nBits) - 1; 
+    codeBufferP->byteBufferP = byteBuffer_create(ofP);
+    codeBufferP->curAccum    = 0;
+    codeBufferP->curBits     = 0;
+    codeBufferP->codeCount   = 0;
+
+    return codeBufferP;
+}
+
+
+
+static void
+codeBuffer_destroy(codeBuffer * const codeBufferP) {
+
+    byteBuffer_destroy(codeBufferP->byteBufferP);
+
+    free(codeBufferP);
+}
+
+
+
+static void
+codeBuffer_resetCodeSize(codeBuffer * const codeBufferP) {
+
+    codeBufferP->nBits = codeBufferP->initBits;
+
+    assert(codeBufferP->nBits <= BITS);
+
+    codeBufferP->maxCode = (1 << codeBufferP->nBits) - 1;
+}
+
+
+
+static void
+codeBuffer_increaseCodeSize(codeBuffer * const codeBufferP) {
+
+    ++codeBufferP->nBits;
+
+    assert(codeBufferP->nBits <= BITS);
+
+    codeBufferP->maxCode = (1 << codeBufferP->nBits) - 1;
+}
+
+
+
+static unsigned long const masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
+                                       0x001F, 0x003F, 0x007F, 0x00FF,
+                                       0x01FF, 0x03FF, 0x07FF, 0x0FFF,
+                                       0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
+
+static void
+codeBuffer_output(codeBuffer * const codeBufferP,
+                  stringCode   const code) {
+/*----------------------------------------------------------------------------
+   Output one GIF code to the file, through the code buffer.
+
+   The code is represented as N bits in the file -- the lower
+   N bits of 'code'.  N is a the current code size of *codeBufferP.
+   
+   Id 'code' is the maximum possible code for the current code size
+   for *codeBufferP, increase that code size (unless it's already 
+   maxed out).
+-----------------------------------------------------------------------------*/
+    assert (code <= codeBufferP->maxCode);
+
+    codeBufferP->curAccum &= masks[codeBufferP->curBits];
+
+    if (codeBufferP->curBits > 0)
+        codeBufferP->curAccum |= ((long)code << codeBufferP->curBits);
+    else
+        codeBufferP->curAccum = code;
+
+    codeBufferP->curBits += codeBufferP->nBits;
+
+    while (codeBufferP->curBits >= 8) {
+        byteBuffer_out(codeBufferP->byteBufferP,
+                       codeBufferP->curAccum & 0xff);
+        codeBufferP->curAccum >>= 8;
+        codeBufferP->curBits -= 8;
+    }
+
+    ++codeBufferP->codeCount;
+}
+
+
+
+static void
+codeBuffer_flush(codeBuffer * const codeBufferP) {
+
+    /* Output the possible partial byte in the buffer */
+
+    if (codeBufferP->curBits > 0) {
+        byteBuffer_out(codeBufferP->byteBufferP,
+                       codeBufferP->curAccum & 0xff);
+        codeBufferP->curBits = 0;
+    }
+    byteBuffer_flush(codeBufferP->byteBufferP);
+    
+    byteBuffer_flushFile(codeBufferP->byteBufferP);
+
+    if (verbose)
+        pm_message("%u strings of pixels written to file",
+                   codeBufferP->codeCount);
+    codeBufferP->codeCount = 0;
+}
+
+
+
+typedef struct {
+    codeBuffer * codeBufferP;
+        /* The place to which we write our string codes.
+
+           Constant.
+        */
+    bool lzw;
+        /* We're actually doing LZW compression.  False means we follow
+           the algorithm enough tht an LZW decompressor will recover the
+           proper data, but always using one code per pixel, and therefore
+           not effecting any compression and not using the LZW patent.
+        */
+    unsigned int hshift;
+        /* This is how many bits we shift left a string code in forming the
+           primary hash of the concatenation of that string with another.
+           Constant.
+        */
+
+    /* Codes less than 'clearCode' are singleton pixel codes - each
+       represents the pixel value equal to it.
+
+       Codes greater than 'eofCode' are multipixel string codes.  Each
+       represents a string of pixels that is defined by the preceding
+       stream.
+    */
+    stringCode clearCode;
+        /* The code in an LZW stream that means to clear the string
+           dictionary and start fresh.
+
+           Constant.
+        */
+    stringCode eofCode;
+        /* The code in an LZW stream that means there's no more coming
+
+           Constant.
+        */
+    stringCode initCodeLimit;
+        /* The value of 'codeLimit' at the start of a block.
+
+           Constant.
+        */
+
+    stringCode codeLimit;
+        /* One beyond the maximum code possible with the current code
+           size.
+        */
+
+    struct hashTableEntry * hashTable;
+    stringCode nextUnusedCode;
+        /* Numerically next code available to assign to a a multi-pixel
+           string.  Note that codes for multi-pixel strings are in the
+           upper half of the range of codes, always greater than
+           'clearCode'.
+        */
+
+    stringCode stringSoFar;
+        /* The code for the string we have built so far.  This code indicates
+           one or more pixels that we have encoded but not yet output
+           because we're hoping to match an even longer string.
+
+           Valid only when 'buildingString' is true.
+
+           In the non-lzw case the single pixel to output.
+        */
+    bool buildingString;
+        /* We are in the middle of building a string; 'stringSoFar' describes
+           the pixels in it so far.  The only time this is false is at the
+           very beginning of the stream.
+ 
+           Ignored in the non-lzw case. 
+        */
+} lzwCompressor;
+
+
+
+static lzwCompressor *
+lzw_create(FILE *       const ofP,
+           unsigned int const initBits,
+           bool         const lzw) {
+
+    lzwCompressor * lzwP;
+
+    MALLOCVAR_NOFAIL(lzwP);
+
+    MALLOCARRAY(lzwP->hashTable, HSIZE);
+
+    if (lzwP->hashTable == NULL)
+        pm_error("Couldn't get memory for %u-entry hash table.", HSIZE);
+
+    /* Constants */
+    lzwP->lzw = lzw;
+    lzwP->hshift =
+        nSignificantBits(HSIZE-1) - 1 - nSignificantBits(MAXCMAPSIZE-1);
+    lzwP->clearCode = 1 << (initBits - 1);
+    lzwP->eofCode = lzwP->clearCode + 1;
+    lzwP->initCodeLimit = 1 << initBits;
+
+    lzwP->buildingString = FALSE;
+
+    lzwP->codeBufferP = codeBuffer_create(ofP, initBits, lzw);
+
+    return lzwP;
+}
+
+
+
+static void
+lzw_destroy(lzwCompressor * const lzwP) {
+
+    codeBuffer_destroy(lzwP->codeBufferP);
+
+    free(lzwP->hashTable);
+
+    free(lzwP);
+}
+
+
+
+static void
+lzwHashClear(lzwCompressor * const lzwP) {
+
+    /* Empty the code table */
+
+    unsigned int i;
+
+    for (i = 0; i < HSIZE; ++i)
+        lzwP->hashTable[i].fcode = -1;
+
+    lzwP->nextUnusedCode = lzwP->clearCode + 2;
+
+    
+}
+
+
+
+static void
+lzw_clearBlock(lzwCompressor * const lzwP) {
+/*----------------------------------------------------------------------------
+  
+-----------------------------------------------------------------------------*/
+    lzwHashClear(lzwP);
+
+    codeBuffer_output(lzwP->codeBufferP, lzwP->clearCode);
+
+    codeBuffer_resetCodeSize(lzwP->codeBufferP);
+
+    lzwP->codeLimit = lzwP->initCodeLimit;
+}
+
+
+
+static void
+lzwAdjustCodeSize(lzwCompressor * const lzwP,
+                  stringCode      const newCode) {
+/*----------------------------------------------------------------------------
+   Assuming we just defined code 'newCode', increase the code size as
+   required so that this code fits.
+
+   The decompressor is mimicking our assignment of that code, so knows that
+   we are making this adjustment, so expects codes of the new size.
+-----------------------------------------------------------------------------*/
+    assert(newCode <= lzwP->codeLimit);
+
+    if (newCode == lzwP->codeLimit) {
+        lzwP->codeLimit *= 2;
+        codeBuffer_increaseCodeSize(lzwP->codeBufferP);
+
+        assert(lzwP->codeLimit <= maxCodeLimitLzw);
+    }
+}
+
+
+
+static void
+lzwOutputCurrentString(lzwCompressor * const lzwP) {
+/*----------------------------------------------------------------------------
+   Put a code for the currently built-up string in the output stream.
+
+   Doing this causes a new string code to be defined (code is
+   lzwP->nextUnusedCode), so Caller must add that to the hash.  If
+   that code's size is beyond the overall limit, we reset the hash
+   (which means future codes will start back at the minimum size) and
+   put a clear code in the stream to tell the decompressor to do the
+   same.  So Caller must add it to the hash _before_ calling us.
+
+   Note that in the non-compressing case, the overall limit is small
+   enough to prevent us from ever defining string codes; we'll always
+   reset the hash.
+
+   There's an odd case that always screws up any attempt to make this
+   code cleaner: At the end of the LZW stream, you have to output the
+   code for the final string even though you don't have a following
+   pixel that would make a longer string.  So there's nothing to add
+   to the hash table and no point in allocating a new string code.
+   But the decompressor doesn't know that we're done, so he allocates
+   the next string code and may therefore increase his code length.
+   If we don't do the same, we will write our one last code -- the EOF
+   code -- in a code length smaller than what the decompressor is
+   expecting, and he will have a premature end of stream.
+
+   So this subroutine does run for that final code flush and does some
+   of the motions of defining a new string code, but this subroutine
+   can't update the hash because in that particular case, there's
+   nothing to add.
+-----------------------------------------------------------------------------*/
+    codeBuffer_output(lzwP->codeBufferP, lzwP->stringSoFar);
+    if (lzwP->nextUnusedCode < lzwP->codeBufferP->maxCodeLimit) {
+        /* Allocate the code for the extended string, which Caller
+           should have already put in the hash so he can use it in the
+           future.  Decompressor knows when it sees the code output
+           above to define a string on its end too, using the same
+           string code we do.
+        */
+        stringCode const newCode = lzwP->nextUnusedCode++;
+
+        /* This code may be too big to fit in the current code size, in
+           which case we have to increase the code size (and decompressor
+           will do the same).
+        */
+        lzwAdjustCodeSize(lzwP, newCode);
+    } else {
+        /* Forget all the strings so far; start building again; tell
+           decompressor to do the same.
+        */
+        lzw_clearBlock(lzwP);
+    }
+}
+
+
+
+static void
+lzw_flush(lzwCompressor * const lzwP) {
+
+    if (lzwP->lzw)
+        lzwOutputCurrentString(lzwP);
+        /* Put out the code for the final string. */
+
+    codeBuffer_output(lzwP->codeBufferP, lzwP->eofCode);
+
+    codeBuffer_flush(lzwP->codeBufferP);
+}
+
+
+
+static unsigned int
+primaryHash(stringCode   const baseString,
+            stringCode   const additionalPixel,
+            unsigned int const hshift) {
+
+    unsigned int hash;
+
+    assert(baseString < maxCodeLimitLzw);
+    assert(additionalPixel < MAXCMAPSIZE);
+
+    hash = (additionalPixel << hshift) ^ baseString;
+
+    assert(hash < HSIZE);
+
+    return hash;
+}
+
+    
+
+static void
+lookupInHash(lzwCompressor *  const lzwP,
+             unsigned int     const gifPixel,
+             long             const fcode,
+             bool *           const foundP,
+             unsigned short * const codeP,
+             unsigned int *   const hashP) {
+
+    int disp;
+        /* secondary hash stride (after G. Knott) */
+    int i;
+        /* Index into hash table */
+
+    i = primaryHash(lzwP->stringSoFar, gifPixel, lzwP->hshift);
+    disp = (i == 0) ? 1 : HSIZE - i;
+
+    while (lzwP->hashTable[i].fcode != fcode &&
+           lzwP->hashTable[i].fcode >= 0) {
+        i -= disp;
+        if (i < 0)
+            i += HSIZE;
+    }
+
+    if (lzwP->hashTable[i].fcode == fcode) {
+        /* Found fcode in hash table */
+        *foundP = TRUE;
+        *codeP = lzwP->hashTable[i].ent;
+    } else {
+        /* Found where it _should_ be (but it's not) with primary hash */
+        *foundP = FALSE;
+        *hashP = i;
+    }
+}
+
+
+
+static void
+lzw_encodePixel(lzwCompressor * const lzwP,
+                unsigned int    const gifPixel) {
+
+    bool found;
+    unsigned short code;
+    unsigned int hash;
+        /* Index into hash table where the value should go */
+    
+    assert(gifPixel < 256);
+
+    if (!lzwP->buildingString) {
+        /* Start a new string with just this pixel */
+        lzwP->stringSoFar = gifPixel;
+        lzwP->buildingString = TRUE;
+    } else {
+        long const fcode = ((long) gifPixel << BITS) + lzwP->stringSoFar;
+            /* The encoding of the string we've already recognized plus the
+               instant pixel, to be looked up in the hash of knows strings.
+            */
+    
+        lookupInHash(lzwP, gifPixel, fcode, &found, &code, &hash);
+
+        if (found)
+            /* With this new pixel, it is still a known string; 'code' is
+               its code
+            */
+            lzwP->stringSoFar = code;
+        else {
+            /* It's no longer a known string.  Output the code for the
+               known prefix of the string, thus defining a new string
+               code for possible later use.  Warning:
+               lzwOutputCurrentString() does more than you think. 
+            */
+
+            lzwP->hashTable[hash].ent   = lzwP->nextUnusedCode;
+            lzwP->hashTable[hash].fcode = fcode;
+
+            lzwOutputCurrentString(lzwP);
+
+            /* This singleton pixel starts the next string */
+            lzwP->stringSoFar = gifPixel;
+        }
+    }
+}
+
+
+
+/*
+ * compress stdin to stdout
+ *
+ * Algorithm:  use open addressing double hashing (no chaining) on the
+ * prefix code / next character combination.  We do a variant of Knuth's
+ * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
+ * secondary probe.  Here, the modular division first probe is gives way
+ * to a faster exclusive-or manipulation.  Also do block compression with
+ * an adaptive reset, whereby the code table is cleared when the compression
+ * ratio decreases, but after the table fills.  The variable-length output
+ * codes are re-sized at this point, and a special CLEAR code is generated
+ * for the decompressor.  Late addition:  construct the table according to
+ * file size for noticeable speed improvement on small files.  Please direct
+ * questions about this implementation to ames!jaw.
+ */
+
+static void
+writePixelUncompressed(lzwCompressor * const lzwP,
+                       unsigned int    const gifPixel) {
+                      
+    lzwP->stringSoFar = gifPixel;
+    lzwOutputCurrentString(lzwP);
+
+}    
+
+static void
+writeRaster(struct pam *  const pamP,
+            rowReader *   const rowReaderP,
+            unsigned int  const alphaPlane,
+            unsigned int  const alphaThreshold,
+            struct cmap * const cmapP, 
+            unsigned int  const initBits,
+            FILE *        const ofP,
+            bool          const lzw) {
+/*----------------------------------------------------------------------------
+   Write the raster to file 'ofP'.
+
+   Get the raster to write from 'rowReaderP', which gives tuples whose
+   format is described by 'pamP'.
+
+   Use the colormap 'cmapP' to generate the raster ('rowReaderP' gives
+   pixel values as RGB samples; the GIF raster is colormap indices).
+
+   Write the raster using LZW compression, or uncompressed depending
+   on 'lzw'.
+-----------------------------------------------------------------------------*/
+    lzwCompressor * lzwP;
+    tuple * tuplerow;
+    unsigned int nRowsDone;
+        /* Number of rows we have read so far from the the input (the
+           last of which is the one we're working on now).  Note that
+           in case of interlace, this is not the same thing as the row
+           number of the current row.
+        */
+    
+    lzwP = lzw_create(ofP, initBits, lzw);
+
+    tuplerow = pnm_allocpamrow(pamP);
+
+    lzw_clearBlock(lzwP);
+
+    nRowsDone = 0;
+    
+    while (nRowsDone < pamP->height) {
+        unsigned int col;
+
+        rowReader_read(rowReaderP, tuplerow);
+
+        for (col = 0; col < pamP->width; ++col) {
+            unsigned int const colorIndex =
+                gifPixel(pamP, tuplerow[col], alphaPlane, alphaThreshold,
+                         cmapP);
+            
+                /* The value for the pixel in the GIF image.  I.e. the colormap
+                   index.
+                */
+            if (lzw)
+                lzw_encodePixel(lzwP, colorIndex);
+            else
+                writePixelUncompressed(lzwP, colorIndex);    
+        }
+        ++nRowsDone;
+    }
+    /* Gif is no good with no pixels; fortunately, that's impossible: */
+    assert(nRowsDone > 0);
+
+    lzw_flush(lzwP);
+
+    pnm_freepamrow(tuplerow);
+    
+    lzw_destroy(lzwP);
+}
+
+
+
+
+
+
+
+
+
+static void
+writeGlobalColorMap(FILE *              const ofP,
+                    const struct cmap * const cmapP,
+                    unsigned int        const bitsPerPixel) {
+/*----------------------------------------------------------------------------
+  Write out the Global Color Map
+
+  Note that the Global Color Map is always a power of two colors
+  in size, but *cmapP could be smaller than that.  So we pad with
+  black.
+-----------------------------------------------------------------------------*/
+    unsigned int const colorMapSize = 1 << bitsPerPixel;
+
+    struct pam pam;
+    unsigned int i;
+    tuple tupleRgb255;
+
+    if (verbose)
+        pm_message("Writing %u-entry global colormap for %u colors",
+                   colorMapSize, cmapP->cmapSize);
+
+    pam = cmapP->pam;
+    pam.size = PAM_STRUCT_SIZE(allocation_depth);
+    pam.len = pam.size;
+    pnm_setminallocationdepth(&pam, 3);
+
+    tupleRgb255 = pnm_allocpamtuple(&pam);
+
+    for (i = 0; i < colorMapSize; ++i) {
+        if (i < cmapP->cmapSize) {
+            tuple const color = cmapP->color[cmapP->permi[i]];
+
+            assert(cmapP->permi[i] < cmapP->cmapSize);
+
+            pnm_scaletuple(&pam, tupleRgb255, color, 255);
+            pnm_maketuplergb(&pam, tupleRgb255);
+
+            fputc(tupleRgb255[PAM_RED_PLANE], ofP);
+            fputc(tupleRgb255[PAM_GRN_PLANE], ofP);
+            fputc(tupleRgb255[PAM_BLU_PLANE], ofP);
+        } else {
+            fputc(0, ofP);
+            fputc(0, ofP);
+            fputc(0, ofP);
+        }
+    }
+    pnm_freepamtuple(tupleRgb255);
+}
+        
+
+
+static void
+writeGifHeader(FILE *              const ofP,
+               unsigned int        const width,
+               unsigned int        const height, 
+               unsigned int        const background, 
+               unsigned int        const bitsPerPixel,
+               const struct cmap * const cmapP,
+               char                const comment[]) {
+
+    unsigned int const resolution = bitsPerPixel;
+
+    unsigned char b;
+
+    /* Write the Magic header */
+    if (cmapP->haveTransparent || comment)
+        fwrite("GIF89a", 1, 6, ofP);
+    else
+        fwrite("GIF87a", 1, 6, ofP);
+
+    /* Write out the screen width and height */
+    Putword(width,  ofP);
+    Putword(height, ofP);
+
+    /* Indicate that there is a global color map */
+    b = 0x80;       /* Yes, there is a color map */
+
+    /* OR in the resolution */
+    b |= (resolution - 1) << 4;
+
+    /* OR in the Bits per Pixel */
+    b |= (bitsPerPixel - 1);
+
+    /* Write it out */
+    fputc(b, ofP);
+
+    /* Write out the Background color */
+    assert((unsigned char)background == background);
+    fputc(background, ofP);
+
+    /* Byte of 0's (future expansion) */
+    fputc(0x00, ofP);
+
+    writeGlobalColorMap(ofP, cmapP, bitsPerPixel);
+
+    if (cmapP->haveTransparent) 
+        writeTransparentColorIndexExtension(ofP, cmapP->transparent);
+
+    if (comment)
+        writeCommentExtension(ofP, comment);
+}
+
+
+
+static void
+writeImageHeader(FILE *       const ofP,
+                 unsigned int const leftOffset,
+                 unsigned int const topOffset,
+                 unsigned int const gWidth,
+                 unsigned int const gHeight,
+                 bool         const gInterlace,
+                 unsigned int const initCodeSize) {
+
+    Putword(leftOffset, ofP);
+    Putword(topOffset,  ofP);
+    Putword(gWidth,     ofP);
+    Putword(gHeight,    ofP);
+
+    /* Write out whether or not the image is interlaced */
+    if (gInterlace)
+        fputc(0x40, ofP);
+    else
+        fputc(0x00, ofP);
+
+    /* Write out the initial code size */
+    fputc(initCodeSize, ofP);
+}
+
+
+
+static void
+reportImageInfo(bool         const interlace,
+                unsigned int const background,
+                unsigned int const bitsPerPixel) {
+
+    if (verbose) {
+        if (interlace)
+            pm_message("interlaced");
+        else
+            pm_message("not interlaced");
+        pm_message("Background color index = %u", background);
+        pm_message("%u bits per pixel", bitsPerPixel);
+    }
+}
+
+
+
+static void
+gifEncode(struct pam *  const pamP,
+          FILE *        const ofP, 
+          pm_filepos    const rasterPos,
+          bool          const gInterlace,
+          int           const background, 
+          unsigned int  const bitsPerPixel,
+          struct cmap * const cmapP,
+          char          const comment[],
+          bool          const lzw) {
+
+    unsigned int const leftOffset = 0;
+    unsigned int const topOffset  = 0;
+
+    unsigned int const initCodeSize = bitsPerPixel <= 1 ? 2 : bitsPerPixel;
+        /* The initial code size */
+
+    sample const alphaThreshold = (pamP->maxval + 1) / 2;
+        /* Levels below this in the alpha plane indicate transparent
+           pixels in the output image.
+        */
+
+    unsigned int const alphaPlane = pamAlphaPlane(pamP);
+
+    rowReader * rowReaderP;
+
+    reportImageInfo(gInterlace, background, bitsPerPixel);
+
+    writeGifHeader(ofP, pamP->width, pamP->height, background,
+                   bitsPerPixel, cmapP, comment);
+
+    /* Write an Image separator */
+    fputc(',', ofP);
+
+    writeImageHeader(ofP, leftOffset, topOffset, pamP->width, pamP->height,
+                     gInterlace, initCodeSize);
+
+    rowReaderP = rowReader_create(pamP, rasterPos, gInterlace);
+
+    /* Write the actual raster */
+
+    writeRaster(pamP, rowReaderP, alphaPlane, alphaThreshold,
+                cmapP, initCodeSize + 1, ofP, lzw);
+
+    rowReader_destroy(rowReaderP);
+
+    /* Write out a zero length data block (to end the series) */
+    fputc(0, ofP);
+
+    /* Write the GIF file terminator */
+    fputc(';', ofP);
+}
+
+
+
+static void
+reportTransparent(struct cmap * const cmapP) {
+
+    if (verbose) {
+        if (cmapP->haveTransparent) {
+            tuple const color = cmapP->color[cmapP->permi[cmapP->transparent]];
+            pm_message("Color %u (%lu, %lu, %lu) is transparent",
+                       cmapP->transparent,
+                       color[PAM_RED_PLANE],
+                       color[PAM_GRN_PLANE],
+                       color[PAM_BLU_PLANE]);
+        } else
+            pm_message("No transparent color");
+    }
+}
+
+
+
+static void
+computeTransparent(char          const colorarg[], 
+                   bool          const usingFakeTrans,
+                   unsigned int  const fakeTransparent,
+                   struct cmap * const cmapP) {
+/*----------------------------------------------------------------------------
+   Figure out the color index (index into the colormap) of the color
+   that is to be transparent in the GIF.
+
+   colorarg[] is the string that specifies the color the user wants to
+   be transparent (e.g. "red", "#fefefe").  Its maxval is the maxval
+   of the colormap.  'cmap' is the full colormap except that its
+   'transparent' component isn't valid.
+
+   colorarg[] is a standard Netpbm color specification, except that
+   may have a "=" prefix, which means it specifies a particular exact
+   color, as opposed to without the "=", which means "the color that
+   is closest to this and actually in the image."
+
+   colorarg[] null means the color didn't ask for a particular color
+   to be transparent.
+
+   Establish no transparent color if colorarg[] specifies an exact
+   color and that color is not in the image.  Also issue an
+   informational message.
+
+   'usingFakeTrans' means pixels will be transparent because of something
+   other than their foreground color, and 'fakeTransparent' is the
+   color map index for transparent colors.
+-----------------------------------------------------------------------------*/
+    if (colorarg) {
+        const char * colorspec;
+        bool exact;
+        tuple transcolor;
+        bool found;
+        int presortColorindex;
+        
+        if (colorarg[0] == '=') {
+            colorspec = &colorarg[1];
+            exact = TRUE;
+        } else {
+            colorspec = colorarg;
+            exact = FALSE;
+        }
+
+        transcolor = pnm_parsecolor(colorspec, cmapP->pam.maxval);
+        pnm_lookuptuple(&cmapP->pam, cmapP->tuplehash, transcolor, &found,
+                        &presortColorindex);
+        
+        if (found) {
+            cmapP->haveTransparent = TRUE;
+            cmapP->transparent = cmapP->perm[presortColorindex];
+        } else if (!exact) {
+            cmapP->haveTransparent = TRUE;
+            cmapP->transparent =
+                cmapP->perm[closestColor(transcolor, &cmapP->pam, cmapP)];
+        } else {
+            cmapP->haveTransparent = FALSE;
+            pm_message("Warning: specified transparent color "
+                       "does not occur in image.");
+        }
+    } else if (usingFakeTrans) {
+        cmapP->haveTransparent = TRUE;
+        cmapP->transparent = fakeTransparent;
+    } else
+        cmapP->haveTransparent = FALSE;
+
+    reportTransparent(cmapP);
+}
+
+
+
+static unsigned int
+sortOrder(tuple        const tuple,
+          struct pam * const pamP) {
+    
+    if (pamP->depth < 3)
+        return tuple[0];
+    else
+        return ((tuple[0] * MAXCMAPSIZE) + tuple[1]) * MAXCMAPSIZE + tuple[2];
+}
+
+
+
+
+static void
+sortColormap(bool          const sort,
+             struct cmap * const cmapP) {
+/*----------------------------------------------------------------------------
+   Sort (in place) the colormap *cmapP.
+
+   Create the perm[] and permi[] mappings for the colormap.
+
+   'sort' is logical:  true means to sort the colormap by red intensity,
+   then by green intensity, then by blue intensity.  False means a null
+   sort -- leave it in the same order in which we found it.
+-----------------------------------------------------------------------------*/
+    tuple * const color = cmapP->color;
+    int * const perm = cmapP->perm;
+    int * const permi = cmapP->permi;
+    struct pam * const pamP = &cmapP->pam;
+    unsigned int const cmapSize = cmapP->cmapSize;
+    
+    unsigned int i;
+
+    /* We will sort permi[].  So we first set up permi[] to reflect the
+       original, unsorted order.
+    */
+    for (i=0; i < cmapSize; i++)
+        permi[i] = i;
+
+    if (sort) {
+        pm_message("sorting colormap");
+        for (i = 0; i < cmapSize; ++i) {
+            unsigned int j;
+            for (j = i+1; j < cmapSize; ++j) {
+                if (sortOrder(color[permi[i]], pamP) >
+                    sortOrder(color[permi[j]], pamP)) {
+
+                    sample tmp;
+                    
+                    tmp = permi[i]; permi[i] = permi[j]; permi[j] = tmp;
+                }
+            }
+        }
+    }
+    for (i = 0; i < cmapSize; ++i)
+        perm[permi[i]] = i;
+}
+
+
+
+static void
+addToColormap(struct cmap *  const cmapP, 
+              const char *   const colorspec, 
+              unsigned int * const newIndexP) {
+/*----------------------------------------------------------------------------
+  Add a new entry to the colormap.  Make the color that specified by
+  'colorspec', and return the index of the new entry as *newIndexP.
+
+  'colorspec' is a color specification given by the user, e.g.
+  "red" or "rgb:ff/03/0d".  The maxval for this color specification is
+  that for the colormap *cmapP.
+-----------------------------------------------------------------------------*/
+    tuple const transcolor = pnm_parsecolor(colorspec, cmapP->pam.maxval);
+
+    unsigned int const colorIndex = cmapP->cmapSize++;
+
+    cmapP->color[colorIndex] = pnm_allocpamtuple(&cmapP->pam);
+
+    if (cmapP->pam.depth < 3) {
+        if (!pnm_rgbtupleisgray(transcolor))
+            pm_error("Image is grayscale, but color '%s' is not gray.  "
+                     "It is (%lu, %lu, %lu)",
+                     colorspec,
+                     transcolor[PAM_RED_PLANE],
+                     transcolor[PAM_GRN_PLANE],
+                     transcolor[PAM_BLU_PLANE]);
+        else
+            cmapP->color[colorIndex][0] = transcolor[0];
+    } else {
+        pnm_assigntuple(&cmapP->pam, cmapP->color[colorIndex], transcolor);
+    }
+    *newIndexP = colorIndex;
+}
+
+
+
+static void
+colormapFromFile(char               const filespec[],
+                 unsigned int       const maxcolors,
+                 tupletable *       const tupletableP, 
+                 struct pam *       const mapPamP,
+                 unsigned int *     const colorCountP) {
+/*----------------------------------------------------------------------------
+   Read a colormap from the Netpbm file filespec[].  Return a
+   tupletable of the colors in it (which is practically a colormap) as
+   *tupletableP and the format of those tuples as *mapPamP.  Return
+   the number of colors as *colorsCountP.
+-----------------------------------------------------------------------------*/
+    FILE * mapfileP;
+    tuple ** colors;
+    unsigned int colorCount;
+
+    mapfileP = pm_openr(filespec);
+    colors = pnm_readpam(mapfileP, mapPamP, PAM_STRUCT_SIZE(tuple_type));
+    pm_close(mapfileP);
+
+    pm_message("computing other colormap ...");
+    
+    pnm_computetuplefreqtable(mapPamP, colors, maxcolors, &colorCount);
+
+    *colorCountP = colorCount;
+
+    pnm_freepamarray(colors, mapPamP); 
+}
+
+
+
+static void
+computeColormapFromInput(struct pam *   const pamP,
+                         unsigned int   const maxcolors,
+                         unsigned int   const nInputComp,
+                         struct pam *   const mapPamP,
+                         unsigned int * const colorCountP,
+                         tupletable *   const tuplefreqP) {
+    
+    tupletable tuplefreq;
+
+    pm_message("computing colormap...");
+
+    tuplefreq = pnm_computetuplefreqtable3(
+        pamP, NULL, maxcolors, nInputComp, pamP->maxval, colorCountP);
+
+    *mapPamP = *pamP;
+    mapPamP->depth = nInputComp;
+
+    *tuplefreqP = tuplefreq;
+}
+
+
+
+static void
+computeLibnetpbmColormap(struct pam *   const pamP,
+                         bool           const haveAlpha,
+                         const char *   const mapfile,
+                         tuple *        const color,
+                         tuplehash *    const tuplehashP,
+                         struct pam *   const mapPamP,
+                         unsigned int * const colorCountP) {
+/*----------------------------------------------------------------------------
+   Compute a colormap, libnetpbm style, for the image described by
+   'pamP', which is positioned to the raster.
+
+   If 'mapfile' is non-null, Use the colors in that (Netpbm) file for
+   the color map instead of the colors in 'pamP'.
+
+   Return the colormap as color[] and *tuplehashP.  Return the format
+   of those tuples as *mapPamP.
+
+   The tuples of the color map have a meaningful depth of 1 (grayscale) or 3
+   (color) and *mapPamP reflects that.
+
+   While we're at it, count the colors and validate that there aren't
+   too many.  Return the count as *colorCountP.  In determining if there are
+   too many, allow one slot for a fake transparency color if 'haveAlpha'
+   is true.  If there are too many, issue an error message and abort the
+   program.
+-----------------------------------------------------------------------------*/
+    unsigned int const maxcolors = haveAlpha ? MAXCMAPSIZE - 1 : MAXCMAPSIZE;
+        /* The most colors we can tolerate in the image.  If we have
+           our own made-up entry in the colormap for transparency, it
+           isn't included in this count.
+        */
+    unsigned int const nInputComp = haveAlpha ? pamP->depth - 1 : pamP->depth;
+        /* Number of color components (not alpha) in the input image */
+
+    unsigned int i;
+    tupletable tuplefreq;
+    unsigned int colorCount;
+
+    if (mapfile) {
+        /* Read the colormap from a separate colormap file. */
+        colormapFromFile(mapfile, maxcolors, &tuplefreq, mapPamP,
+                         &colorCount);
+
+        if (mapPamP->depth != nInputComp)
+            pm_error("Depth of map file (%u) does not match number of "
+                     "color components in input file (%u)",
+                      mapPamP->depth, pamP->depth);
+        if (mapPamP->maxval != pamP->maxval)
+            pm_error("Maxval of map file (%lu) does not match maxval of "
+                     "input file (%lu)", mapPamP->maxval, pamP->maxval);
+    } else
+        computeColormapFromInput(pamP, maxcolors, nInputComp, 
+                                 mapPamP, &colorCount, &tuplefreq);
+    
+    if (tuplefreq == NULL)
+        pm_error("too many colors - try doing a 'pnmquant %u'", maxcolors);
+
+    pm_message("%u colors found", colorCount);
+
+    for (i = 0; i < colorCount; ++i) {
+        color[i] = pnm_allocpamtuple(mapPamP);
+        pnm_assigntuple(mapPamP, color[i], tuplefreq[i]->tuple);
+    }
+
+    /* And make a hash table for fast lookup. */
+    *tuplehashP =
+        pnm_computetupletablehash(mapPamP, tuplefreq, colorCount);
+
+    *colorCountP = colorCount;
+
+    pnm_freetupletable(mapPamP, tuplefreq);
+}
+
+
+
+static void
+destroyCmap(struct cmap * const cmapP) {
+
+    unsigned int colorIndex;
+    
+    for (colorIndex = 0; colorIndex < cmapP->cmapSize; ++colorIndex)
+        pnm_freepamtuple(cmapP->color[colorIndex]);
+
+    pnm_destroytuplehash(cmapP->tuplehash);
+}
+
+
+
+int
+main(int argc, char *argv[]) {
+    struct cmdlineInfo cmdline;
+    FILE * ifP;
+    struct pam pam;
+    unsigned int bitsPerPixel;
+    pm_filepos rasterPos;
+
+    struct cmap cmap;
+        /* The colormap, with all its accessories */
+    unsigned int fakeTransparent;
+        /* colormap index of the fake transparency color we're using to
+           implement the alpha mask.  Undefined if we're not doing an alpha
+           mask.
+        */
+    
+    pnm_init(&argc, argv);
+    
+    parseCommandLine(argc, argv, &cmdline);
+    
+    verbose = cmdline.verbose;
+    
+    ifP = pm_openr_seekable(cmdline.input_filespec);
+    
+    pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
+    
+    pm_tell2(ifP, &rasterPos, sizeof(rasterPos));
+    
+    computeLibnetpbmColormap(&pam, !!pamAlphaPlane(&pam), cmdline.mapfile, 
+                             cmap.color, &cmap.tuplehash,
+                             &cmap.pam, &cmap.cmapSize);
+    
+    assert(cmap.pam.maxval == pam.maxval);
+
+    if (pamAlphaPlane(&pam)) {
+        /* Add a fake entry to the end of the colormap for transparency.  
+           Make its color black. 
+        */
+        addToColormap(&cmap, cmdline.alphacolor, &fakeTransparent);
+    }
+    sortColormap(cmdline.sort, &cmap);
+
+    bitsPerPixel = pm_maxvaltobits(cmap.cmapSize-1);
+
+    computeTransparent(cmdline.transparent,
+                       !!pamAlphaPlane(&pam), fakeTransparent, &cmap);
+
+    /* All set, let's do it. */
+    gifEncode(&pam, stdout, rasterPos,
+              cmdline.interlace, 0, bitsPerPixel, &cmap, cmdline.comment,
+              !cmdline.nolzw);
+    
+    destroyCmap(&cmap);
+
+    pm_close(ifP);
+    pm_close(stdout);
+    
+    return 0;
+}
+
+
+
+/*============================================================================
+  Original version, named 'ppmgif' was by Jef Poskanzer in 1989, based
+  on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>.A Lempel-Zim
+  compression based on "compress".
+
+  Switched to use libnetpbm PAM facilities (ergo process PAM images)
+  and renamed 'pamtogif' by Bryan Henderson November 2006.
+
+  The non-LZW GIF generation stuff was adapted from the Independent
+  JPEG Group's djpeg on 2001.09.29.  In 2006.12 the output subroutines
+  were rewritten; now no uncompressed output subroutines are derived from
+  the Independent JPEG Group's source code.
+
+ 
+  Copyright (C) 1989 by Jef Poskanzer.
+ 
+  Permission to use, copy, modify, and distribute this software and its
+  documentation for any purpose and without fee is hereby granted, provided
+  that the above copyright notice appear in all copies and that both that
+  copyright notice and this permission notice appear in supporting
+  documentation.  This software is provided "as is" without express or
+  implied warranty.
+ 
+  The Graphics Interchange Format(c) is the Copyright property of
+  CompuServe Incorporated.  GIF(sm) is a Service Mark property of
+  CompuServe Incorporated.
+============================================================================*/
diff --git a/converter/other/pamtopnm.c b/converter/other/pamtopnm.c
index cc1164da..6835b43f 100644
--- a/converter/other/pamtopnm.c
+++ b/converter/other/pamtopnm.c
@@ -108,6 +108,7 @@ main(int argc, char *argv[]) {
 
     struct cmdlineInfo cmdline;
     FILE* ifP;
+    bool eof;   /* no more images in input stream */
     struct pam inpam;   /* Input PAM image */
     struct pam outpam;  /* Output PNM image */
 
@@ -117,39 +118,45 @@ main(int argc, char *argv[]) {
 
     ifP = pm_openr(cmdline.inputFilespec);
 
-    pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
+    eof = FALSE;
+    while (!eof) {
+        pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
 
-    validateTupleType(inpam, cmdline.assume);
+        validateTupleType(inpam, cmdline.assume);
 
-    outpam = inpam;
-    outpam.file = stdout;
-    
-    if (inpam.depth < 3) {
-        outpam.depth = 1;
-        if (inpam.maxval == 1)
-            outpam.format = PBM_FORMAT;
-        else 
-            outpam.format = PGM_FORMAT;
-    } else {
-        outpam.depth = 3;
-        outpam.format = PPM_FORMAT;
-    }
+        outpam = inpam;
+        outpam.file = stdout;
+        
+        if (inpam.depth < 3) {
+            outpam.depth = 1;
+            if (inpam.maxval == 1)
+                outpam.format = PBM_FORMAT;
+            else 
+                outpam.format = PGM_FORMAT;
+        } else {
+            outpam.depth = 3;
+            outpam.format = PPM_FORMAT;
+        }
 
-    pnm_writepaminit(&outpam);
+        pnm_writepaminit(&outpam);
 
-    {
-        tuple *tuplerow;
-        
-        tuplerow = pnm_allocpamrow(&inpam);      
-        { 
-            int row;
+        {
+            tuple *tuplerow;
             
-            for (row = 0; row < inpam.height; row++) {
-                pnm_readpamrow(&inpam, tuplerow);
-                pnm_writepamrow(&outpam, tuplerow);
+            tuplerow = pnm_allocpamrow(&inpam);      
+            { 
+                int row;
+                
+                for (row = 0; row < inpam.height; row++) {
+                    pnm_readpamrow(&inpam, tuplerow);
+                    pnm_writepamrow(&outpam, tuplerow);
+                }
             }
+            pnm_freepamrow(tuplerow);        
         }
-        pnm_freepamrow(tuplerow);        
+
+        pnm_nextimage(ifP, &eof);
     }
+
     return 0;
 }
diff --git a/converter/other/pamtosvg/curve.h b/converter/other/pamtosvg/curve.h
index ee046620..2f010d45 100644
--- a/converter/other/pamtosvg/curve.h
+++ b/converter/other/pamtosvg/curve.h
@@ -77,14 +77,16 @@ extern curve_type copy_most_of_curve (curve_type c);
 /* Free the memory C uses.  */
 extern void free_curve (curve_type c);
 
+/* Like `append_pixel', for a point in real coordinates.  */
+void
+append_point(curve_type  const curve,
+             float_coord const coord);
+
 /* Append the point P to the end of C's list.  */
 void
 append_pixel(curve_type    const c,
              pm_pixelcoord const p);
 
-/* Like `append_pixel', for a point in real coordinates.  */
-extern void append_point (curve_type const c, float_coord const p);
-
 /* Write some or all, respectively, of the curve C in human-readable
    form to the log file, if logging is enabled.  */
 extern void log_curve (curve_type c, bool print_t);
diff --git a/converter/other/pamtosvg/fit.c b/converter/other/pamtosvg/fit.c
index 08db41db..2fa64500 100644
--- a/converter/other/pamtosvg/fit.c
+++ b/converter/other/pamtosvg/fit.c
@@ -54,21 +54,6 @@ typedef struct index_list
 #define INDEX_LIST_LENGTH(i_l)  ((i_l).length)
 #define GET_LAST_INDEX(i_l)  ((i_l).data[INDEX_LIST_LENGTH (i_l) - 1])
 
-static void append_index (index_list_type *, unsigned);
-static void free_index_list (index_list_type *);
-static index_list_type new_index_list (void);
-static void remove_adjacent_corners (index_list_type *, unsigned, bool,
-                     at_exception_type * exception);
-static void filter (curve_type, fitting_opts_type *);
-static void find_vectors
-  (unsigned const, pixel_outline_type const, vector_type * const, vector_type * const, unsigned const);
-static float find_error (curve_type, spline_type, unsigned *,
-               at_exception_type * exception);
-static vector_type find_half_tangent (curve_type, bool start, unsigned *, unsigned);
-static void find_tangent (curve_type, bool, bool, unsigned);
-static void remove_knee_points (curve_type const, bool const);
-static void set_initial_parameter_values (curve_type);
-static float distance (float_coord, float_coord);
 
 
 static pm_pixelcoord
@@ -86,6 +71,50 @@ real_to_int_coord(float_coord const real_coord) {
 }
 
 
+/* Lists of array indices (well, that is what we use it for).  */
+
+static index_list_type
+new_index_list (void)
+{
+  index_list_type index_list;
+
+  index_list.data = NULL;
+  INDEX_LIST_LENGTH (index_list) = 0;
+
+  return index_list;
+}
+
+static void
+free_index_list (index_list_type *index_list)
+{
+  if (INDEX_LIST_LENGTH (*index_list) > 0)
+    {
+      free (index_list->data);
+      index_list->data = NULL;
+      INDEX_LIST_LENGTH (*index_list) = 0;
+    }
+}
+
+static void
+append_index (index_list_type *list, unsigned new_index)
+{
+  INDEX_LIST_LENGTH (*list)++;
+  REALLOCARRAY_NOFAIL(list->data, INDEX_LIST_LENGTH(*list));
+  list->data[INDEX_LIST_LENGTH (*list) - 1] = new_index;
+}
+
+
+/* Return the Euclidean distance between P1 and P2.  */
+
+static float
+distance (float_coord p1, float_coord p2)
+{
+  float x = p1.x - p2.x, y = p1.y - p2.y, z = p1.z - p2.z;
+  return (float) sqrt (SQR(x) + SQR(y) + SQR(z));
+}
+
+
+
 static void
 appendCorner(index_list_type *  const cornerListP,
              unsigned int       const pixelSeq,
@@ -102,6 +131,45 @@ appendCorner(index_list_type *  const cornerListP,
 
 
 static void
+find_vectors(unsigned int       const test_index,
+             pixel_outline_type const outline,
+             vector_type *      const in,
+             vector_type *      const out,
+             unsigned int       const corner_surround) {
+/*----------------------------------------------------------------------------
+  Return the difference vectors coming in and going out of the outline
+  OUTLINE at the point whose index is TEST_INDEX.  In Phoenix,
+  Schneider looks at a single point on either side of the point we're
+  considering.  That works for him because his points are not touching.
+  But our points *are* touching, and so we have to look at
+  `corner_surround' points on either side, to get a better picture of
+  the outline's shape.
+-----------------------------------------------------------------------------*/
+    int i;
+    unsigned n_done;
+    pm_pixelcoord const candidate = O_COORDINATE(outline, test_index);
+
+    in->dx  = in->dy  = in->dz  = 0.0;
+    out->dx = out->dy = out->dz = 0.0;
+    
+    /* Add up the differences from p of the `corner_surround' points
+       before p.
+    */
+    for (i = O_PREV(outline, test_index), n_done = 0;
+         n_done < corner_surround;
+         i = O_PREV(outline, i), ++n_done)
+        *in = Vadd(*in, IPsubtract(O_COORDINATE(outline, i), candidate));
+    
+    /* And the points after p. */
+    for (i = O_NEXT (outline, test_index), n_done = 0;
+         n_done < corner_surround;
+         i = O_NEXT(outline, i), ++n_done)
+        *out = Vadd(*out, IPsubtract(O_COORDINATE(outline, i), candidate));
+}
+
+
+
+static void
 lookAheadForBetterCorner(pixel_outline_type  const outline,
                          unsigned int        const basePixelSeq,
                          float               const baseCornerAngle,
@@ -210,6 +278,287 @@ establishCornerSearchLimits(pixel_outline_type  const outline,
 
 
 static void
+remove_adjacent_corners(index_list_type *   const list,
+                        unsigned int        const last_index,
+                        bool                const remove_adj_corners,
+                        at_exception_type * const exception) {
+/*----------------------------------------------------------------------------
+   Remove adjacent points from the index list LIST.  We do this by first
+   sorting the list and then running through it.  Since these lists are
+   quite short, a straight selection sort (e.g., p.139 of the Art of
+   Computer Programming, vol.3) is good enough.  LAST_INDEX is the index
+   of the last pixel on the outline, i.e., the next one is the first
+   pixel. We need this for checking the adjacency of the last corner.
+
+   We need to do this because the adjacent corners turn into
+   two-pixel-long curves, which can only be fit by straight lines.
+-----------------------------------------------------------------------------*/
+  unsigned int j;
+  unsigned int last;
+  index_list_type new_list = new_index_list ();
+
+  for (j = INDEX_LIST_LENGTH (*list) - 1; j > 0; j--)
+    {
+      unsigned search;
+      unsigned temp;
+      /* Find maximal element below `j'.  */
+      unsigned max_index = j;
+
+      for (search = 0; search < j; search++)
+        if (GET_INDEX (*list, search) > GET_INDEX (*list, max_index))
+          max_index = search;
+
+      if (max_index != j)
+        {
+          temp = GET_INDEX (*list, j);
+          GET_INDEX (*list, j) = GET_INDEX (*list, max_index);
+          GET_INDEX (*list, max_index) = temp;
+      
+      /* xx -- really have to sort?  */
+      LOG ("needed exchange");
+      at_exception_warning(exception, "needed exchange");
+        }
+    }
+
+  /* The list is sorted.  Now look for adjacent entries.  Each time
+     through the loop we insert the current entry and, if appropriate,
+     the next entry.  */
+  for (j = 0; j < INDEX_LIST_LENGTH (*list) - 1; j++)
+    {
+      unsigned current = GET_INDEX (*list, j);
+      unsigned next = GET_INDEX (*list, j + 1);
+
+      /* We should never have inserted the same element twice.  */
+      /* assert (current != next); */
+
+      if ((remove_adj_corners) && ((next == current + 1) || (next == current)))
+        j++;
+
+      append_index (&new_list, current);
+    }
+
+  /* Don't append the last element if it is 1) adjacent to the previous
+     one; or 2) adjacent to the very first one.  */
+  last = GET_LAST_INDEX (*list);
+  if (INDEX_LIST_LENGTH (new_list) == 0
+      || !(last == GET_LAST_INDEX (new_list) + 1
+           || (last == last_index && GET_INDEX (*list, 0) == 0)))
+    append_index (&new_list, last);
+
+  free_index_list (list);
+  *list = new_list;
+}
+
+/* A ``knee'' is a point which forms a ``right angle'' with its
+   predecessor and successor.  See the documentation (the `Removing
+   knees' section) for an example and more details.
+
+   The argument CLOCKWISE tells us which direction we're moving.  (We
+   can't figure that information out from just the single segment with
+   which we are given to work.)
+
+   We should never find two consecutive knees.
+
+   Since the first and last points are corners (unless the curve is
+   cyclic), it doesn't make sense to remove those.  */
+
+/* This evaluates to true if the vector V is zero in one direction and
+   nonzero in the other.  */
+#define ONLY_ONE_ZERO(v)                                                \
+  (((v).dx == 0.0 && (v).dy != 0.0) || ((v).dy == 0.0 && (v).dx != 0.0))
+
+/* There are four possible cases for knees, one for each of the four
+   corners of a rectangle; and then the cases differ depending on which
+   direction we are going around the curve.  The tests are listed here
+   in the order of upper left, upper right, lower right, lower left.
+   Perhaps there is some simple pattern to the
+   clockwise/counterclockwise differences, but I don't see one.  */
+#define CLOCKWISE_KNEE(prev_delta, next_delta)                                                  \
+  ((prev_delta.dx == -1.0 && next_delta.dy == 1.0)                                              \
+   || (prev_delta.dy == 1.0 && next_delta.dx == 1.0)                                    \
+   || (prev_delta.dx == 1.0 && next_delta.dy == -1.0)                                   \
+   || (prev_delta.dy == -1.0 && next_delta.dx == -1.0))
+
+#define COUNTERCLOCKWISE_KNEE(prev_delta, next_delta)                                   \
+  ((prev_delta.dy == 1.0 && next_delta.dx == -1.0)                                              \
+   || (prev_delta.dx == 1.0 && next_delta.dy == 1.0)                                    \
+   || (prev_delta.dy == -1.0 && next_delta.dx == 1.0)                                   \
+   || (prev_delta.dx == -1.0 && next_delta.dy == -1.0))
+
+
+
+static void
+remove_knee_points(curve_type const curve,
+                   bool       const clockwise) {
+
+      unsigned const offset = (CURVE_CYCLIC(curve) == true) ? 0 : 1;
+      curve_type const trimmed_curve = copy_most_of_curve(curve);
+
+      pm_pixelcoord previous;
+      unsigned i;
+
+      if (!CURVE_CYCLIC(curve))
+          append_pixel(trimmed_curve,
+                       real_to_int_coord(CURVE_POINT(curve, 0)));
+
+      previous = real_to_int_coord(CURVE_POINT(curve,
+                                               CURVE_PREV(curve, offset)));
+
+      for (i = offset; i < CURVE_LENGTH (curve) - offset; ++i) {
+          pm_pixelcoord const current =
+              real_to_int_coord(CURVE_POINT(curve, i));
+          pm_pixelcoord const next =
+              real_to_int_coord(CURVE_POINT(curve, CURVE_NEXT(curve, i)));
+          vector_type const prev_delta = IPsubtract(previous, current);
+          vector_type const next_delta = IPsubtract(next, current);
+
+          if (ONLY_ONE_ZERO(prev_delta) && ONLY_ONE_ZERO(next_delta)
+              && ((clockwise && CLOCKWISE_KNEE(prev_delta, next_delta))
+                  || (!clockwise
+                      && COUNTERCLOCKWISE_KNEE(prev_delta, next_delta))))
+              LOG2(" (%d,%d)", current.col, current.row);
+          else {
+              previous = current;
+              append_pixel(trimmed_curve, current);
+          }
+      }
+
+      if (!CURVE_CYCLIC(curve))
+          append_pixel(trimmed_curve,
+                       real_to_int_coord(LAST_CURVE_POINT(curve)));
+
+      if (CURVE_LENGTH(trimmed_curve) == CURVE_LENGTH(curve))
+          LOG(" (none)");
+
+      LOG(".\n");
+
+      free_curve(curve);
+      *curve = *trimmed_curve;
+      free(trimmed_curve);      /* free_curve? --- Masatake */
+}
+
+
+
+/* Smooth the curve by adding in neighboring points.  Do this
+   `filter_iterations' times.  But don't change the corners.  */
+
+static void
+filter(curve_type          const curve,
+       fitting_opts_type * const fitting_opts) {
+
+    unsigned iteration, this_point;
+    unsigned offset = (CURVE_CYCLIC (curve) == true) ? 0 : 1;
+    float_coord prev_new_point;
+    
+    /* We must have at least three points---the previous one, the current
+       one, and the next one.  But if we don't have at least five, we will
+       probably collapse the curve down onto a single point, which means
+       we won't be able to fit it with a spline.
+    */
+    if (CURVE_LENGTH (curve) < 5) {
+        LOG1 ("Length is %u, not enough to filter.\n", CURVE_LENGTH (curve));
+        return;
+    }
+
+    prev_new_point.x = FLT_MAX;
+    prev_new_point.y = FLT_MAX;
+    prev_new_point.z = FLT_MAX;
+    
+    for (iteration = 0;
+         iteration < fitting_opts->filter_iterations;
+         ++iteration) {
+        curve_type newcurve = copy_most_of_curve (curve);
+        bool collapsed = false;
+        
+        /* Keep the first point on the curve.  */
+        if (offset)
+            append_point (newcurve, CURVE_POINT (curve, 0));
+        
+        for (this_point = offset;
+             this_point < CURVE_LENGTH (curve) - offset;
+             ++this_point) {
+            vector_type in, out, sum;
+            float_coord new_point;
+            
+            /* Calculate the vectors in and out, computed by looking
+               at n points on either side of this_point. Experimental
+               it was found that 2 is optimal.
+            */
+
+            signed int prev, prevprev; /* have to be signed */
+            unsigned int next, nextnext;
+            float_coord candidate = CURVE_POINT (curve, this_point);
+            
+            prev = CURVE_PREV (curve, this_point);
+            prevprev = CURVE_PREV (curve, prev);
+            next = CURVE_NEXT (curve, this_point);
+            nextnext = CURVE_NEXT (curve, next);
+            
+            /* Add up the differences from p of the `surround' points
+               before p.
+            */
+            in.dx = in.dy = in.dz = 0.0;
+
+            in = Vadd (in, Psubtract (CURVE_POINT (curve, prev), candidate));
+            if (prevprev >= 0)
+                in = Vadd(in,
+                          Psubtract(CURVE_POINT (curve, prevprev), candidate));
+            
+            /* And the points after p.  Don't use more points after p than we
+               ended up with before it.
+            */
+            out.dx = out.dy = out.dz = 0.0;
+            
+            out = Vadd (out, Psubtract (CURVE_POINT (curve, next), candidate));
+            if (nextnext < CURVE_LENGTH (curve))
+                out = Vadd(out,
+                           Psubtract(CURVE_POINT (curve, nextnext),
+                                     candidate));
+            
+            /* Start with the old point.  */
+            new_point = candidate;
+            sum = Vadd (in, out);
+            /* We added 2*n+2 points, so we have to divide the sum by 2*n+2 */
+            new_point.x += sum.dx / 6;
+            new_point.y += sum.dy / 6;
+            new_point.z += sum.dz / 6;
+            if (fabs (prev_new_point.x - new_point.x) < 0.3
+                && fabs (prev_new_point.y - new_point.y) < 0.3
+                && fabs (prev_new_point.z - new_point.z) < 0.3) {
+                collapsed = true;
+                break;
+            }
+            
+            
+            /* Put the newly computed point into a separate curve, so it
+               doesn't affect future computation (on this iteration).
+            */
+            append_point (newcurve, prev_new_point = new_point);
+        }
+        
+        if (collapsed)
+            free_curve (newcurve);
+        else {
+            /* Just as with the first point, we have to keep the last
+               point.
+            */
+            if (offset)
+                append_point (newcurve, LAST_CURVE_POINT (curve));
+            
+            /* Set the original curve to the newly filtered one, and go
+               again.
+            */
+            free_curve (curve);
+            *curve = *newcurve;
+        }
+        free (newcurve);
+    }
+    log_curve (curve, false);
+}
+
+
+
+static void
 removeAdjacent(index_list_type *   const cornerListP,
                pixel_outline_type  const outline,
                fitting_opts_type * const fittingOptsP,
@@ -951,6 +1300,210 @@ logSplineFit(spline_type const spline) {
 
 
 
+static vector_type
+find_half_tangent(curve_type     const c,
+                  bool           const to_start_point,
+                  unsigned int * const n_points,
+                  unsigned int   const tangent_surround) {
+/*----------------------------------------------------------------------------
+  Find the change in y and change in x for `tangent_surround' (a global)
+  points along CURVE.  Increment N_POINTS by the number of points we
+  actually look at.
+-----------------------------------------------------------------------------*/
+    unsigned int p;
+    int factor = to_start_point ? 1 : -1;
+    unsigned tangent_index = to_start_point ? 0 : c->length - 1;
+    float_coord tangent_point = CURVE_POINT (c, tangent_index);
+    vector_type tangent = { 0.0, 0.0 };
+    unsigned int surround;
+
+    if ((surround = CURVE_LENGTH(c) / 2) > tangent_surround)
+        surround = tangent_surround;
+    
+    for (p = 1; p <= surround; ++p) {
+        int const this_index = p * factor + tangent_index;
+        float_coord this_point;
+        
+        if (this_index < 0 || this_index >= (int) c->length)
+            break;
+
+        this_point = CURVE_POINT(c, p * factor + tangent_index);
+
+        /* Perhaps we should weight the tangent from `this_point' by some
+           factor dependent on the distance from the tangent point.
+        */
+        tangent = Vadd (tangent,
+                        Vmult_scalar(Psubtract(this_point, tangent_point),
+                                     (float) factor));
+        ++*n_points;
+    }
+
+    return tangent;
+}
+
+
+
+static void
+find_tangent(curve_type   const curve,
+             bool         const to_start_point,
+             bool         const cross_curve,
+             unsigned int const tangent_surround_arg) {
+/*----------------------------------------------------------------------------
+  Find an approximation to the tangent to an endpoint of CURVE (to the
+  first point if TO_START_POINT is true, else the last).  If
+  CROSS_CURVE is true, consider points on the adjacent curve to CURVE.
+  
+  It is important to compute an accurate approximation, because the
+  control points that we eventually decide upon to fit the curve will
+  be placed on the half-lines defined by the tangents and
+  endpoints...and we never recompute the tangent after this.
+-----------------------------------------------------------------------------*/
+    vector_type ** curve_tangent;
+    vector_type tangent;
+    unsigned n_points;
+    
+    LOG1("  tangent to %s: ", (to_start_point == true) ? "start" : "end");
+
+    n_points = 0;  /* initial value */
+
+    curve_tangent = to_start_point ?
+        &(CURVE_START_TANGENT(curve)) : &(CURVE_END_TANGENT(curve));
+
+    if (*curve_tangent == NULL) {
+        unsigned int tangent_surround;
+
+        tangent_surround = tangent_surround_arg;  /* initial value */
+        MALLOCVAR_NOFAIL(*curve_tangent);
+        do {
+            tangent = find_half_tangent(curve, to_start_point, &n_points,
+                                        tangent_surround);
+
+            if (cross_curve || CURVE_CYCLIC(curve)) {
+                curve_type const adjacent_curve = to_start_point ?
+                    PREVIOUS_CURVE(curve) : NEXT_CURVE(curve);
+                vector_type const tangent2 = !to_start_point ?
+                    find_half_tangent(adjacent_curve, true, &n_points,
+                                      tangent_surround) :
+                    find_half_tangent(adjacent_curve, true, &n_points,
+                                      tangent_surround);
+                
+                LOG3("(adjacent curve half tangent (%.3f,%.3f,%.3f)) ",
+                     tangent2.dx, tangent2.dy, tangent2.dz);
+                tangent = Vadd (tangent, tangent2);
+            }
+            --tangent_surround;
+        } while (tangent.dx == 0.0 && tangent.dy == 0.0);
+
+        assert(n_points > 0);
+        **curve_tangent = Vmult_scalar (tangent, (float)(1.0 / n_points));
+        if (CURVE_CYCLIC(curve) && CURVE_START_TANGENT(curve))
+            *CURVE_START_TANGENT(curve) = **curve_tangent;
+        if (CURVE_CYCLIC(curve) && CURVE_END_TANGENT(curve))
+            *CURVE_END_TANGENT(curve) = **curve_tangent;
+    } else
+        LOG("(already computed) ");
+    
+    LOG3("(%.3f,%.3f,%.3f).\n", (*curve_tangent)->dx,
+         (*curve_tangent)->dy, (*curve_tangent)->dz);
+}
+
+
+
+static float
+find_error(curve_type          const curve,
+           spline_type         const spline,
+           unsigned int *      const worst_point,
+           at_exception_type * const exception) {
+/*----------------------------------------------------------------------------
+  When this routine is called, we have computed a spline representation
+  for the digitized curve.  The question is, how good is it?  If the
+  fit is very good indeed, we might have an error of zero on each
+  point, and then WORST_POINT becomes irrelevant.  But normally, we
+  return the error at the worst point, and the index of that point in
+  WORST_POINT.  The error computation itself is the Euclidean distance
+  from the original curve CURVE to the fitted spline SPLINE.
+-----------------------------------------------------------------------------*/
+    unsigned int this_point;
+    float total_error;
+    float worst_error;
+
+    total_error = 0.0;  /* initial value */
+    worst_error = FLT_MIN; /* initial value */
+
+    *worst_point = CURVE_LENGTH(curve) + 1;   /* A sentinel value.  */
+        
+    for (this_point = 0; this_point < CURVE_LENGTH(curve); ++this_point) {
+        float_coord const curve_point = CURVE_POINT(curve, this_point);
+        float const t = CURVE_T(curve, this_point);
+        float_coord const spline_point = evaluate_spline(spline, t);
+        float const this_error = distance(curve_point, spline_point);
+        if (this_error >= worst_error) {
+            *worst_point = this_point;
+            worst_error = this_error;
+        }
+        total_error += this_error;
+    }
+
+    if (*worst_point == CURVE_LENGTH(curve) + 1) {
+        /* Didn't have any ``worst point''; the error should be zero.  */
+        if (epsilon_equal(total_error, 0.0))
+            LOG ("  Every point fit perfectly.\n");
+        else {
+            LOG("No worst point found; something is wrong");
+            at_exception_warning(exception,
+                                 "No worst point found; something is wrong");
+        }
+    } else {
+        if (epsilon_equal(total_error, 0.0))
+            LOG ("  Every point fit perfectly.\n");
+        else {
+            LOG5("  Worst error (at (%.3f,%.3f,%.3f), point #%u) was %.3f.\n",
+                 CURVE_POINT(curve, *worst_point).x,
+                 CURVE_POINT(curve, *worst_point).y,
+                 CURVE_POINT(curve, *worst_point).z,
+                 *worst_point, worst_error);
+            LOG1("  Total error was %.3f.\n", total_error);
+            LOG2("  Average error (over %u points) was %.3f.\n",
+                 CURVE_LENGTH(curve), total_error / CURVE_LENGTH(curve));
+        }
+    }
+    return worst_error;
+}
+
+
+
+static void
+set_initial_parameter_values(curve_type const curve) {
+/*----------------------------------------------------------------------------
+   Find reasonable values for t for each point on CURVE.  The method is
+   called chord-length parameterization, which is described in Plass &
+   Stone.  The basic idea is just to use the distance from one point to
+   the next as the t value, normalized to produce values that increase
+   from zero for the first point to one for the last point.
+-----------------------------------------------------------------------------*/
+    unsigned int p;
+
+    LOG("\nAssigning initial t values:\n  ");
+
+    CURVE_T(curve, 0) = 0.0;
+
+    for (p = 1; p < CURVE_LENGTH (curve); ++p) {
+        float_coord const point = CURVE_POINT(curve, p);
+        float_coord const previous_p = CURVE_POINT(curve, p - 1);
+        float const d = distance (point, previous_p);
+        CURVE_T (curve, p) = CURVE_T (curve, p - 1) + d;
+    }
+
+    assert(LAST_CURVE_T (curve) != 0.0);
+
+    for (p = 1; p < CURVE_LENGTH(curve); ++p)
+        CURVE_T(curve, p) = CURVE_T(curve, p) / LAST_CURVE_T(curve);
+
+    log_entire_curve(curve);
+}
+
+
+
 static spline_list_type *
 fit_with_least_squares(curve_type                const curve,
                        const fitting_opts_type * const fitting_opts,
@@ -1377,547 +1930,3 @@ fit_outlines_to_splines(pixel_outline_list_type  const pixelOutlineList,
 
 
 
-
-static void
-find_vectors(unsigned int       const test_index,
-             pixel_outline_type const outline,
-             vector_type *      const in,
-             vector_type *      const out,
-             unsigned int       const corner_surround) {
-/*----------------------------------------------------------------------------
-  Return the difference vectors coming in and going out of the outline
-  OUTLINE at the point whose index is TEST_INDEX.  In Phoenix,
-  Schneider looks at a single point on either side of the point we're
-  considering.  That works for him because his points are not touching.
-  But our points *are* touching, and so we have to look at
-  `corner_surround' points on either side, to get a better picture of
-  the outline's shape.
------------------------------------------------------------------------------*/
-    int i;
-    unsigned n_done;
-    pm_pixelcoord const candidate = O_COORDINATE(outline, test_index);
-
-    in->dx  = in->dy  = in->dz  = 0.0;
-    out->dx = out->dy = out->dz = 0.0;
-    
-    /* Add up the differences from p of the `corner_surround' points
-       before p.
-    */
-    for (i = O_PREV(outline, test_index), n_done = 0;
-         n_done < corner_surround;
-         i = O_PREV(outline, i), ++n_done)
-        *in = Vadd(*in, IPsubtract(O_COORDINATE(outline, i), candidate));
-    
-    /* And the points after p. */
-    for (i = O_NEXT (outline, test_index), n_done = 0;
-         n_done < corner_surround;
-         i = O_NEXT(outline, i), ++n_done)
-        *out = Vadd(*out, IPsubtract(O_COORDINATE(outline, i), candidate));
-}
-
-
-
-/* Remove adjacent points from the index list LIST.  We do this by first
-   sorting the list and then running through it.  Since these lists are
-   quite short, a straight selection sort (e.g., p.139 of the Art of
-   Computer Programming, vol.3) is good enough.  LAST_INDEX is the index
-   of the last pixel on the outline, i.e., the next one is the first
-   pixel. We need this for checking the adjacency of the last corner.
-
-   We need to do this because the adjacent corners turn into
-   two-pixel-long curves, which can only be fit by straight lines.  */
-
-static void
-remove_adjacent_corners (index_list_type *list, unsigned last_index,
-             bool remove_adj_corners,
-             at_exception_type * exception)
-             
-{
-  unsigned j;
-  unsigned last;
-  index_list_type new_list = new_index_list ();
-
-  for (j = INDEX_LIST_LENGTH (*list) - 1; j > 0; j--)
-    {
-      unsigned search;
-      unsigned temp;
-      /* Find maximal element below `j'.  */
-      unsigned max_index = j;
-
-      for (search = 0; search < j; search++)
-        if (GET_INDEX (*list, search) > GET_INDEX (*list, max_index))
-          max_index = search;
-
-      if (max_index != j)
-        {
-          temp = GET_INDEX (*list, j);
-          GET_INDEX (*list, j) = GET_INDEX (*list, max_index);
-          GET_INDEX (*list, max_index) = temp;
-      
-      /* xx -- really have to sort?  */
-      LOG ("needed exchange");
-      at_exception_warning(exception, "needed exchange");
-        }
-    }
-
-  /* The list is sorted.  Now look for adjacent entries.  Each time
-     through the loop we insert the current entry and, if appropriate,
-     the next entry.  */
-  for (j = 0; j < INDEX_LIST_LENGTH (*list) - 1; j++)
-    {
-      unsigned current = GET_INDEX (*list, j);
-      unsigned next = GET_INDEX (*list, j + 1);
-
-      /* We should never have inserted the same element twice.  */
-      /* assert (current != next); */
-
-      if ((remove_adj_corners) && ((next == current + 1) || (next == current)))
-        j++;
-
-      append_index (&new_list, current);
-    }
-
-  /* Don't append the last element if it is 1) adjacent to the previous
-     one; or 2) adjacent to the very first one.  */
-  last = GET_LAST_INDEX (*list);
-  if (INDEX_LIST_LENGTH (new_list) == 0
-      || !(last == GET_LAST_INDEX (new_list) + 1
-           || (last == last_index && GET_INDEX (*list, 0) == 0)))
-    append_index (&new_list, last);
-
-  free_index_list (list);
-  *list = new_list;
-}
-
-/* A ``knee'' is a point which forms a ``right angle'' with its
-   predecessor and successor.  See the documentation (the `Removing
-   knees' section) for an example and more details.
-
-   The argument CLOCKWISE tells us which direction we're moving.  (We
-   can't figure that information out from just the single segment with
-   which we are given to work.)
-
-   We should never find two consecutive knees.
-
-   Since the first and last points are corners (unless the curve is
-   cyclic), it doesn't make sense to remove those.  */
-
-/* This evaluates to true if the vector V is zero in one direction and
-   nonzero in the other.  */
-#define ONLY_ONE_ZERO(v)                                                \
-  (((v).dx == 0.0 && (v).dy != 0.0) || ((v).dy == 0.0 && (v).dx != 0.0))
-
-/* There are four possible cases for knees, one for each of the four
-   corners of a rectangle; and then the cases differ depending on which
-   direction we are going around the curve.  The tests are listed here
-   in the order of upper left, upper right, lower right, lower left.
-   Perhaps there is some simple pattern to the
-   clockwise/counterclockwise differences, but I don't see one.  */
-#define CLOCKWISE_KNEE(prev_delta, next_delta)                                                  \
-  ((prev_delta.dx == -1.0 && next_delta.dy == 1.0)                                              \
-   || (prev_delta.dy == 1.0 && next_delta.dx == 1.0)                                    \
-   || (prev_delta.dx == 1.0 && next_delta.dy == -1.0)                                   \
-   || (prev_delta.dy == -1.0 && next_delta.dx == -1.0))
-
-#define COUNTERCLOCKWISE_KNEE(prev_delta, next_delta)                                   \
-  ((prev_delta.dy == 1.0 && next_delta.dx == -1.0)                                              \
-   || (prev_delta.dx == 1.0 && next_delta.dy == 1.0)                                    \
-   || (prev_delta.dy == -1.0 && next_delta.dx == 1.0)                                   \
-   || (prev_delta.dx == -1.0 && next_delta.dy == -1.0))
-
-
-
-static void
-remove_knee_points(curve_type const curve,
-                   bool       const clockwise) {
-
-      unsigned const offset = (CURVE_CYCLIC(curve) == true) ? 0 : 1;
-      curve_type const trimmed_curve = copy_most_of_curve(curve);
-
-      pm_pixelcoord previous;
-      unsigned i;
-
-      if (!CURVE_CYCLIC(curve))
-          append_pixel(trimmed_curve,
-                       real_to_int_coord(CURVE_POINT(curve, 0)));
-
-      previous = real_to_int_coord(CURVE_POINT(curve,
-                                               CURVE_PREV(curve, offset)));
-
-      for (i = offset; i < CURVE_LENGTH (curve) - offset; ++i) {
-          pm_pixelcoord const current =
-              real_to_int_coord(CURVE_POINT(curve, i));
-          pm_pixelcoord const next =
-              real_to_int_coord(CURVE_POINT(curve, CURVE_NEXT(curve, i)));
-          vector_type const prev_delta = IPsubtract(previous, current);
-          vector_type const next_delta = IPsubtract(next, current);
-
-          if (ONLY_ONE_ZERO(prev_delta) && ONLY_ONE_ZERO(next_delta)
-              && ((clockwise && CLOCKWISE_KNEE(prev_delta, next_delta))
-                  || (!clockwise
-                      && COUNTERCLOCKWISE_KNEE(prev_delta, next_delta))))
-              LOG2(" (%d,%d)", current.col, current.row);
-          else {
-              previous = current;
-              append_pixel(trimmed_curve, current);
-          }
-      }
-
-      if (!CURVE_CYCLIC(curve))
-          append_pixel(trimmed_curve,
-                       real_to_int_coord(LAST_CURVE_POINT(curve)));
-
-      if (CURVE_LENGTH(trimmed_curve) == CURVE_LENGTH(curve))
-          LOG(" (none)");
-
-      LOG(".\n");
-
-      free_curve(curve);
-      *curve = *trimmed_curve;
-      free(trimmed_curve);      /* free_curve? --- Masatake */
-}
-
-
-
-/* Smooth the curve by adding in neighboring points.  Do this
-   `filter_iterations' times.  But don't change the corners.  */
-
-static void
-filter (curve_type curve, fitting_opts_type *fitting_opts)
-{
-  unsigned iteration, this_point;
-  unsigned offset = (CURVE_CYCLIC (curve) == true) ? 0 : 1;
-  float_coord prev_new_point;
-
-  /* We must have at least three points---the previous one, the current
-     one, and the next one.  But if we don't have at least five, we will
-     probably collapse the curve down onto a single point, which means
-     we won't be able to fit it with a spline.  */
-  if (CURVE_LENGTH (curve) < 5)
-    {
-      LOG1 ("Length is %u, not enough to filter.\n", CURVE_LENGTH (curve));
-      return;
-    }
-
-  prev_new_point.x = FLT_MAX;
-  prev_new_point.y = FLT_MAX;
-  prev_new_point.z = FLT_MAX;
-
-  for (iteration = 0; iteration < fitting_opts->filter_iterations;
-   iteration++)
-    {
-      curve_type newcurve = copy_most_of_curve (curve);
-      bool collapsed = false;
-
-      /* Keep the first point on the curve.  */
-      if (offset)
-        append_point (newcurve, CURVE_POINT (curve, 0));
-
-      for (this_point = offset; this_point < CURVE_LENGTH (curve) - offset;
-           this_point++)
-        {
-          vector_type in, out, sum;
-          float_coord new_point;
-
-          /* Calculate the vectors in and out, computed by looking at n points
-             on either side of this_point. Experimental it was found that 2 is
-             optimal. */
-
-          signed int prev, prevprev; /* have to be signed */
-          unsigned int next, nextnext;
-          float_coord candidate = CURVE_POINT (curve, this_point);
-
-          prev = CURVE_PREV (curve, this_point);
-          prevprev = CURVE_PREV (curve, prev);
-          next = CURVE_NEXT (curve, this_point);
-          nextnext = CURVE_NEXT (curve, next);
-
-          /* Add up the differences from p of the `surround' points
-             before p.  */
-          in.dx = in.dy = in.dz = 0.0;
-
-          in = Vadd (in, Psubtract (CURVE_POINT (curve, prev), candidate));
-          if (prevprev >= 0)
-              in = Vadd (in, Psubtract (CURVE_POINT (curve, prevprev), candidate));
-
-          /* And the points after p.  Don't use more points after p than we
-             ended up with before it.  */
-          out.dx = out.dy = out.dz = 0.0;
-
-          out = Vadd (out, Psubtract (CURVE_POINT (curve, next), candidate));
-          if (nextnext < CURVE_LENGTH (curve))
-              out = Vadd (out, Psubtract (CURVE_POINT (curve, nextnext), candidate));
-
-          /* Start with the old point.  */
-          new_point = candidate;
-          sum = Vadd (in, out);
-          /* We added 2*n+2 points, so we have to divide the sum by 2*n+2 */
-          new_point.x += sum.dx / 6;
-          new_point.y += sum.dy / 6;
-          new_point.z += sum.dz / 6;
-          if (fabs (prev_new_point.x - new_point.x) < 0.3
-              && fabs (prev_new_point.y - new_point.y) < 0.3
-              && fabs (prev_new_point.z - new_point.z) < 0.3)
-            {
-              collapsed = true;
-              break;
-            }
-
-
-          /* Put the newly computed point into a separate curve, so it
-             doesn't affect future computation (on this iteration).  */
-          append_point (newcurve, prev_new_point = new_point);
-        }
-
-      if (collapsed)
-    free_curve (newcurve);
-      else
-    {
-          /* Just as with the first point, we have to keep the last point.  */
-          if (offset)
-        append_point (newcurve, LAST_CURVE_POINT (curve));
-      
-          /* Set the original curve to the newly filtered one, and go again.  */
-          free_curve (curve);
-          *curve = *newcurve;
-    }
-      free (newcurve);
-    }
-
-  log_curve (curve, false);
-}
-
-
-
-/* Find reasonable values for t for each point on CURVE.  The method is
-   called chord-length parameterization, which is described in Plass &
-   Stone.  The basic idea is just to use the distance from one point to
-   the next as the t value, normalized to produce values that increase
-   from zero for the first point to one for the last point.  */
-
-static void
-set_initial_parameter_values (curve_type curve)
-{
-  unsigned p;
-
-  LOG ("\nAssigning initial t values:\n  ");
-
-  CURVE_T (curve, 0) = 0.0;
-
-  for (p = 1; p < CURVE_LENGTH (curve); p++)
-    {
-      float_coord point = CURVE_POINT (curve, p),
-                           previous_p = CURVE_POINT (curve, p - 1);
-      float d = distance (point, previous_p);
-      CURVE_T (curve, p) = CURVE_T (curve, p - 1) + d;
-    }
-
-  assert (LAST_CURVE_T (curve) != 0.0);
-
-  for (p = 1; p < CURVE_LENGTH (curve); p++)
-    CURVE_T (curve, p) = CURVE_T (curve, p) / LAST_CURVE_T (curve);
-
-  log_entire_curve (curve);
-}
-
-/* Find an approximation to the tangent to an endpoint of CURVE (to the
-   first point if TO_START_POINT is true, else the last).  If
-   CROSS_CURVE is true, consider points on the adjacent curve to CURVE.
-
-   It is important to compute an accurate approximation, because the
-   control points that we eventually decide upon to fit the curve will
-   be placed on the half-lines defined by the tangents and
-   endpoints...and we never recompute the tangent after this.  */
-
-static void
-find_tangent (curve_type curve, bool to_start_point, bool cross_curve,
-  unsigned tangent_surround)
-{
-  vector_type tangent;
-  vector_type **curve_tangent = (to_start_point == true) ? &(CURVE_START_TANGENT (curve))
-                                               : &(CURVE_END_TANGENT (curve));
-  unsigned n_points = 0;
-
-  LOG1 ("  tangent to %s: ", (to_start_point == true) ? "start" : "end");
-
-  if (*curve_tangent == NULL)
-    {
-        MALLOCVAR_NOFAIL(*curve_tangent);
-      do
-        {
-          tangent = find_half_tangent (curve, to_start_point, &n_points,
-            tangent_surround);
-
-          if ((cross_curve == true) || (CURVE_CYCLIC (curve) == true))
-            {
-              curve_type adjacent_curve
-                = (to_start_point == true) ? PREVIOUS_CURVE (curve) : NEXT_CURVE (curve);
-              vector_type tangent2
-                = (to_start_point == false) ? find_half_tangent (adjacent_curve, true, &n_points,
-                tangent_surround) : find_half_tangent (adjacent_curve, true, &n_points,
-                tangent_surround);
-
-              LOG3 ("(adjacent curve half tangent (%.3f,%.3f,%.3f)) ",
-                tangent2.dx, tangent2.dy, tangent2.dz);
-              tangent = Vadd (tangent, tangent2);
-            }
-          tangent_surround--;
-
-        }
-      while (tangent.dx == 0.0 && tangent.dy == 0.0);
-
-      assert (n_points > 0);
-      **curve_tangent = Vmult_scalar (tangent, (float)(1.0 / n_points));
-      if ((CURVE_CYCLIC (curve) == true) && CURVE_START_TANGENT (curve))
-          *CURVE_START_TANGENT (curve) = **curve_tangent;
-      if  ((CURVE_CYCLIC (curve) == true) && CURVE_END_TANGENT (curve))
-          *CURVE_END_TANGENT (curve) = **curve_tangent;
-    }
-  else
-    LOG ("(already computed) ");
-
-  LOG3 ("(%.3f,%.3f,%.3f).\n", (*curve_tangent)->dx, (*curve_tangent)->dy, (*curve_tangent)->dz);
-}
-
-/* Find the change in y and change in x for `tangent_surround' (a global)
-   points along CURVE.  Increment N_POINTS by the number of points we
-   actually look at.  */
-
-static vector_type
-find_half_tangent (curve_type c, bool to_start_point, unsigned *n_points,
-  unsigned tangent_surround)
-{
-  unsigned p;
-  int factor = to_start_point ? 1 : -1;
-  unsigned tangent_index = to_start_point ? 0 : c->length - 1;
-  float_coord tangent_point = CURVE_POINT (c, tangent_index);
-  vector_type tangent = { 0.0, 0.0 };
-  unsigned int surround;
-
-  if ((surround = CURVE_LENGTH (c) / 2) > tangent_surround)
-    surround = tangent_surround;
-
-  for (p = 1; p <= surround; p++)
-    {
-      int this_index = p * factor + tangent_index;
-      float_coord this_point;
-
-      if (this_index < 0 || this_index >= (int) c->length)
-        break;
-
-      this_point = CURVE_POINT (c, p * factor + tangent_index);
-
-      /* Perhaps we should weight the tangent from `this_point' by some
-         factor dependent on the distance from the tangent point.  */
-      tangent = Vadd (tangent,
-                      Vmult_scalar (Psubtract (this_point, tangent_point),
-                                    (float) factor));
-      (*n_points)++;
-    }
-
-  return tangent;
-}
-
-/* When this routine is called, we have computed a spline representation
-   for the digitized curve.  The question is, how good is it?  If the
-   fit is very good indeed, we might have an error of zero on each
-   point, and then WORST_POINT becomes irrelevant.  But normally, we
-   return the error at the worst point, and the index of that point in
-   WORST_POINT.  The error computation itself is the Euclidean distance
-   from the original curve CURVE to the fitted spline SPLINE.  */
-
-static float
-find_error (curve_type curve, spline_type spline, unsigned *worst_point,
-        at_exception_type * exception)
-{
-  unsigned this_point;
-  float total_error = 0.0;
-  float worst_error = FLT_MIN;
-
-  *worst_point = CURVE_LENGTH (curve) + 1;   /* A sentinel value.  */
-
-  for (this_point = 0; this_point < CURVE_LENGTH (curve); this_point++)
-    {
-      float_coord curve_point = CURVE_POINT (curve, this_point);
-      float t = CURVE_T (curve, this_point);
-      float_coord spline_point = evaluate_spline (spline, t);
-      float this_error = distance (curve_point, spline_point);
-      if (this_error >= worst_error)
-        {
-         *worst_point = this_point;
-          worst_error = this_error;
-        }
-      total_error += this_error;
-    }
-
-  if (*worst_point == CURVE_LENGTH (curve) + 1)
-    { /* Didn't have any ``worst point''; the error should be zero.  */
-      if (epsilon_equal (total_error, 0.0))
-        LOG ("  Every point fit perfectly.\n");
-      else
-    {
-      LOG("No worst point found; something is wrong");
-      at_exception_warning(exception, "No worst point found; something is wrong");
-    }
-    }
-  else
-    {
-      if (epsilon_equal (total_error, 0.0))
-        LOG ("  Every point fit perfectly.\n");
-      else
-        {
-          LOG5 ("  Worst error (at (%.3f,%.3f,%.3f), point #%u) was %.3f.\n",
-              CURVE_POINT (curve, *worst_point).x,
-              CURVE_POINT (curve, *worst_point).y,
-              CURVE_POINT (curve, *worst_point).z, *worst_point, worst_error);
-          LOG1 ("  Total error was %.3f.\n", total_error);
-          LOG2 ("  Average error (over %u points) was %.3f.\n",
-              CURVE_LENGTH (curve), total_error / CURVE_LENGTH (curve));
-        }
-    }
-
-  return worst_error;
-}
-
-
-/* Lists of array indices (well, that is what we use it for).  */
-
-static index_list_type
-new_index_list (void)
-{
-  index_list_type index_list;
-
-  index_list.data = NULL;
-  INDEX_LIST_LENGTH (index_list) = 0;
-
-  return index_list;
-}
-
-static void
-free_index_list (index_list_type *index_list)
-{
-  if (INDEX_LIST_LENGTH (*index_list) > 0)
-    {
-      free (index_list->data);
-      index_list->data = NULL;
-      INDEX_LIST_LENGTH (*index_list) = 0;
-    }
-}
-
-static void
-append_index (index_list_type *list, unsigned new_index)
-{
-  INDEX_LIST_LENGTH (*list)++;
-  REALLOCARRAY_NOFAIL(list->data, INDEX_LIST_LENGTH(*list));
-  list->data[INDEX_LIST_LENGTH (*list) - 1] = new_index;
-}
-
-
-/* Return the Euclidean distance between P1 and P2.  */
-
-static float
-distance (float_coord p1, float_coord p2)
-{
-  float x = p1.x - p2.x, y = p1.y - p2.y, z = p1.z - p2.z;
-  return (float) sqrt (SQR(x) + SQR(y) + SQR(z));
-}
diff --git a/converter/other/pgmtopbm.c b/converter/other/pgmtopbm.c
index 98bdc332..36b39017 100644
--- a/converter/other/pgmtopbm.c
+++ b/converter/other/pgmtopbm.c
@@ -11,10 +11,11 @@
 */
 
 #include <assert.h>
+
+#include "shhopt.h"
 #include "pgm.h"
 #include "dithers.h"
 #include "mallocvar.h"
-#include "shhopt.h"
 
 enum halftone {QT_FS, QT_THRESH, QT_DITHER8, QT_CLUSTER, QT_HILBERT};
 
@@ -445,7 +446,7 @@ createFsConverter(unsigned int const cols,
     /* Initialize Floyd-Steinberg error vectors. */
     MALLOCARRAY_NOFAIL(stateP->thiserr, cols + 2);
     MALLOCARRAY_NOFAIL(stateP->nexterr, cols + 2);
-    srand((int)(time(NULL) ^ getpid()));
+    srand(pm_randseed());
 
     {
         /* (random errors in [-fs_scale/8 .. fs_scale/8]) */
diff --git a/converter/other/pgmtoppm.c b/converter/other/pgmtoppm.c
index 7693fe0a..cface024 100644
--- a/converter/other/pgmtoppm.c
+++ b/converter/other/pgmtoppm.c
@@ -11,146 +11,229 @@
 */
 
 #include <string.h>
+
+#include "mallocvar.h"
+#include "shhopt.h"
 #include "ppm.h"
 
-int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    gray* grayrow;
-    register gray* gP;
-    pixel p;
-    pixel* pixelrow;
-    register pixel* pP;
-    pixel** mappixels;
-    int argn, rows, cols, format, maprows, mapcols, mapmaxcolor, row;
-    register int col;
-    gray maxval;
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char * inputFilename;  /* '-' if stdin */
+    const char * map;
+    const char * colorBlack;
+    const char * colorWhite;
+};
+
+
+
+static void
+parseCommandLine(int argc, char ** argv,
+                 struct cmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   parse program command line described in Unix standard form by argc
+   and argv.  Return the information in the options as *cmdlineP.  
+
+   If command line is internally inconsistent (invalid options, etc.),
+   issue error message to stderr and abort program.
+
+   Note that the strings we return are stored in the storage that
+   was passed to us as the argv array.  We also trash *argv.
+-----------------------------------------------------------------------------*/
+    optEntry *option_def;
+        /* Instructions to optParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    unsigned int mapSpec;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "map",            OPT_STRING,    &cmdlineP->map,
+            &mapSpec,            0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (!mapSpec)
+        cmdlineP->map = NULL;
+
+    if (mapSpec) {
+        /* No color argument; only argument is file name */
+        if (argc-1 < 1)
+            cmdlineP->inputFilename = "-";
+        else {
+            cmdlineP->inputFilename = argv[1];
+            if (argc-1 > 1)
+                pm_error("With -map option, there is at most one argument: "
+                         "the file name.  You specified %u", argc-1);
+        }
+    } else {
+        /* Arguments are color or color range and file name */
+        if (argc-1 < 1) {
+            cmdlineP->colorBlack = "black";
+            cmdlineP->colorWhite = "white";
+        } else {
+            char * buffer = strdup(argv[1]);
+            char * hyphenPos = strchr(buffer, '-');
+            if (hyphenPos) {
+                *hyphenPos = '\0';
+                cmdlineP->colorBlack = buffer;
+                cmdlineP->colorWhite = hyphenPos+1;
+            } else {
+                cmdlineP->colorBlack = "black";
+                cmdlineP->colorWhite = buffer;
+            }
+        }
+        if (argc-1 < 2)
+            cmdlineP->inputFilename = "-";
+        else
+            cmdlineP->inputFilename = argv[2];
+        
+        if (argc-1 > 2)
+            pm_error("Program takes at most 2 arguments:  "
+                     "color name/range and input file name.  "
+                     "You specified %u", argc-1);
+    }
+}
+
+
+
+static void
+convertWithMap(FILE * const ifP,
+               unsigned int const cols,
+               unsigned int const rows,
+               gray         const maxval,
+               int          const format,
+               const char * const mapFileName,
+               FILE *       const ofP,
+               gray *       const grayrow,
+               pixel *      const pixelrow) {
+
+    unsigned int row;
+    FILE * mapFileP;
+    int mapcols, maprows;
     pixval mapmaxval;
-    char* color0;
-    char* color1;
+    pixel ** mappixels;
+    unsigned int mapmaxcolor;
+    
+    mapFileP = pm_openr(mapFileName);
+    mappixels = ppm_readppm(mapFileP, &mapcols, &maprows, &mapmaxval);
+    pm_close(mapFileP);
+    mapmaxcolor = maprows * mapcols - 1;
+
+    ppm_writeppminit(ofP, cols, rows, mapmaxval, 0);
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+            
+        pgm_readpgmrow(ifP, grayrow, cols, maxval, format);
+
+        for (col = 0; col < cols; ++col) {
+            unsigned int c;
+            if (maxval == mapmaxcolor)
+                c = grayrow[col];
+            else
+                c = grayrow[col] * mapmaxcolor / maxval;
+            pixelrow[col] = mappixels[c / mapcols][c % mapcols];
+        }
+        ppm_writeppmrow(ofP, pixelrow, cols, mapmaxval, 0);
+    }
+    ppm_freearray(mappixels, maprows);
+}
+
+
+
+static void
+convertLinear(FILE * const ifP,
+              unsigned int const cols,
+              unsigned int const rows,
+              gray         const maxval,
+              int          const format,
+              const char * const colorNameBlack,
+              const char * const colorNameWhite,
+              FILE *       const ofP,
+              gray *       const grayrow,
+              pixel *      const pixelrow) {
+
+    pixel colorBlack, colorWhite;
     pixval red0, grn0, blu0, red1, grn1, blu1;
-    const char* const usage = "<colorspec> [pgmfile]\n                 <colorspec1>,<colorspec2> [pgmfile]\n                 -map mapfile [pgmfile]";
-
-
-    ppm_init( &argc, argv );
-
-    argn = 1;
-    mappixels = (pixel**) 0;
-
-    if ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
-	{
-	if ( pm_keymatch( argv[argn], "-map", 2 ) )
-	    {
-	    ++argn;
-	    if ( argn == argc )
-		pm_usage( usage );
-	    ifp = pm_openr( argv[argn] );
-	    mappixels = ppm_readppm( ifp, &mapcols, &maprows, &mapmaxval );
-	    pm_close( ifp );
-	    mapmaxcolor = maprows * mapcols - 1;
-	    }
-	else
-	    pm_usage( usage );
-	++argn;
-	}
-
-    if ( mappixels == (pixel**) 0 )
-	{
-	if ( argn == argc )
-	    pm_usage( usage );
-	color0 = argv[argn];
-	++argn;
-	}
-
-    if ( argn != argc )
-	{
-	ifp = pm_openr( argv[argn] );
-	++argn;
-	}
-    else
-	ifp = stdin;
+    unsigned int row;
+
+    ppm_writeppminit(ofP, cols, rows, maxval, 0);
+
+    colorBlack = ppm_parsecolor(colorNameBlack, maxval);
+    colorWhite = ppm_parsecolor(colorNameWhite, maxval);
+ 
+    red0 = PPM_GETR(colorBlack);
+    grn0 = PPM_GETG(colorBlack);
+    blu0 = PPM_GETB(colorBlack);
+    red1 = PPM_GETR(colorWhite);
+    grn1 = PPM_GETG(colorWhite);
+    blu1 = PPM_GETB(colorWhite);
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+
+        pgm_readpgmrow(ifP, grayrow, cols, maxval, format);
+
+        for (col = 0; col < cols; ++col) {
+            gray const input = grayrow[col];
+            PPM_ASSIGN(
+                pixelrow[col],
+                (red0 * (maxval - input) + red1 * input) / maxval,
+                (grn0 * (maxval - input) + grn1 * input) / maxval,
+                (blu0 * (maxval - input) + blu1 * input) / maxval);
+        }
+        ppm_writeppmrow(ofP, pixelrow, cols, maxval, 0);
+    }
+}
 
-    if ( argn != argc )
-	pm_usage( usage );
 
-    pgm_readpgminit( ifp, &cols, &rows, &maxval, &format );
-    grayrow = pgm_allocrow( cols );
-    if ( mappixels == (pixel**) 0 )
-	ppm_writeppminit( stdout, cols, rows, (pixval) maxval, 0 );
-    else
-	ppm_writeppminit( stdout, cols, rows, mapmaxval, 0 );
-    pixelrow = ppm_allocrow( cols );
-
-    if ( mappixels == (pixel**) 0 )
-	{
-	color1 = strchr( color0, '-' );
-	if ( color1 == 0 )
-	    {
-	    color1 = color0;
-	    red0 = 0;
-	    grn0 = 0;
-	    blu0 = 0;
-	    }
-	else
-	    {
-	    *color1 = '\0';
-	    ++color1;
-	    p = ppm_parsecolor( color0, (pixval) maxval );
-	    red0 = PPM_GETR( p );
-	    grn0 = PPM_GETG( p );
-	    blu0 = PPM_GETB( p );
-	    }
-	p = ppm_parsecolor( color1, (pixval) maxval );
-	red1 = PPM_GETR( p );
-	grn1 = PPM_GETG( p );
-	blu1 = PPM_GETB( p );
-	}
-
-    for ( row = 0; row < rows; ++row )
-	{
-	pgm_readpgmrow( ifp, grayrow, cols, maxval, format );
-
-	if ( mappixels == (pixel**) 0 )
-	    {
-	    for ( col = 0, gP = grayrow, pP = pixelrow;
-		  col < cols;
-		  ++col, ++gP, ++pP )
-		PPM_ASSIGN(
-		    *pP,
-		    ( red0 * ( maxval - *gP ) + red1 * *gP ) / maxval,
-		    ( grn0 * ( maxval - *gP ) + grn1 * *gP ) / maxval,
-		    ( blu0 * ( maxval - *gP ) + blu1 * *gP ) / maxval );
-
-	    }
-	else
-	    {
-	    register int c;
-
-	    for ( col = 0, gP = grayrow, pP = pixelrow;
-		  col < cols;
-		  ++col, ++gP, ++pP )
-		{
-		if ( maxval == mapmaxcolor )
-		    c = *gP;
-		else
-		    c = *gP * mapmaxcolor / maxval;
-		*pP = mappixels[c / mapcols][c % mapcols];
-		}
-	    }
-
-    if (!mappixels)
-        ppm_writeppmrow( stdout, pixelrow, cols, (pixval) maxval, 0 );
+
+int
+main(int    argc,
+     char * argv[]) {
+
+    FILE * ifP;
+    struct cmdlineInfo cmdline;
+    gray * grayrow;
+    pixel * pixelrow;
+    int rows, cols, format;
+    gray maxval;
+
+    ppm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFilename);
+
+    pgm_readpgminit(ifP, &cols, &rows, &maxval, &format);
+    grayrow = pgm_allocrow(cols);
+    pixelrow = ppm_allocrow(cols);
+
+    if (cmdline.map)
+        convertWithMap(ifP, cols, rows, maxval, format, cmdline.map,
+                       stdout, grayrow, pixelrow);
     else
-        ppm_writeppmrow( stdout, pixelrow, cols, mapmaxval, 0 );
-	}
+        convertLinear(ifP, cols, rows, maxval, format, 
+                      cmdline.colorBlack, cmdline.colorWhite, stdout,
+                      grayrow, pixelrow);
 
-    pm_close( ifp );
+    ppm_freerow(pixelrow);
+    pgm_freerow(grayrow);
+    pm_close(ifP);
 
     /* If the program failed, it previously aborted with nonzero completion
        code, via various function calls.
     */
     return 0;
-    }
+}
diff --git a/converter/other/pngtopnm.c b/converter/other/pngtopnm.c
index bb8afb8d..2b88bd1e 100644
--- a/converter/other/pngtopnm.c
+++ b/converter/other/pngtopnm.c
@@ -240,23 +240,12 @@ gamma_correct(png_uint_16 const v,
 
 
 
-#ifdef __STDC__
 static int iscolor (png_color c)
-#else
-static int iscolor (c)
-png_color c;
-#endif
 {
   return c.red != c.green || c.green != c.blue;
 }
 
-#ifdef __STDC__
 static void save_text (png_info *info_ptr, FILE *tfp)
-#else
-static void save_text (info_ptr, tfp)
-png_info *info_ptr;
-FILE *tfp;
-#endif
 {
   int i, j, k;
 
@@ -285,12 +274,7 @@ FILE *tfp;
   }
 }
 
-#ifdef __STDC__
 static void show_time (png_info *info_ptr)
-#else
-static void show_time (info_ptr)
-png_info *info_ptr;
-#endif
 {
     static const char * const month[] = {
         "", "January", "February", "March", "April", "May", "June",
@@ -305,13 +289,7 @@ png_info *info_ptr;
   }
 }
 
-#ifdef __STDC__
 static void pngtopnm_error_handler (png_structp png_ptr, png_const_charp msg)
-#else
-static void pngtopnm_error_handler (png_ptr, msg)
-png_structp png_ptr;
-png_const_charp msg;
-#endif
 {
   jmpbuf_wrapper  *jmpbuf_ptr;
 
diff --git a/converter/other/pnmtoddif.c b/converter/other/pnmtoddif.c
index 65152865..3a910a7b 100644
--- a/converter/other/pnmtoddif.c
+++ b/converter/other/pnmtoddif.c
@@ -166,11 +166,7 @@ wr_int(unsigned char ** buffer, int val)
     } else {
         sign = val < 0 ? 0xff : 0x00;   /* Sign bits */
         length = 4;
-#ifdef __STDC__
         mask  = 0xffu << 24;
-#else
-        mask  = 0xff << 24;
-#endif
         while ((val & mask) == sign) {  /* Find the smallest representation */
             length--;
             mask >>= 8;
diff --git a/converter/other/pnmtojpeg.c b/converter/other/pnmtojpeg.c
index 9a247633..5a4c5511 100644
--- a/converter/other/pnmtojpeg.c
+++ b/converter/other/pnmtojpeg.c
@@ -330,23 +330,6 @@ parseCommandLine(const int argc, char ** argv,
 }
 
 
-static void
-compute_rescaling_array(JSAMPLE ** const rescale_p, const pixval maxval,
-                        const struct jpeg_compress_struct cinfo);
-static void
-convert_scanlines(struct jpeg_compress_struct * const cinfo_p, FILE * const input_file,
-                  const pixval maxval, const int input_fmt,
-                  JSAMPLE xlate_table[]);
-
-static boolean read_quant_tables (j_compress_ptr cinfo, char * filename,
-                                  int scale_factor, boolean force_baseline);
-
-static boolean read_scan_script (j_compress_ptr cinfo, char * filename);
-
-static boolean set_quant_slots (j_compress_ptr cinfo, char *arg);
-
-static boolean set_sample_factors (j_compress_ptr cinfo, char *arg);
-
 
 static void
 report_compressor(const struct jpeg_compress_struct cinfo) {
@@ -423,6 +406,349 @@ setup_jpeg_density(struct jpeg_compress_struct * const cinfoP,
 
 
 
+/*----------------------------------------------------------------------------
+   The functions below here are essentially the file rdswitch.c from
+   the JPEG library.  They perform the functions specifed by the following
+   pnmtojpeg options:
+
+   -qtables file          Read quantization tables from text file
+   -scans file            Read scan script from text file
+   -qslots N[,N,...]      Set component quantization table selectors
+   -sample HxV[,HxV,...]  Set component sampling factors
+-----------------------------------------------------------------------------*/
+
+static int
+text_getc (FILE * file)
+/* Read next char, skipping over any comments (# to end of line) */
+/* A comment/newline sequence is returned as a newline */
+{
+    register int ch;
+  
+    ch = getc(file);
+    if (ch == '#') {
+        do {
+            ch = getc(file);
+        } while (ch != '\n' && ch != EOF);
+    }
+    return ch;
+}
+
+
+static boolean
+read_text_integer (FILE * file, long * result, int * termchar)
+/* Read an unsigned decimal integer from a file, store it in result */
+/* Reads one trailing character after the integer; returns it in termchar */
+{
+    register int ch;
+    register long val;
+  
+    /* Skip any leading whitespace, detect EOF */
+    do {
+        ch = text_getc(file);
+        if (ch == EOF) {
+            *termchar = ch;
+            return FALSE;
+        }
+    } while (isspace(ch));
+  
+    if (! isdigit(ch)) {
+        *termchar = ch;
+        return FALSE;
+    }
+
+    val = ch - '0';
+    while ((ch = text_getc(file)) != EOF) {
+        if (! isdigit(ch))
+            break;
+        val *= 10;
+        val += ch - '0';
+    }
+    *result = val;
+    *termchar = ch;
+    return TRUE;
+}
+
+
+static boolean
+read_scan_integer (FILE * file, long * result, int * termchar)
+/* Variant of read_text_integer that always looks for a non-space termchar;
+ * this simplifies parsing of punctuation in scan scripts.
+ */
+{
+    register int ch;
+
+    if (! read_text_integer(file, result, termchar))
+        return FALSE;
+    ch = *termchar;
+    while (ch != EOF && isspace(ch))
+        ch = text_getc(file);
+    if (isdigit(ch)) {		/* oops, put it back */
+        if (ungetc(ch, file) == EOF)
+            return FALSE;
+        ch = ' ';
+    } else {
+        /* Any separators other than ';' and ':' are ignored;
+         * this allows user to insert commas, etc, if desired.
+         */
+        if (ch != EOF && ch != ';' && ch != ':')
+            ch = ' ';
+    }
+    *termchar = ch;
+    return TRUE;
+}
+
+
+
+static boolean
+read_scan_script(j_compress_ptr const cinfo,
+                 const char *   const filename) {
+/*----------------------------------------------------------------------------
+  Read a scan script from the specified text file.
+  Each entry in the file defines one scan to be emitted.
+  Entries are separated by semicolons ';'.
+  An entry contains one to four component indexes,
+  optionally followed by a colon ':' and four progressive-JPEG parameters.
+  The component indexes denote which component(s) are to be transmitted
+  in the current scan.  The first component has index 0.
+  Sequential JPEG is used if the progressive-JPEG parameters are omitted.
+  The file is free format text: any whitespace may appear between numbers
+  and the ':' and ';' punctuation marks.  Also, other punctuation (such
+  as commas or dashes) can be placed between numbers if desired.
+  Comments preceded by '#' may be included in the file.
+  Note: we do very little validity checking here;
+  jcmaster.c will validate the script parameters.
+-----------------------------------------------------------------------------*/
+    FILE * fp;
+    unsigned int nscans;
+    unsigned int ncomps;
+    int termchar;
+    long val;
+#define MAX_SCANS  100      /* quite arbitrary limit */
+    jpeg_scan_info scans[MAX_SCANS];
+
+    fp = fopen(filename, "r");
+    if (fp == NULL) {
+        pm_message("Can't open scan definition file %s", filename);
+        return FALSE;
+    }
+    nscans = 0;
+
+    while (read_scan_integer(fp, &val, &termchar)) {
+        ++nscans;  /* We got another scan */
+        if (nscans > MAX_SCANS) {
+            pm_message("Too many scans defined in file %s", filename);
+            fclose(fp);
+            return FALSE;
+        }
+        scans[nscans-1].component_index[0] = (int) val;
+        ncomps = 1;
+        while (termchar == ' ') {
+            if (ncomps >= MAX_COMPS_IN_SCAN) {
+                pm_message("Too many components in one scan in file %s", 
+                           filename);
+                fclose(fp);
+                return FALSE;
+            }
+            if (! read_scan_integer(fp, &val, &termchar))
+                goto bogus;
+            scans[nscans-1].component_index[ncomps] = (int) val;
+            ++ncomps;
+        }
+        scans[nscans-1].comps_in_scan = ncomps;
+        if (termchar == ':') {
+            if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
+                goto bogus;
+            scans[nscans-1].Ss = (int) val;
+            if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
+                goto bogus;
+            scans[nscans-1].Se = (int) val;
+            if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
+                goto bogus;
+            scans[nscans-1].Ah = (int) val;
+            if (! read_scan_integer(fp, &val, &termchar))
+                goto bogus;
+            scans[nscans-1].Al = (int) val;
+        } else {
+            /* set non-progressive parameters */
+            scans[nscans-1].Ss = 0;
+            scans[nscans-1].Se = DCTSIZE2-1;
+            scans[nscans-1].Ah = 0;
+            scans[nscans-1].Al = 0;
+        }
+        if (termchar != ';' && termchar != EOF) {
+        bogus:
+            pm_message("Invalid scan entry format in file %s", filename);
+            fclose(fp);
+            return FALSE;
+        }
+    }
+
+    if (termchar != EOF) {
+        pm_message("Non-numeric data in file %s", filename);
+        fclose(fp);
+        return FALSE;
+    }
+
+    if (nscans > 0) {
+        /* Stash completed scan list in cinfo structure.  NOTE: in
+           this program, JPOOL_IMAGE is the right lifetime for this
+           data, but if you want to compress multiple images you'd
+           want JPOOL_PERMANENT.  
+        */
+        const unsigned int scan_info_size = nscans * sizeof(jpeg_scan_info);
+        jpeg_scan_info * const scan_info = 
+            (jpeg_scan_info *)
+            (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+                                        scan_info_size);
+        memcpy(scan_info, scans, scan_info_size);
+        cinfo->scan_info = scan_info;
+        cinfo->num_scans = nscans;
+    }
+
+    fclose(fp);
+    return TRUE;
+}
+
+
+
+static boolean
+read_quant_tables (j_compress_ptr cinfo, char * filename,
+                   int scale_factor, boolean force_baseline)
+/* Read a set of quantization tables from the specified file.
+ * The file is plain ASCII text: decimal numbers with whitespace between.
+ * Comments preceded by '#' may be included in the file.
+ * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values.
+ * The tables are implicitly numbered 0,1,etc.
+ * NOTE: does not affect the qslots mapping, which will default to selecting
+ * table 0 for luminance (or primary) components, 1 for chrominance components.
+ * You must use -qslots if you want a different component->table mapping.
+ */
+{
+    FILE * fp;
+    int tblno, i, termchar;
+    long val;
+    unsigned int table[DCTSIZE2];
+
+    if ((fp = fopen(filename, "rb")) == NULL) {
+        pm_message("Can't open table file %s", filename);
+        return FALSE;
+    }
+    tblno = 0;
+
+    while (read_text_integer(fp, &val, &termchar)) {
+        /* read 1st element of table */
+        if (tblno >= NUM_QUANT_TBLS) {
+            pm_message("Too many tables in file %s", filename);
+            fclose(fp);
+            return FALSE;
+        }
+        table[0] = (unsigned int) val;
+        for (i = 1; i < DCTSIZE2; i++) {
+            if (! read_text_integer(fp, &val, &termchar)) {
+                pm_message("Invalid table data in file %s", filename);
+                fclose(fp);
+                return FALSE;
+            }
+            table[i] = (unsigned int) val;
+        }
+        jpeg_add_quant_table(cinfo, tblno, table, scale_factor, 
+                             force_baseline);
+        tblno++;
+    }
+
+    if (termchar != EOF) {
+        pm_message("Non-numeric data in file %s", filename);
+        fclose(fp);
+        return FALSE;
+    }
+
+    fclose(fp);
+    return TRUE;
+}
+
+
+
+static boolean
+set_quant_slots (j_compress_ptr cinfo, char *arg)
+/* Process a quantization-table-selectors parameter string, of the form
+ *     N[,N,...]
+ * If there are more components than parameters, the last value is replicated.
+ */
+{
+    int val = 0;			/* default table # */
+    int ci;
+    char ch;
+
+    for (ci = 0; ci < MAX_COMPONENTS; ci++) {
+        if (*arg) {
+            ch = ',';			/* if not set by sscanf, will be ',' */
+            if (sscanf(arg, "%d%c", &val, &ch) < 1)
+                return FALSE;
+            if (ch != ',')		/* syntax check */
+                return FALSE;
+            if (val < 0 || val >= NUM_QUANT_TBLS) {
+                pm_message("Invalid quantization table number: %d.  "
+                           "JPEG quantization tables are numbered 0..%d",
+                           val, NUM_QUANT_TBLS - 1);
+                return FALSE;
+            }
+            cinfo->comp_info[ci].quant_tbl_no = val;
+            while (*arg && *arg++ != ',') 
+                /* advance to next segment of arg string */
+                ;
+        } else {
+            /* reached end of parameter, set remaining components to last tbl*/
+            cinfo->comp_info[ci].quant_tbl_no = val;
+        }
+    }
+    return TRUE;
+}
+
+
+static boolean
+set_sample_factors (j_compress_ptr cinfo, char *arg)
+/* Process a sample-factors parameter string, of the form
+ *     HxV[,HxV,...]
+ * If there are more components than parameters, "1x1" is assumed for the rest.
+ */
+{
+    int ci, val1, val2;
+    char ch1, ch2;
+
+    for (ci = 0; ci < MAX_COMPONENTS; ci++) {
+        if (*arg) {
+            ch2 = ',';		/* if not set by sscanf, will be ',' */
+            if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3)
+                return FALSE;
+            if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */
+                return FALSE;
+            if (val1 <= 0 || val1 > 4) {
+                pm_message("Invalid sampling factor: %d.  " 
+                           "JPEG sampling factors must be 1..4", val1);
+                return FALSE;
+            }
+            if (val2 <= 0 || val2 > 4) {
+                pm_message("Invalid sampling factor: %d.  "
+                           "JPEG sampling factors must be 1..4", val2);
+                return FALSE;
+            }
+            cinfo->comp_info[ci].h_samp_factor = val1;
+            cinfo->comp_info[ci].v_samp_factor = val2;
+            while (*arg && *arg++ != ',') 
+                /* advance to next segment of arg string */
+                ;
+        } else {
+            /* reached end of parameter, set remaining components 
+               to 1x1 sampling */
+            cinfo->comp_info[ci].h_samp_factor = 1;
+            cinfo->comp_info[ci].v_samp_factor = 1;
+        }
+    }
+    return TRUE;
+}
+
+
+
 static void
 setup_jpeg(struct jpeg_compress_struct * const cinfoP,
            struct jpeg_error_mgr       * const jerrP,
@@ -692,348 +1018,16 @@ convert_scanlines(struct jpeg_compress_struct * const cinfo_p,
 
 }
 
-/*----------------------------------------------------------------------------
-   The functions below here are essentially the file rdswitch.c from
-   the JPEG library.  They perform the functions specifed by the following
-   pnmtojpeg options:
-
-   -qtables file          Read quantization tables from text file
-   -scans file            Read scan script from text file
-   -qslots N[,N,...]      Set component quantization table selectors
-   -sample HxV[,HxV,...]  Set component sampling factors
------------------------------------------------------------------------------*/
-
-static int
-text_getc (FILE * file)
-/* Read next char, skipping over any comments (# to end of line) */
-/* A comment/newline sequence is returned as a newline */
-{
-    register int ch;
-  
-    ch = getc(file);
-    if (ch == '#') {
-        do {
-            ch = getc(file);
-        } while (ch != '\n' && ch != EOF);
-    }
-    return ch;
-}
-
-
-static boolean
-read_text_integer (FILE * file, long * result, int * termchar)
-/* Read an unsigned decimal integer from a file, store it in result */
-/* Reads one trailing character after the integer; returns it in termchar */
-{
-    register int ch;
-    register long val;
-  
-    /* Skip any leading whitespace, detect EOF */
-    do {
-        ch = text_getc(file);
-        if (ch == EOF) {
-            *termchar = ch;
-            return FALSE;
-        }
-    } while (isspace(ch));
-  
-    if (! isdigit(ch)) {
-        *termchar = ch;
-        return FALSE;
-    }
-
-    val = ch - '0';
-    while ((ch = text_getc(file)) != EOF) {
-        if (! isdigit(ch))
-            break;
-        val *= 10;
-        val += ch - '0';
-    }
-    *result = val;
-    *termchar = ch;
-    return TRUE;
-}
-
-
-static boolean
-read_quant_tables (j_compress_ptr cinfo, char * filename,
-                   int scale_factor, boolean force_baseline)
-/* Read a set of quantization tables from the specified file.
- * The file is plain ASCII text: decimal numbers with whitespace between.
- * Comments preceded by '#' may be included in the file.
- * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values.
- * The tables are implicitly numbered 0,1,etc.
- * NOTE: does not affect the qslots mapping, which will default to selecting
- * table 0 for luminance (or primary) components, 1 for chrominance components.
- * You must use -qslots if you want a different component->table mapping.
- */
-{
-    FILE * fp;
-    int tblno, i, termchar;
-    long val;
-    unsigned int table[DCTSIZE2];
-
-    if ((fp = fopen(filename, "rb")) == NULL) {
-        pm_message("Can't open table file %s", filename);
-        return FALSE;
-    }
-    tblno = 0;
-
-    while (read_text_integer(fp, &val, &termchar)) { /* read 1st element of table */
-        if (tblno >= NUM_QUANT_TBLS) {
-            pm_message("Too many tables in file %s", filename);
-            fclose(fp);
-            return FALSE;
-        }
-        table[0] = (unsigned int) val;
-        for (i = 1; i < DCTSIZE2; i++) {
-            if (! read_text_integer(fp, &val, &termchar)) {
-                pm_message("Invalid table data in file %s", filename);
-                fclose(fp);
-                return FALSE;
-            }
-            table[i] = (unsigned int) val;
-        }
-        jpeg_add_quant_table(cinfo, tblno, table, scale_factor, 
-                             force_baseline);
-        tblno++;
-    }
-
-    if (termchar != EOF) {
-        pm_message("Non-numeric data in file %s", filename);
-        fclose(fp);
-        return FALSE;
-    }
-
-    fclose(fp);
-    return TRUE;
-}
-
-
-static boolean
-read_scan_integer (FILE * file, long * result, int * termchar)
-/* Variant of read_text_integer that always looks for a non-space termchar;
- * this simplifies parsing of punctuation in scan scripts.
- */
-{
-    register int ch;
-
-    if (! read_text_integer(file, result, termchar))
-        return FALSE;
-    ch = *termchar;
-    while (ch != EOF && isspace(ch))
-        ch = text_getc(file);
-    if (isdigit(ch)) {		/* oops, put it back */
-        if (ungetc(ch, file) == EOF)
-            return FALSE;
-        ch = ' ';
-    } else {
-        /* Any separators other than ';' and ':' are ignored;
-         * this allows user to insert commas, etc, if desired.
-         */
-        if (ch != EOF && ch != ';' && ch != ':')
-            ch = ' ';
-    }
-    *termchar = ch;
-    return TRUE;
-}
-
-
-boolean
-read_scan_script (j_compress_ptr cinfo, char * filename)
-/* Read a scan script from the specified text file.
- * Each entry in the file defines one scan to be emitted.
- * Entries are separated by semicolons ';'.
- * An entry contains one to four component indexes,
- * optionally followed by a colon ':' and four progressive-JPEG parameters.
- * The component indexes denote which component(s) are to be transmitted
- * in the current scan.  The first component has index 0.
- * Sequential JPEG is used if the progressive-JPEG parameters are omitted.
- * The file is free format text: any whitespace may appear between numbers
- * and the ':' and ';' punctuation marks.  Also, other punctuation (such
- * as commas or dashes) can be placed between numbers if desired.
- * Comments preceded by '#' may be included in the file.
- * Note: we do very little validity checking here;
- * jcmaster.c will validate the script parameters.
- */
-{
-    FILE * fp;
-    int nscans, ncomps, termchar;
-    long val;
-#define MAX_SCANS  100      /* quite arbitrary limit */
-    jpeg_scan_info scans[MAX_SCANS];
-
-    if ((fp = fopen(filename, "r")) == NULL) {
-        pm_message("Can't open scan definition file %s", filename);
-        return FALSE;
-    }
-    nscans = 0;
-
-    while (read_scan_integer(fp, &val, &termchar)) {
-        nscans++;  /* We got another scan */
-        if (nscans > MAX_SCANS) {
-            pm_message("Too many scans defined in file %s", filename);
-            fclose(fp);
-            return FALSE;
-        }
-        scans[nscans-1].component_index[0] = (int) val;
-        ncomps = 1;
-        while (termchar == ' ') {
-            if (ncomps >= MAX_COMPS_IN_SCAN) {
-                pm_message("Too many components in one scan in file %s", 
-                           filename);
-                fclose(fp);
-                return FALSE;
-            }
-            if (! read_scan_integer(fp, &val, &termchar))
-                goto bogus;
-            scans[nscans-1].component_index[ncomps] = (int) val;
-            ncomps++;
-        }
-        scans[nscans-1].comps_in_scan = ncomps;
-        if (termchar == ':') {
-            if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
-                goto bogus;
-            scans[nscans-1].Ss = (int) val;
-            if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
-                goto bogus;
-            scans[nscans-1].Se = (int) val;
-            if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
-                goto bogus;
-            scans[nscans-1].Ah = (int) val;
-            if (! read_scan_integer(fp, &val, &termchar))
-                goto bogus;
-            scans[nscans-1].Al = (int) val;
-        } else {
-            /* set non-progressive parameters */
-            scans[nscans-1].Ss = 0;
-            scans[nscans-1].Se = DCTSIZE2-1;
-            scans[nscans-1].Ah = 0;
-            scans[nscans-1].Al = 0;
-        }
-        if (termchar != ';' && termchar != EOF) {
-        bogus:
-            pm_message("Invalid scan entry format in file %s", filename);
-            fclose(fp);
-            return FALSE;
-        }
-    }
-
-    if (termchar != EOF) {
-        pm_message("Non-numeric data in file %s", filename);
-        fclose(fp);
-        return FALSE;
-    }
-
-    if (nscans > 0) {
-        /* Stash completed scan list in cinfo structure.  NOTE: in
-         * this program, JPOOL_IMAGE is the right lifetime for this
-         * data, but if you want to compress multiple images you'd
-         * want JPOOL_PERMANENT.  
-         */
-        const unsigned int scan_info_size = nscans * sizeof(jpeg_scan_info);
-        jpeg_scan_info * const scan_info = 
-            (jpeg_scan_info *)
-            (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
-                                        scan_info_size);
-        memcpy(scan_info, scans, scan_info_size);
-        cinfo->scan_info = scan_info;
-        cinfo->num_scans = nscans;
-    }
-
-    fclose(fp);
-    return TRUE;
-}
-
-
-static boolean
-set_quant_slots (j_compress_ptr cinfo, char *arg)
-/* Process a quantization-table-selectors parameter string, of the form
- *     N[,N,...]
- * If there are more components than parameters, the last value is replicated.
- */
-{
-    int val = 0;			/* default table # */
-    int ci;
-    char ch;
-
-    for (ci = 0; ci < MAX_COMPONENTS; ci++) {
-        if (*arg) {
-            ch = ',';			/* if not set by sscanf, will be ',' */
-            if (sscanf(arg, "%d%c", &val, &ch) < 1)
-                return FALSE;
-            if (ch != ',')		/* syntax check */
-                return FALSE;
-            if (val < 0 || val >= NUM_QUANT_TBLS) {
-                pm_message("Invalid quantization table number: %d.  "
-                           "JPEG quantization tables are numbered 0..%d",
-                           val, NUM_QUANT_TBLS - 1);
-                return FALSE;
-            }
-            cinfo->comp_info[ci].quant_tbl_no = val;
-            while (*arg && *arg++ != ',') 
-                /* advance to next segment of arg string */
-                ;
-        } else {
-            /* reached end of parameter, set remaining components to last tbl*/
-            cinfo->comp_info[ci].quant_tbl_no = val;
-        }
-    }
-    return TRUE;
-}
-
-
-static boolean
-set_sample_factors (j_compress_ptr cinfo, char *arg)
-/* Process a sample-factors parameter string, of the form
- *     HxV[,HxV,...]
- * If there are more components than parameters, "1x1" is assumed for the rest.
- */
-{
-    int ci, val1, val2;
-    char ch1, ch2;
-
-    for (ci = 0; ci < MAX_COMPONENTS; ci++) {
-        if (*arg) {
-            ch2 = ',';		/* if not set by sscanf, will be ',' */
-            if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3)
-                return FALSE;
-            if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */
-                return FALSE;
-            if (val1 <= 0 || val1 > 4) {
-                pm_message("Invalid sampling factor: %d.  " 
-                           "JPEG sampling factors must be 1..4", val1);
-                return FALSE;
-            }
-            if (val2 <= 0 || val2 > 4) {
-                pm_message("Invalid sampling factor: %d.  "
-                           "JPEG sampling factors must be 1..4", val2);
-                return FALSE;
-            }
-            cinfo->comp_info[ci].h_samp_factor = val1;
-            cinfo->comp_info[ci].v_samp_factor = val2;
-            while (*arg && *arg++ != ',') 
-                /* advance to next segment of arg string */
-                ;
-        } else {
-            /* reached end of parameter, set remaining components 
-               to 1x1 sampling */
-            cinfo->comp_info[ci].h_samp_factor = 1;
-            cinfo->comp_info[ci].v_samp_factor = 1;
-        }
-    }
-    return TRUE;
-}
-
 
 
 int
-main(int argc, char ** argv) {
+main(int     argc,
+     char ** argv) {
 
     struct cmdlineInfo cmdline;
     struct jpeg_compress_struct cinfo;
     struct jpeg_error_mgr jerr;
-    FILE *input_file;
+    FILE * input_file;
     FILE * output_file;
     int height;  
         /* height of the input image in rows, as specified by its header */
diff --git a/converter/other/pnmtopalm/Makefile b/converter/other/pnmtopalm/Makefile
index d7bf2829..3d802ed6 100644
--- a/converter/other/pnmtopalm/Makefile
+++ b/converter/other/pnmtopalm/Makefile
@@ -25,7 +25,8 @@ $(BINARIES): %: %.o palmcolormap.o $(NETPBMLIB) $(LIBOPT)
 	  $(MATHLIB) $(LDLIBS) $(RPATH) $(LADD)
 
 gen_palm_colormap : % : %.c palmcolormap.o
-	$(CC) -I importinc $(CFLAGS) $(LDFLAGS) -o $@ $< palmcolormap.o \
+	$(CC) -I importinc $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ \
+	  $< palmcolormap.o \
 	  $(LIBOPTS) $(MATHLIB) $(LDLIBS) $(LADD)
 
 
diff --git a/converter/other/pnmtopng.c b/converter/other/pnmtopng.c
index ed245b93..4e267b99 100644
--- a/converter/other/pnmtopng.c
+++ b/converter/other/pnmtopng.c
@@ -383,7 +383,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 */
 
-    optParseOptions3( &argc, argv, opt, sizeof(opt), 0);
+    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
 
@@ -962,7 +962,7 @@ analyzeAlpha(FILE *     const ifp,
              gray       const alphaMaxval,
              bool *     const allOpaqueP,
              bool *     const singleColorIsTransP, 
-             pixel*     const alphaTranscolorP) {
+             pixel *    const alphaTranscolorP) {
 /*----------------------------------------------------------------------------
   Get information about the alpha mask, in combination with the masked
   image, that Caller can use to choose the most efficient way to
@@ -993,7 +993,7 @@ analyzeAlpha(FILE *     const ifp,
         */
         foundTransparentPixel = FALSE;  /* initial assumption */
         pm_seek2(ifp, &rasterPos, sizeof(rasterPos));
-        for (row = 0 ; row < rows && !foundTransparentPixel ; ++row) {
+        for (row = 0; row < rows && !foundTransparentPixel; ++row) {
             int col;
             pnm_readpnmrow(ifp, xelrow, cols, maxval, format);
             for (col = 0; col < cols && !foundTransparentPixel; ++col) {
@@ -2238,12 +2238,12 @@ convertpnm(struct cmdlineInfo const cmdline,
          of the input image.
       */
   int transexact;  
-    /* boolean: the user wants only the exact color he specified to be
-       transparent; not just something close to it.
-    */
+      /* boolean: the user wants only the exact color he specified to be
+         transparent; not just something close to it.
+      */
   int transparent;
   bool alpha;
-    /* There will be an alpha mask */
+      /* There will be an alpha mask */
   unsigned int pnm_meaningful_bits;
   pixel backcolor;
       /* The background color, with maxval equal to that of the input
@@ -2700,7 +2700,7 @@ main(int argc, char *argv[]) {
 
     int errorlevel;
     
-    pnm_init (&argc, argv);
+    pnm_init(&argc, argv);
     
     parseCommandLine(argc, argv, &cmdline);
     
diff --git a/converter/pbm/Makefile b/converter/pbm/Makefile
index 318b8e9e..f1533ab2 100644
--- a/converter/pbm/Makefile
+++ b/converter/pbm/Makefile
@@ -17,7 +17,7 @@ PORTBINARIES =	atktopbm brushtopbm cmuwmtopbm ddbugtopbm g3topbm escp2topbm \
 		pbmtomacp pbmtomatrixorbital pbmtomda pbmtomgr pbmtomrf \
 		pbmtonokia \
 		pbmtopi3 pbmtoplot pbmtopsg3 pbmtoptx pbmtowbmp \
-		pbmtox10bm pbmtoxbm pbmtoybm pbmtozinc \
+		pbmtoxbm pbmtoybm pbmtozinc \
 		pi3topbm pktopbm \
 		wbmptopbm xbmtopbm ybmtopbm	
 
@@ -29,7 +29,7 @@ endif
 #in libm?
 MATHBINARIES =	pbmtopk
 BINARIES =	$(PORTBINARIES) $(MATHBINARIES)
-SCRIPTS =
+SCRIPTS =       pbmtox10bm
 
 OBJECTS = $(BINARIES:%=%.o)
 
diff --git a/converter/pbm/cmuwmtopbm.c b/converter/pbm/cmuwmtopbm.c
index dce1d449..ce59491e 100644
--- a/converter/pbm/cmuwmtopbm.c
+++ b/converter/pbm/cmuwmtopbm.c
@@ -1,4 +1,4 @@
-/* cmuwmtopbm.c - read a CMU window manager bitmap and produce a portable bitmap
+/* cmuwmtopbm.c - read a CMU window manager bitmap and produce a PBM image.
 **
 ** Copyright (C) 1989 by Jef Poskanzer.
 **
@@ -10,105 +10,106 @@
 ** implied warranty.
 */
 
+/* 2006.10 (afu)
+   Changed bitrow from plain to raw, read function from getc() to fread(),
+   write function from pbm_writepbmrow() to pbm_writepbmrow_packed().
+   Retired bitwise transformation functions.
+
+   This program does not check the pad bits at the end of each row.
+*/
+
+
 #include "pbm.h"
 #include "cmuwm.h"
 
-static void getinit ARGS(( FILE* file, int* colsP, int* rowsP, short* depthP, int* padrightP ));
-static bit getbit ARGS(( FILE* file ));
 
-int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    bit* bitrow;
-    register bit* bP;
-    int rows, cols, padright, row, col;
-    short depth;
 
+static void
+readCmuwmHeader(FILE *         const ifP,
+                unsigned int * const colsP,
+                unsigned int * const rowsP,
+                unsigned int * const depthP) {
 
-    pbm_init( &argc, argv );
+    const char * const initReadError =
+        "CMU window manager header EOF / read error";
 
-    if ( argc > 2 )
-	pm_usage( "[cmuwmfile]" );
+    long l;
+    short s;
+    int rc;
+
+    rc = pm_readbiglong(ifP, &l);
+    if (rc == -1 )
+        pm_error(initReadError);
+    if (l != CMUWM_MAGIC)
+        pm_error("bad magic number in CMU window manager file");
+    rc = pm_readbiglong(ifP, &l);
+    if (rc == -1)
+        pm_error(initReadError);
+    *colsP = l;
+    rc = pm_readbiglong(ifP, &l);
+    if (rc == -1 )
+        pm_error(initReadError);
+    *rowsP = l;
+    rc = pm_readbigshort(ifP, &s);
+    if (rc == -1)
+        pm_error(initReadError);
+    *depthP = s;
+}
 
-    if ( argc == 2 )
-	ifp = pm_openr( argv[1] );
-    else
-	ifp = stdin;
-
-    getinit( ifp, &cols, &rows, &depth, &padright );
-    if ( depth != 1 )
-	pm_error(
-	    "CMU window manager file has depth of %d, must be 1",
-	    (int) depth );
-
-    pbm_writepbminit( stdout, cols, rows, 0 );
-    bitrow = pbm_allocrow( cols );
-
-    for ( row = 0; row < rows; ++row )
-	{
-	/* Get data. */
-        for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
-	    *bP = getbit( ifp );
-	/* Discard line padding */
-        for ( col = 0; col < padright; ++col )
-	    (void) getbit( ifp );
-	pbm_writepbmrow( stdout, bitrow, cols, 0 );
-	}
-
-    pm_close( ifp );
-    pm_close( stdout );
-
-    exit( 0 );
-    }
 
-static int item, bitsperitem, bitshift;
 
-static void
-getinit( file, colsP, rowsP, depthP, padrightP )
-    FILE* file;
-    int* colsP;
-    int* rowsP;
-    short* depthP;
-    int* padrightP;
-    {
-    long l;
+int
+main(int     argc,
+     char * argv[]) {
 
-    if ( pm_readbiglong( file, &l ) == -1 )
-	pm_error( "EOF / read error" );
-    if ( l != CMUWM_MAGIC )
-	pm_error( "bad magic number in CMU window manager file" );
-    if ( pm_readbiglong( file, &l ) == -1 )
-	pm_error( "EOF / read error" );
-    *colsP = (int) l;
-    if ( pm_readbiglong( file, &l ) == -1 )
-	pm_error( "EOF / read error" );
-    *rowsP = (int) l;
-    if ( pm_readbigshort( file, depthP ) == -1 )
-	pm_error( "EOF / read error" );
-    *padrightP = ( ( *colsP + 7 ) / 8 ) * 8 - *colsP;
-
-    bitsperitem = 0;
-    }
+    FILE * ifP;
+    unsigned char * bitrow;
+    unsigned int rows, cols, depth;
+    unsigned int row;
+
+    const char * inputFileName;
 
-static bit
-getbit( file )
-    FILE* file;
-    {
-    bit b;
-
-    if ( bitsperitem == 0 )
-	{
-	item = getc( file );
-	if ( item == EOF )
-	    pm_error( "EOF / read error" );
-	bitsperitem = 8;
-	bitshift = 7;
-	}
-    b = ( ( item >> bitshift) & 1 ) ? PBM_WHITE : PBM_BLACK;
-    --bitsperitem;
-    --bitshift;
-    return b;
+    pbm_init(&argc, argv);
+
+    if (argc-1 > 1)
+        pm_error("Too many arguments (%u).  "
+                 "Only argument is optional input file", argc-1);
+    if (argc-1 == 1)
+        inputFileName = argv[1];
+    else
+        inputFileName = "-";
+    
+    ifP = pm_openr(inputFileName);
+
+    readCmuwmHeader(ifP, &cols, &rows, &depth);
+    if (depth != 1)
+        pm_error("CMU window manager file has depth of %u, must be 1", depth);
+
+    pbm_writepbminit(stdout, cols, rows, 0);
+    bitrow = pbm_allocrow_packed(cols);
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int const bytesPerRow = pbm_packed_bytes(cols);
+        unsigned int byteSeq;
+        size_t bytesRead;
+
+        bytesRead = fread(bitrow, 1, bytesPerRow, ifP);
+        if (bytesRead != bytesPerRow)
+            pm_error("CWU window manager bitmap EOF / read error");
+            
+        /* Invert all bits in row - raster formats are similar.
+           CMUWM Black:0 White:1  End of row padded with 1
+           PBM   Black:1 White:0  End preferably padded with 0
+        */
+   
+        for (byteSeq = 0; byteSeq < bytesPerRow; ++byteSeq)
+            bitrow[byteSeq] = ~bitrow[byteSeq];
+                
+        pbm_writepbmrow_packed(stdout, bitrow, cols, 0);
     }
+
+    pm_close(ifP);
+    pm_close(stdout);
+
+    return 0;
+}
diff --git a/converter/pbm/mgrtopbm.c b/converter/pbm/mgrtopbm.c
index cea4be48..9f7004a1 100644
--- a/converter/pbm/mgrtopbm.c
+++ b/converter/pbm/mgrtopbm.c
@@ -1,13 +1,10 @@
-/* mgrtopbm.c - read a MGR bitmap and produce a portable bitmap
-**
-** Copyright (C) 1989 by Jef Poskanzer.
-**
-** Permission to use, copy, modify, and distribute this software and its
-** documentation for any purpose and without fee is hereby granted, provided
-** that the above copyright notice appear in all copies and that both that
-** copyright notice and this permission notice appear in supporting
-** documentation.  This software is provided "as is" without express or
-** implied warranty.
+/* mgrtopbm.c - read a MGR bitmap and produce a PBM image.
+
+   Copyright information is at end of file.
+
+   You can find MGR and some MGR format test images at
+   ftp://sunsite.unc.edu/pub/Linux/apps/MGR/!INDEX.html
+
 */
 
 #include <string.h>
@@ -17,29 +14,29 @@
 #include "mgr.h"
 
 
-static unsigned char item;
-static int bitsperitem, bitshift;
 
 static void
-getinit(FILE * const file, 
-        int *  const colsP, 
-        int *  const rowsP, 
-        int *  const depthP, 
-        int *  const padrightP,
-        int *  const bitsperitemP) {
-
+readMgrHeader(FILE *          const ifP, 
+              unsigned int *  const colsP, 
+              unsigned int *  const rowsP, 
+              unsigned int *  const depthP, 
+              unsigned int *  const padrightP ) {
+    
     struct b_header head;
-    int pad;
+    unsigned int pad;
+    size_t bytesRead;
 
-    if (fread(&head, sizeof(struct old_b_header), 1, file ) != 1)
+    bytesRead = fread(&head, sizeof(struct old_b_header), 1, ifP);
+    if (bytesRead != 1)
         pm_error("Unable to read 1st byte of file.  "
                  "fread() returns errno %d (%s)",
                  errno, strerror(errno));
     if (head.magic[0] == 'y' && head.magic[1] == 'z') { 
         /* new style bitmap */
-        if (fread(&head.depth, 
-                  sizeof(head) - sizeof(struct old_b_header), 1, file) 
-             != 1 )
+        size_t bytesRead;
+        bytesRead = fread(&head.depth, 
+                          sizeof(head) - sizeof(struct old_b_header), 1, ifP);
+        if (bytesRead != 1 )
             pm_error("Unable to read header after 1st byte.  "
                      "fread() returns errno %d (%s)",
                      errno, strerror(errno));
@@ -60,7 +57,7 @@ getinit(FILE * const file,
     } else {
         pm_error("bad magic chars in MGR file: '%c%c'",
                  head.magic[0], head.magic[1] );
-        pad = -1;  /* should never reach here */
+        pad = 0;  /* should never reach here */
     }
 
     if (head.h_wide < ' ' || head.l_wide < ' ')
@@ -71,75 +68,79 @@ getinit(FILE * const file,
     *colsP = (((int)head.h_wide - ' ') << 6) + ((int)head.l_wide - ' ');
     *rowsP = (((int)head.h_high - ' ') << 6) + ((int) head.l_high - ' ');
     *padrightP = ( ( *colsP + pad - 1 ) / pad ) * pad - *colsP;
-    
-    *bitsperitemP = 8;
 }
 
 
 
-static bit
-getbit( file )
-    FILE* file;
-    {
-    bit b;
-
-    if ( bitsperitem == 8 )
-	{
-	item = getc( file );
-	bitsperitem = 0;
-	bitshift = 7;
-	}
-    bitsperitem++;
-    b = ( ( item >> bitshift) & 1 ) ? PBM_BLACK : PBM_WHITE;
-    bitshift--;
-    return b;
-    }
-
+int
+main(int    argc,
+     char * argv[]) {
+
+    FILE * ifP;
+    unsigned char * bitrow;
+    unsigned int rows, cols, depth;
+    unsigned int padright;
+    unsigned int row;
+    unsigned int itemCount;
+    const char * inputFileName;
+
+    pbm_init(&argc, argv);
+
+    if (argc-1 > 1)
+        pm_error("Too many arguments (%u).  "
+                 "Only argument is optional input file", argc-1);
+    if (argc-1 == 1)
+        inputFileName = argv[1];
+    else
+        inputFileName = "-";
+    
+    ifP = pm_openr(inputFileName);
 
+    readMgrHeader(ifP, &cols, &rows, &depth, &padright);
+    if (depth != 1)
+        pm_error("MGR file has depth of %u, must be 1", depth);
 
-int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    bit* bitrow;
-    register bit* bP;
-    int rows, cols, depth, padright, row, col;
+    pbm_writepbminit(stdout, cols, rows, 0);
 
+    bitrow = pbm_allocrow_packed(cols + padright);
+    
+    itemCount = (cols + padright ) / 8;
+
+    for (row = 0; row < rows; ++row) {
+        /* The raster formats are nearly identical.
+           MGR may have rows padded to 16 or 32 bit boundaries.
+        */
+        size_t bytesRead;
+        bytesRead = fread(bitrow, 1, itemCount, ifP);
+        if (bytesRead < itemCount)
+            pm_error("fread() failed to read mgr bitmap data");
+
+        pbm_writepbmrow_packed(stdout, bitrow, cols, 0);
+    }
+    pm_close(ifP);
+    pm_close(stdout);
+    return 0;
+}
 
-    pbm_init( &argc, argv );
 
-    if ( argc > 2 )
-	pm_usage( "[mgrfile]" );
 
-    if ( argc == 2 )
-	ifp = pm_openr( argv[1] );
-    else
-	ifp = stdin;
-
-    getinit( ifp, &cols, &rows, &depth, &padright, &bitsperitem );
-    if ( depth != 1 )
-	pm_error( "MGR file has depth of %d, must be 1", depth );
-
-    pbm_writepbminit( stdout, cols, rows, 0 );
-    bitrow = pbm_allocrow( cols );
-
-    for ( row = 0; row < rows; row++ )
-	{
-	/* Get data, bit-reversed within each byte. */
-        for ( col = 0, bP = bitrow; col < cols; col++, bP++ )
-	    *bP = getbit( ifp );
-	/* Discard line padding */
-        for ( col = 0; col < padright; col ++ )
-	    (void) getbit( ifp );
-	pbm_writepbmrow( stdout, bitrow, cols, 0 );
-	}
-
-    pm_close( ifp );
-    pm_close( stdout );
-
-    exit( 0 );
-    }
+/* 2006.10 (afu)
+   Changed bitrow from plain to raw, read function from getc() to fread(),
+   write function from pbm_writepbmrow() to pbm_writepbmrow_packed().
+   Retired bitwise transformation functions.
+   
+   NOT tested for old-style format files.  Only one zz file in mgrsrc-0.69 .
+  
+*/
 
 
+/*
+** Copyright (C) 1989 by Jef Poskanzer.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation.  This software is provided "as is" without express or
+** implied warranty.
+*/
diff --git a/converter/pbm/pbmtocmuwm.c b/converter/pbm/pbmtocmuwm.c
index 64d7af40..773d988b 100644
--- a/converter/pbm/pbmtocmuwm.c
+++ b/converter/pbm/pbmtocmuwm.c
@@ -1,4 +1,4 @@
-/* pbmtocmuwm.c - read a portable bitmap and produce a CMU window manager bitmap
+/* pbmtocmuwm.c - read a PBM image and produce a CMU window manager bitmap
 **
 ** Copyright (C) 1989 by Jef Poskanzer.
 **
@@ -10,108 +10,95 @@
 ** implied warranty.
 */
 
-#include "pbm.h"
-#include "cmuwm.h"
+/* 2006.10 (afu)
+   Changed bitrow from plain to raw, read function from pbm_readpbmrow() to
+   pbm_readpbmrow_packed(), write function from putc() to fwrite().
 
-static void putinit ARGS(( int rows, int cols ));
-static void putbit ARGS(( bit b ));
-static void putrest ARGS(( void ));
-static void putitem ARGS(( void ));
-
-int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    bit* bitrow;
-    register bit* bP;
-    int rows, cols, format, padright, row, col;
+   Retired bitwise transformation functions.
+*/
 
+#include "pbm.h"
+#include "cmuwm.h"
 
-    pbm_init( &argc, argv );
+static void
+putinit(unsigned int const rows,
+        unsigned int const cols) {
 
-    if ( argc > 2 )
-	pm_usage( "[pbmfile]" );
+    const char * const initWriteError =
+        "CMU window manager header write error";
 
-    if ( argc == 2 )
-	ifp = pm_openr( argv[1] );
-    else
-	ifp = stdin;
+    int rc;
 
-    pbm_readpbminit( ifp, &cols, &rows, &format );
-    bitrow = pbm_allocrow( cols );
-    
-    /* Round cols up to the nearest multiple of 8. */
-    padright = ( ( cols + 7 ) / 8 ) * 8 - cols;
+    rc = pm_writebiglong(stdout, CMUWM_MAGIC);
+    if (rc == -1)
+        pm_error(initWriteError);
+    rc = pm_writebiglong(stdout, cols);
+    if (rc == -1)
+        pm_error(initWriteError);
+    rc = pm_writebiglong(stdout, rows);
+    if (rc == -1)
+        pm_error(initWriteError);
+    rc = pm_writebigshort(stdout, (short) 1);
+    if (rc == -1)
+        pm_error(initWriteError);
+}
 
-    putinit( rows, cols );
-    for ( row = 0; row < rows; row++ )
-	{
-	pbm_readpbmrow( ifp, bitrow, cols, format );
-        for ( col = 0, bP = bitrow; col < cols; col++, bP++ )
-	    putbit( *bP );
-	for ( col = 0; col < padright; col++ )
-	    putbit( 0 );
-        }
 
-    pm_close( ifp );
 
-    putrest( );
+int
+main(int argc,
+     char * argv[]) {
 
-    exit( 0 );
-    }
+    FILE * ifP;
+    unsigned char * bitrow;
+    int rows, cols;
+    int format;
+    unsigned int row;
+    const char * inputFileName;
 
-static unsigned char item;
-static int bitsperitem, bitshift;
+    pbm_init(&argc, argv);
 
-static void
-putinit( rows, cols )
-    int rows, cols;
-    {
-    if ( pm_writebiglong( stdout, CMUWM_MAGIC ) == -1 )
-	pm_error( "write error" );
-    if ( pm_writebiglong( stdout, cols ) == -1 )
-	pm_error( "write error" );
-    if ( pm_writebiglong( stdout, rows ) == -1 )
-	pm_error( "write error" );
-    if ( pm_writebigshort( stdout, (short) 1 ) == -1 )
-	pm_error( "write error" );
-
-    item = 0;
-    bitsperitem = 0;
-    bitshift = 7;
-    }
+    if (argc-1 > 1)
+        pm_error("Too many arguments (%u).  "
+                 "Only argument is optional input file", argc-1);
+    if (argc-1 == 1)
+        inputFileName = argv[1];
+    else
+        inputFileName = "-";
+    
+    ifP = pm_openr(inputFileName);
 
-#if __STDC__
-static void
-putbit( bit b )
-#else /*__STDC__*/
-static void
-putbit( b )
-    bit b;
-#endif /*__STDC__*/
-    {
-    if ( bitsperitem == 8 )
-	putitem( );
-    if ( b == PBM_WHITE )
-	item += 1 << bitshift;
-    bitsperitem++;
-    bitshift--;
-    }
+    pbm_readpbminit(ifP, &cols, &rows, &format);
+    bitrow = pbm_allocrow_packed(cols);
 
-static void
-putrest( )
-    {
-    if ( bitsperitem > 0 )
-	putitem( );
+    putinit(rows, cols);
+    
+    /* Convert PBM raster data to CMUWM and write */ 
+    for (row = 0; row < rows; ++row) {
+        unsigned int const bytesPerRow = pbm_packed_bytes(cols);
+        unsigned char const padding = 
+            (cols % 8 == 0) ? 0x00 : ((unsigned char) ~0 >> (cols % 8));
+
+        unsigned int i;
+        size_t bytesWritten;
+
+        pbm_readpbmrow_packed(ifP, bitrow, cols, format);
+
+        /* Invert all bits in row - raster formats are similar.
+           PBM   Black:1 White:0  "Don't care" bits at end of row
+           CMUWM Black:0 White:1  End of row padded with 1
+        */
+
+        for (i = 0; i < bytesPerRow; ++i)
+            bitrow[i] = ~bitrow[i];
+
+        bitrow[bytesPerRow-1] |= padding;  /* Set row end pad bits */
+        
+        bytesWritten = fwrite(bitrow, 1, bytesPerRow, stdout);
+        if (bytesWritten != bytesPerRow)
+            pm_error("fwrite() failed to write CMU window manager bitmap");
     }
 
-static void
-putitem( )
-    {
-    (void) putc( item, stdout );
-    item = 0;
-    bitsperitem = 0;
-    bitshift = 7;
-    }
+    pm_close(ifP);
+    return 0;
+}
diff --git a/converter/pbm/pbmtogem.c b/converter/pbm/pbmtogem.c
index 59f2b9cf..cefbdc95 100644
--- a/converter/pbm/pbmtogem.c
+++ b/converter/pbm/pbmtogem.c
@@ -129,14 +129,8 @@ putinit (rows, cols)
   linerepeat = -1;
 }
 
-#if __STDC__
 static void
 putbit( bit b )
-#else /*__STDC__*/
-static void
-putbit( b )
-    bit b;
-#endif /*__STDC__*/
     {
     if ( bitsperitem == 8 )
 	putitem( );
diff --git a/converter/pbm/pbmtogo.c b/converter/pbm/pbmtogo.c
index b7c12373..67fe5821 100644
--- a/converter/pbm/pbmtogo.c
+++ b/converter/pbm/pbmtogo.c
@@ -214,7 +214,7 @@ main( argc, argv )
             fflush(stdout);
 
             /* Output the plot data */
-            write(1, outbuffer, nout);
+            fwrite(outbuffer, 1, nout, stdout);
 
             /* Reset the counters */
             linerepeat = 0;
@@ -225,7 +225,7 @@ main( argc, argv )
                   putchar(linerepeat);
                   printf("%d/", nout+1);
                   fflush(stdout);
-                  write(1, outbuffer, nout);
+                  fwrite(outbuffer, 1, nout, stdout);
                   linerepeat = 0;
               }
         }
@@ -264,14 +264,8 @@ putinit()
   bitshift = 7;
 }
 
-#if __STDC__
 static void
 putbit(bit b)
-#else /*__STDC__*/
-static void
-putbit(b)
-bit b;
-#endif /*__STDC__*/
 {
   if (b == PBM_BLACK)
     item += 1 << bitshift;
diff --git a/converter/pbm/pbmtoicon.c b/converter/pbm/pbmtoicon.c
index 0e21c202..d5fefb76 100644
--- a/converter/pbm/pbmtoicon.c
+++ b/converter/pbm/pbmtoicon.c
@@ -1,4 +1,4 @@
-/* pbmtoicon.c - read a portable bitmap and produce a Sun icon file
+/* pbmtoicon.c - read a PBM image and produce a Sun icon file
 **
 ** Copyright (C) 1988 by Jef Poskanzer.
 **
@@ -10,125 +10,177 @@
 ** implied warranty.
 */
 
+/* 2006.10 (afu)
+   Changed bitrow from plain to raw, read function from pbm_readpbmrow() to
+   pbm_readpbmrow_packed.  Applied wordint to scoop up 16 bit output items.
+   putitem changed to better express the output format.
+   Retired bitwise transformation functions.
+*/
+
+#include "wordaccess.h"
 #include "pbm.h"
 
-static void putinit ARGS(( void ));
-static void putbit ARGS(( bit b ));
-static void putrest ARGS(( void ));
-static void putitem ARGS(( void ));
+static unsigned short int itemBuff[8];
+static unsigned int itemCnt;    /* takes values 0 to 8 */
+FILE * putFp;
 
-int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    bit* bitrow;
-    register bit* bP;
-    int rows, cols, format, pad, padleft, padright, row, col;
 
 
-    pbm_init( &argc, argv );
+static void
+putinit(FILE * const ofP) {
+    putFp = ofP;
+    itemCnt = 0;
+}
 
-    if ( argc > 2 )
-	pm_usage( "[pbmfile]" );
 
-    if ( argc == 2 )
-	ifp = pm_openr( argv[1] );
-    else
-	ifp = stdin;
 
-    pbm_readpbminit( ifp, &cols, &rows, &format );
-    bitrow = pbm_allocrow( cols );
+static void
+putitem(wordint const item) {
+
+    if (itemCnt == 8 ) {
+        /* Buffer is full.  Write out one line. */
+        int rc;
     
-    /* Round cols up to the nearest multiple of 16. */
-    pad = ( ( cols + 15 ) / 16 ) * 16 - cols;
-    padleft = pad / 2;
-    padright = pad - padleft;
-
-    printf( "/* Format_version=1, Width=%d, Height=%d", cols + pad, rows );
-    printf( ", Depth=1, Valid_bits_per_item=16\n */\n" );
-
-    putinit( );
-    for ( row = 0; row < rows; ++row )
-	{
-	pbm_readpbmrow( ifp, bitrow, cols, format );
-	for ( col = 0; col < padleft; ++col )
-	    putbit( 0 );
-        for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
-	    putbit( *bP );
-	for ( col = 0; col < padright; ++col )
-	    putbit( 0 );
-        }
+        rc = fprintf(putFp,
+                     "\t0x%04x,0x%04x,0x%04x,0x%04x,"
+                     "0x%04x,0x%04x,0x%04x,0x%04x,\n",
+                     itemBuff[0],itemBuff[1],itemBuff[2],itemBuff[3],
+                     itemBuff[4],itemBuff[5],itemBuff[6],itemBuff[7]);
+        if (rc < 0)        
+           pm_error("fprintf() failed to write Icon bitmap");
+           
+        itemCnt = 0;
+    }
+    itemBuff[itemCnt++] = item & 0xffff;  /* Only lower 16 bits are used */
+}
 
-    pm_close( ifp );
 
-    putrest( );
 
-    exit( 0 );
-    }
+static void
+putterm(void) {
 
-static int item, bitsperitem, bitshift, itemsperline, firstitem;
+    unsigned int i;
 
-static void
-putinit( )
-    {
-    itemsperline = 0;
-    bitsperitem = 0;
-    item = 0;
-    bitshift = 15;
-    firstitem = 1;
+    for (i = 0; i < itemCnt; ++i) {
+        int rc;
+        rc = fprintf(putFp, "%s0x%04x%c", i == 0  ? "\t" : "", itemBuff[i],
+                     i == itemCnt - 1 ? '\n' : ',');
+        if (rc < 0)        
+            pm_error("fprintf() failed to write Icon bitmap");
     }
+}     
+
+
 
-#if __STDC__
-static void
-putbit( bit b )
-#else /*__STDC__*/
 static void
-putbit( b )
-bit b;
-#endif /*__STDC__*/
-    {
-    if ( bitsperitem == 16 )
-	putitem( );
-    ++bitsperitem;
-    if ( b == PBM_BLACK )
-	item += 1 << bitshift;
-    --bitshift;
-    }
+writeIconHeader(FILE *       const ofP,
+                unsigned int const width,
+                unsigned int const height) {
+
+    int rc;
+
+    rc = fprintf(ofP,
+                 "/* Format_version=1, Width=%u, Height=%u", width, height);
+    if (rc < 0)
+        pm_error("fprintf() failed to write Icon header");
+        
+    rc = fprintf(ofP, ", Depth=1, Valid_bits_per_item=16\n */\n");
+    if (rc < 0)
+        pm_error("fprintf() failed to write Icon header");
+}
+
+
 
 static void
-putrest( )
-    {
-    if ( bitsperitem > 0 )
-	putitem( );
-    putchar( '\n' );
+writeIcon(FILE *       const ifP,
+          unsigned int const cols,
+          unsigned int const rows,
+          int          const format,
+          FILE *       const ofP) {
+
+    unsigned int const wordintSize = sizeof(wordint) * 8;
+        /* wordintSize is usually 32 or 64 bits.  Must be at least 24. */
+    unsigned int const items = (cols + 15) / 16;
+    unsigned int const bitrowBytes = pbm_packed_bytes(cols);
+    unsigned int const pad = items * 16 - cols;
+    /* 'padleft' is added to the output.  'padbyte' is for cleaning
+       the input
+    */
+    unsigned int const padleft = pad / 2;
+    unsigned int const padbyte = bitrowBytes * 8 - cols;
+    unsigned int const shift   = (wordintSize - 24) + padleft;
+    
+    unsigned char * bitbuffer;
+    unsigned char * bitrow;
+    unsigned int row;
+
+    bitbuffer = pbm_allocrow_packed(cols + wordintSize);
+    bitrow = &bitbuffer[1];
+    bitbuffer[0] = 0;
+    bitrow[bitrowBytes] = 0;
+    
+    writeIconHeader(ofP, cols + pad, rows);
+
+    putinit(ofP);
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int itemSeq;
+        pbm_readpbmrow_packed(ifP, bitrow, cols, format);
+
+        /* Clear post-data junk in final partial byte */
+        if (padbyte > 0) {
+            bitrow[bitrowBytes-1] >>= padbyte;
+            bitrow[bitrowBytes-1] <<= padbyte;
+        }
+        
+        for (itemSeq = 0; itemSeq < items; ++itemSeq) {
+            /* Scoop up bits, shift-align, send to format & print function.
+    
+               An item is 16 bits, typically spread over 3 bytes due to
+               left-padding.  We use wordint here to scoop up 4 (or more)
+               consecutive bytes.  An item always resides within the higher
+               24 bits of each scoop.  It is essential to use wordint
+               (or rather the wordaccess function bytesToWordInt() ); 
+               simple long, uint_32t, etc. do not work for they are not
+               shift-tolerant.
+            */
+            
+            wordint const scoop = bytesToWordint(&bitbuffer[itemSeq*2]);
+            putitem (scoop >> shift);
+        }
     }
+    putterm();    
+}
 
-static void
-putitem( )
-    {
-    const char* hexits = "0123456789abcdef";
 
-    if ( firstitem )
-	firstitem = 0;
+
+int
+main(int argc,
+     char * argv[]) {
+
+    FILE * ifP;
+    int rows, cols;
+    int format;
+    const char * inputFileName;
+
+    pbm_init(&argc, argv);
+
+    if (argc-1 > 1)
+        pm_error("Too many arguments (%u).  "
+                 "Only argument is optional input file", argc-1);
+    if (argc-1 == 1)
+        inputFileName = argv[1];
     else
-	putchar( ',' );
-    if ( itemsperline == 8 )
-	{
-	putchar( '\n' );
-	itemsperline = 0;
-	}
-    if ( itemsperline == 0 )
-	putchar( '\t' );
-    putchar( '0' );
-    putchar( 'x' );
-    putchar( hexits[item >> 12] );
-    putchar( hexits[( item >> 8 ) & 15] );
-    putchar( hexits[( item >> 4 ) & 15] );
-    putchar( hexits[item & 15] );
-    ++itemsperline;
-    bitsperitem = 0;
-    item = 0;
-    bitshift = 15;
-    }
+        inputFileName = "-";
+    
+    ifP = pm_openr(inputFileName);
+
+    pbm_readpbminit(ifP, &cols, &rows, &format);
+
+    writeIcon(ifP, cols, rows, format, stdout);
+
+    pm_close(ifP);
+
+    return 0;
+}
+
diff --git a/converter/pbm/pbmtomgr.c b/converter/pbm/pbmtomgr.c
index 7a6e7fc1..2ca7c7d0 100644
--- a/converter/pbm/pbmtomgr.c
+++ b/converter/pbm/pbmtomgr.c
@@ -1,120 +1,114 @@
-/* pbmtomgr.c - read a portable bitmap and produce a MGR bitmap
-**
-** Copyright (C) 1989 by Jef Poskanzer.
-**
-** Permission to use, copy, modify, and distribute this software and its
-** documentation for any purpose and without fee is hereby granted, provided
-** that the above copyright notice appear in all copies and that both that
-** copyright notice and this permission notice appear in supporting
-** documentation.  This software is provided "as is" without express or
-** implied warranty.
+/* pbmtomgr.c - read a PBM image and produce a MGR bitmap
+
+   Copyright information is at end of file.
+
+   You can find MGR and some MGR format test images at
+   ftp://sunsite.unc.edu/pub/Linux/apps/MGR/!INDEX.html
 */
 
 #include "pbm.h"
 #include "mgr.h"
 
-static void putinit ARGS(( int rows, int cols ));
-static void putbit ARGS(( bit b ));
-static void putrest ARGS(( void ));
-static void putitem ARGS(( void ));
+static void
+putinit(unsigned int const rows,
+        unsigned int const cols) {
 
-int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    bit* bitrow;
-    register bit* bP;
-    int rows, cols, format, padright, row, col;
+    struct b_header head;
+    size_t writtenCount;
 
+    head.magic[0] = 'y';
+    head.magic[1] = 'z';
+    head.h_wide = ((cols >> 6) & 0x3f) + ' ';
+    head.l_wide = (cols & 0x3f) + ' ';
+    head.h_high = (( rows >> 6) & 0x3f) + ' ';
+    head.l_high = (rows & 0x3f) + ' ';
+    head.depth = (1 & 0x3f) + ' ';
+    head._reserved = ' ';
+    writtenCount = fwrite(&head, sizeof(head), 1, stdout);
+    if (writtenCount != 1)
+        pm_error("fwrite() failed to write the MGR header.");    
+}
 
-    pbm_init( &argc, argv );
 
-    if ( argc > 2 )
-	pm_usage( "[pbmfile]" );
 
-    if ( argc == 2 )
-	ifp = pm_openr( argv[1] );
+int
+main(int argc,
+     char * argv[]) {
+
+    FILE * ifP;
+    unsigned char * bitrow;
+    int rows;
+    int cols;
+    int format;
+    unsigned int row;
+    unsigned int bytesPerRow;
+        /* Number of packed bytes (8 columns per byte) in a row. */
+    unsigned int padright;
+        /* Number of columns added to the right of each row to get up to
+           a multiple of 8, i.e. an integral number of packed bytes.
+        */
+    const char * inputFileName;
+
+    pbm_init(&argc, argv);
+
+    if (argc-1 > 1)
+        pm_error("Too many arguments (%u).  "
+                 "Only argument is optional input file", argc-1);
+    if (argc-1 == 1)
+        inputFileName = argv[1];
     else
-	ifp = stdin;
-
-    pbm_readpbminit( ifp, &cols, &rows, &format );
-    bitrow = pbm_allocrow( cols );
+        inputFileName = "-";
     
-    /* Round cols up to the nearest multiple of 8. */
-    padright = ( ( cols + 7 ) / 8 ) * 8 - cols;
-
-    putinit( rows, cols );
-    for ( row = 0; row < rows; ++row )
-	{
-	pbm_readpbmrow( ifp, bitrow, cols, format );
-        for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
-	    putbit( *bP );
-	for ( col = 0; col < padright; ++col )
-	    putbit( 0 );
-        }
+    ifP = pm_openr(inputFileName);
 
-    pm_close( ifp );
+    pbm_readpbminit(ifP, &cols, &rows, &format);
+    
+    bitrow = pbm_allocrow_packed(cols);
+    bytesPerRow = pbm_packed_bytes(cols);
+    padright = bytesPerRow * 8 - cols;
 
-    putrest( );
+    putinit(rows, cols);
+    
+    for (row = 0; row < rows; ++row) {
+        /* The raster formats are identical. 
+           The row end pad bits are set to 0 in mgr.
+        */
+        size_t bytesWritten;
+
+        pbm_readpbmrow_packed(ifP, bitrow, cols, format);
+        
+        if (padright > 0) {
+            bitrow[bytesPerRow-1] >>= padright;
+            bitrow[bytesPerRow-1] <<= padright;
+        }
 
-    exit( 0 );
+        bytesWritten = fwrite(bitrow, 1, bytesPerRow, stdout);
+        if (bytesWritten != bytesPerRow )
+            pm_error("fwrite() failed to write MGR bitmap "
+                     "to Standard Output.");    
     }
+    pm_close(ifP);
+    return 0;
+}
 
-static unsigned char item;
-static int bitsperitem, bitshift;
-
-static void
-putinit( rows, cols )
-    int rows, cols;
-    {
-    struct b_header head;
-
-    head.magic[0] = 'y';
-    head.magic[1] = 'z';
-    head.h_wide = ( ( cols >> 6 ) & 0x3f ) + ' ';
-    head.l_wide = ( cols & 0x3f ) + ' ';
-    head.h_high = ( ( rows >> 6 ) & 0x3f ) + ' ';
-    head.l_high = ( rows & 0x3f ) + ' ';
-    head.depth = ( 1 & 0x3f ) + ' ';
-    head._reserved = ' ';
-    fwrite( &head, sizeof(head), 1, stdout );
 
-    item = 0;
-    bitsperitem = 0;
-    bitshift = 7;
-    }
 
-#if __STDC__
-static void
-putbit( bit b )
-#else /*__STDC__*/
-static void
-putbit( b )
-    bit b;
-#endif /*__STDC__*/
-    {
-    if ( bitsperitem == 8 )
-	putitem( );
-    ++bitsperitem;
-    if ( b == PBM_BLACK )
-	item += 1 << bitshift;
-    --bitshift;
-    }
+/* 2006.10 (afu)
+   Changed bitrow from plain to raw, read function from pbm_readpbmrow() to
+   pbm_readpbmrow_packed(), write function from putc() to fwrite().
 
-static void
-putrest( )
-    {
-    if ( bitsperitem > 0 )
-	putitem( );
-    }
+   Retired bitwise transformation functions.
+   
+   Produces only new style bitmap (8 bit padding.)  See mgrtopbm.c .
+*/
 
-static void
-putitem( )
-    {
-    fwrite( &item, sizeof(item), 1, stdout );
-    item = 0;
-    bitsperitem = 0;
-    bitshift = 7;
-    }
+/*
+** Copyright (C) 1989 by Jef Poskanzer.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation.  This software is provided "as is" without express or
+** implied warranty.
+*/
diff --git a/converter/pbm/pbmtopi3.c b/converter/pbm/pbmtopi3.c
index 06023d7a..6a60af62 100644
--- a/converter/pbm/pbmtopi3.c
+++ b/converter/pbm/pbmtopi3.c
@@ -89,14 +89,8 @@ putinit( )
     bitshift = 7;
     }
 
-#if __STDC__
 static void
 putbit( bit b )
-#else /*__STDC__*/
-static void
-putbit( b )
-    bit b;
-#endif /*__STDC__*/
     {
     if (bitsperitem == 8)
 	putitem( );
diff --git a/converter/pbm/pbmtoptx.c b/converter/pbm/pbmtoptx.c
index 5031efcb..8cd60326 100644
--- a/converter/pbm/pbmtoptx.c
+++ b/converter/pbm/pbmtoptx.c
@@ -67,14 +67,8 @@ putinit( )
     bitshift = 0;
     }
 
-#if __STDC__
 static void
 putbit( bit b )
-#else /*__STDC__*/
-static void
-putbit( b )
-    bit b;
-#endif /*__STDC__*/
     {
     if ( bitsperitem == 6 )
 	putitem( );
diff --git a/converter/pbm/pbmtox10bm b/converter/pbm/pbmtox10bm
new file mode 100644
index 00000000..9a1a7286
--- /dev/null
+++ b/converter/pbm/pbmtox10bm
@@ -0,0 +1,45 @@
+#! /usr/bin/perl
+
+#============================================================================
+#  This is a compatibility interface to Pbmtoxbm.
+#
+#  It exists so existing programs and procedures that rely on Pbmtox10bm
+#  syntax continue to work.  You should not make new use of Pbmtox10bm and
+#  if you modify an old use, you should upgrade it to use Pbmtoxbm.
+#
+#  Pbmtoxbm with the -x10 option is backward compatible with Pbmtox10bm.
+#============================================================================
+
+use strict;
+use File::Basename;
+use Cwd 'abs_path';
+
+my $infile;
+
+foreach (@ARGV) {
+    if (/^-/) {
+        # It's an option.  But Pbmtox10bm didn't have any options.
+        print(STDERR "Invalid option '$_'\n");
+        exit(10);
+    } else {
+        # It's a parameter
+        if (defined($infile)) {
+            print(STDERR
+                  "You may specify at most one non-option parameter.\n");
+            exit(10);
+        } else {
+            $infile = $_;
+        }
+    }
+}
+
+my $infileParm = defined($infile) ? $infile : "-";
+
+# We want to get Pbmtoxbm from the same directory we came from if
+# it's there.  Frequently, the directory containing Netpbm programs is
+# not in the PATH and we were invoked by absolute path.
+
+my $my_directory = abs_path(dirname($0));
+$ENV{"PATH"} = $my_directory . ":" . $ENV{"PATH"};
+
+exec('pbmtoxbm', '-x10', $infileParm);
diff --git a/converter/pbm/pbmtox10bm.c b/converter/pbm/pbmtox10bm.c
deleted file mode 100644
index ef31fb9b..00000000
--- a/converter/pbm/pbmtox10bm.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/* pbmtox10bm.c - read a portable bitmap and produce an X10 bitmap file
-**
-** Copyright (C) 1988 by Jef Poskanzer.
-**
-** Permission to use, copy, modify, and distribute this software and its
-** documentation for any purpose and without fee is hereby granted, provided
-** that the above copyright notice appear in all copies and that both that
-** copyright notice and this permission notice appear in supporting
-** documentation.  This software is provided "as is" without express or
-** implied warranty.
-*/
-
-#include <string.h>
-
-#include "nstring.h"
-#include "pbm.h"
-
-int
-main(int argc, char * argv[]) {
-
-    FILE* ifp;
-    bit* bitrow;
-    bit * bP;
-    int rows, cols, format, padright, row;
-    int col;
-    char name[100];
-    char* cp;
-    int itemsperline;
-    int bitsperitem;
-    int item;
-    int firstitem;
-    const char* const hexchar = "0123456789abcdef";
-
-
-    pbm_init( &argc, argv );
-
-    if ( argc > 2 )
-        pm_usage( "[pbmfile]" );
-
-    if ( argc == 2 )
-	{
-        ifp = pm_openr( argv[1] );
-        strcpy( name, argv[1] );
-        if (STREQ( name, "-" ))
-            strcpy( name, "noname" );
-
-        if ( ( cp = strchr( name, '.' ) ) != 0 )
-            *cp = '\0';
-	}
-    else
-	{
-        ifp = stdin;
-        strcpy( name, "noname" );
-	}
-
-    pbm_readpbminit( ifp, &cols, &rows, &format );
-    bitrow = pbm_allocrow( cols );
-
-    /* Compute padding to round cols up to the nearest multiple of 16. */
-    padright = ( ( cols + 15 ) / 16 ) * 16 - cols;
-
-    printf( "#define %s_width %d\n", name, cols );
-    printf( "#define %s_height %d\n", name, rows );
-    printf( "static short %s_bits[] = {\n", name );
-
-    itemsperline = 0;
-    bitsperitem = 0;
-    item = 0;
-    firstitem = 1;
-
-#define PUTITEM \
-    { \
-        if ( firstitem ) \
-	        firstitem = 0; \
-        else \
-	        putchar( ',' ); \
-    if ( itemsperline == 11 ) \
-	{ \
-	    putchar( '\n' ); \
-	    itemsperline = 0; \
-	} \
-    if ( itemsperline == 0 ) \
-	    putchar( ' ' ); \
-    ++itemsperline; \
-    putchar('0'); \
-    putchar('x'); \
-    putchar(hexchar[item >> 12]); \
-    putchar(hexchar[(item >> 8) & 15]); \
-    putchar(hexchar[(item >> 4) & 15]); \
-    putchar(hexchar[item & 15]); \
-    bitsperitem = 0; \
-    item = 0; \
-    }
-
-#define PUTBIT(b) \
-    { \
-    if ( bitsperitem == 16 ) \
-	    PUTITEM; \
-    if ( (b) == PBM_BLACK ) \
-	    item += 1 << bitsperitem; \
-    ++bitsperitem; \
-    }
-
-    for ( row = 0; row < rows; ++row )
-	{
-        pbm_readpbmrow( ifp, bitrow, cols, format );
-        for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
-            PUTBIT(*bP);
-        for ( col = 0; col < padright; ++col )
-            PUTBIT(0);
-    }
-
-    pm_close( ifp );
-    
-    if ( bitsperitem > 0 )
-        PUTITEM;
-    printf( "};\n" );
-
-    return 0;
-}
diff --git a/converter/pbm/pbmtoxbm.c b/converter/pbm/pbmtoxbm.c
index 96830a0c..eb45f11b 100644
--- a/converter/pbm/pbmtoxbm.c
+++ b/converter/pbm/pbmtoxbm.c
@@ -1,4 +1,4 @@
-/* pbmtoxbm.c - read a portable bitmap and produce an X11 bitmap file
+/* pbmtoxbm.c - read a PBM image and produce an X11/X10 bitmap file
 **
 ** Copyright (C) 1988 by Jef Poskanzer.
 **
@@ -10,17 +10,113 @@
 ** implied warranty.
 */
 
+/* 2006.10 (afu)   
+   Changed bitrow from plain to raw, read function from pbm_readpbmrow() to
+   pbm_readpbmrow_packed().  Retired bitwise transformation functions.
+ 
+   Output function putitem rewritten to handle both X10 and X11.
+
+   Added -name option.  There is no check for the string thus given.
+
+*/
+
 #define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 
 #include <string.h>
 
 #include "pbm.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "bitreverse.h"
 #include "nstring.h"
 
 
+enum xbmVersion { X10, X11 };
+
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char *    inputFileName;
+    const char *    name;
+    enum xbmVersion xbmVersion;
+};
+
 static void
-generateName(char const filenameArg[], const char ** const nameP) {
+parseCommandLine(int                 argc, 
+                 char **             argv,
+                 struct cmdlineInfo *cmdlineP ) {
+/*----------------------------------------------------------------------------
+   Parse program command line described in Unix standard form by argc
+   and argv.  Return the information in the options as *cmdlineP.  
+
+   If command line is internally inconsistent (invalid options, etc.),
+   issue error message to stderr and abort program.
+
+   Note that the strings we return are stored in the storage that
+   was passed to us as the argv array.  We also trash *argv.
+-----------------------------------------------------------------------------*/
+    optEntry *option_def;
+    /* Instructions to optParseOptions3 on how to parse our options. */
+
+    optStruct3 opt;
+    unsigned int option_def_index;
+    unsigned int x10, x11, nameSpec;
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+
+    OPTENT3(0, "name", OPT_STRING, &cmdlineP->name, &nameSpec, 0);
+    OPTENT3(0, "x10" , OPT_FLAG,   NULL, &x10, 0);
+    OPTENT3(0, "x11" , OPT_FLAG,   NULL, &x11, 0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    optParseOptions3( &argc, argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (!nameSpec)
+        cmdlineP->name = NULL;
+    else if (strlen(cmdlineP->name) > 56)
+        pm_error("Image name too long: %d chars. (max 56)",
+                 strlen(cmdlineP->name));
+    else if (!ISALPHA(cmdlineP->name[0]) && cmdlineP->name[0] !='_')
+        pm_error("Image name '%s' starts with non-alphabet character.",
+                  cmdlineP->name);
+    else {
+        unsigned int i;
+        for (i = 0 ; i < strlen(cmdlineP->name); ++i)
+            if (!ISALNUM(cmdlineP->name[i]) && cmdlineP->name[i] != '_')
+                pm_error("Image name '%s' contains invalid character (%c).",
+                         cmdlineP->name, cmdlineP->name[i]);
+    }
+    
+    if (x10 && x11)
+        pm_error("You can't specify both -x10 and -x11");
+    else if (x10)
+        cmdlineP->xbmVersion = X10;
+    else 
+        cmdlineP->xbmVersion = X11;
+        
+    if (argc-1 < 1) 
+        cmdlineP->inputFileName = "-";
+    else {
+        cmdlineP->inputFileName = argv[1];
+        
+        if (argc-1 > 1)
+            pm_error("Program takes zero or one argument (filename).  You "
+                     "specified %u", argc-1);
+    }
+}
+
+
+
+static void
+generateName(char          const filenameArg[],
+             const char ** const nameP) {
 /*----------------------------------------------------------------------------
    Generate a name for the image to put in the bitmap file.  Derive it from
    the filename argument filenameArg[] and return it as a null-terminated
@@ -67,99 +163,235 @@ generateName(char const filenameArg[], const char ** const nameP) {
 
 
 
-int
-main(int argc, char * argv[]) {
+static unsigned short int itemBuff[22];
+static int itemCnt;    /* takes values 0 to 15 (x11) or 21 (x10) */
+static enum xbmVersion itemVersion;
 
-    FILE* ifp;
-    bit* bitrow;
-    int rows, cols, format;
-    int padright;
-    int row;
-    const char * inputFilename;
-    const char *name;
-    int itemsperline;
-    int bitsperitem;
-    int item;
-    int firstitem;
-    const char hexchar[] = "0123456789abcdef";
 
-    pbm_init(&argc, argv);
 
-    if (argc-1 > 1)
-        pm_error("Too many arguments (%d).  The only valid argument is an "
-                 "input file name.", argc-1);
-    else if (argc-1 == 1) 
-        inputFilename = argv[1];
-    else
-        inputFilename = "-";
+static void
+putitemX10(unsigned char const item) {
 
-    generateName(inputFilename, &name);
-    ifp = pm_openr(inputFilename);
-    
-    pbm_readpbminit(ifp, &cols, &rows, &format);
-    bitrow = pbm_allocrow(cols);
-    
-    /* Compute padding to round cols up to the nearest multiple of 8. */
-    padright = ((cols + 7)/8) * 8 - cols;
-
-    printf("#define %s_width %d\n", name, cols);
-    printf("#define %s_height %d\n", name, rows);
-    printf("static char %s_bits[] = {\n", name);
-
-    itemsperline = 0;
-    bitsperitem = 0;
-    item = 0;
-    firstitem = 1;
-
-#define PUTITEM \
-    { \
-    if ( firstitem ) \
-        firstitem = 0; \
-    else \
-        putchar( ',' ); \
-    if ( itemsperline == 15 ) \
-        { \
-        putchar( '\n' ); \
-        itemsperline = 0; \
-        } \
-    if ( itemsperline == 0 ) \
-        putchar( ' ' ); \
-    ++itemsperline; \
-    putchar('0'); \
-    putchar('x'); \
-    putchar(hexchar[item >> 4]); \
-    putchar(hexchar[item & 15]); \
-    bitsperitem = 0; \
-    item = 0; \
+    if (itemCnt == 22) {
+        /* Buffer is full.  Write out one line. */
+        int rc;
+        rc = printf(" 0x%02x%02x,0x%02x%02x,0x%02x%02x,0x%02x%02x,"
+                    "0x%02x%02x,0x%02x%02x,0x%02x%02x,0x%02x%02x,"
+                    "0x%02x%02x,0x%02x%02x,0x%02x%02x,\n",
+                    itemBuff[ 1], itemBuff[ 0], itemBuff[ 3], itemBuff[ 2],
+                    itemBuff[ 5], itemBuff[ 4], itemBuff[ 7], itemBuff[ 6],
+                    itemBuff[ 9], itemBuff[ 8], itemBuff[11], itemBuff[10],
+                    itemBuff[13], itemBuff[12], itemBuff[15], itemBuff[14],
+                    itemBuff[17], itemBuff[16], itemBuff[19], itemBuff[18],
+                    itemBuff[21], itemBuff[20]
+            );
+
+        if (rc < 0)        
+            pm_error("Error writing X10 bitmap raster item.  "
+                     "printf() failed with errno %d (%s)",
+                     errno, strerror(errno));
+        
+        itemCnt = 0;
     }
+    itemBuff[itemCnt++] = bitreverse[item];
+}
+
 
-#define PUTBIT(b) \
-    { \
-    if ( bitsperitem == 8 ) \
-        PUTITEM; \
-    if ( (b) == PBM_BLACK ) \
-        item += 1 << bitsperitem; \
-    ++bitsperitem; \
+
+static void
+putitemX11(unsigned char const item) {
+
+    if (itemCnt == 15 ) {
+        /* Buffer is full.  Write out one line. */
+        int rc;
+        rc = printf(" 0x%02x,0x%02x,0x%02x,0x%02x,"
+                    "0x%02x,0x%02x,0x%02x,0x%02x,"
+                    "0x%02x,0x%02x,0x%02x,0x%02x,"
+                    "0x%02x,0x%02x,0x%02x,\n",
+                    itemBuff[0], itemBuff[1], itemBuff[2], itemBuff[3],
+                    itemBuff[4], itemBuff[5], itemBuff[6], itemBuff[7],
+                    itemBuff[8], itemBuff[9], itemBuff[10],itemBuff[11],
+                    itemBuff[12],itemBuff[13],itemBuff[14]
+            );
+        if (rc < 0)        
+            pm_error("Error writing X11 bitmap raster item.  "
+                     "printf() failed with errno %d (%s)",
+                     errno, strerror(errno));
+        
+        itemCnt = 0;
     }
+    itemBuff[itemCnt++] = bitreverse[item];
+}
 
-    for (row = 0; row < rows; ++row) {
-        int col;
-        pbm_readpbmrow(ifp, bitrow, cols, format);
-        for (col = 0; col < cols; ++col)
-            PUTBIT(bitrow[col]);
-        for (col = 0; col < padright; ++col)
-            PUTBIT(0);
+
+
+static void
+putitem(unsigned char const item) {
+
+    switch (itemVersion) {
+    case X10: putitemX10(item); break;
+    case X11: putitemX11(item); break;
+    }
+}
+
+
+
+static void
+puttermX10(void) {
+
+    unsigned int i;
+
+    for (i = 0; i < itemCnt; i += 2) {
+        int rc;
+
+        rc = printf("%s0x%02x%02x%s",
+                    (i == 0) ? " " : "",
+                    itemBuff[i+1],
+                    itemBuff[i], 
+                    (i == itemCnt - 2) ? "};\n" : ",");
+        if (rc < 0)        
+            pm_error("Error writing end of X10 bitmap raster.  "
+                     "printf() failed with errno %d (%s)",
+                     errno, strerror(errno));
+    }
+}
+
+
+
+static void
+puttermX11(void) {
+
+    unsigned int i;
+
+    for (i = 0; i < itemCnt; ++i) {
+        int rc;
+
+        rc = printf("%s0x%02x%s",
+                    (i == 0)  ? " " : "",
+                    itemBuff[i],
+                    (i == itemCnt - 1) ? "};\n" : ",");
+
+        if (rc < 0)        
+            pm_error("Error writing end of X11 bitmap raster.  "
+                     "printf() failed with errno %d (%s)",
+                     errno, strerror(errno));
     }
+}
+
+
+
+static void
+putinit(enum xbmVersion const xbmVersion) {
+
+    itemCnt = 0;
+    itemVersion = xbmVersion;
+}
+
 
-    pm_close(ifp);
 
-    if (bitsperitem > 0)
-        PUTITEM;
-    printf("};\n");
+static void
+putterm(void) {
+
+    switch (itemVersion) {
+    case X10: puttermX10(); break;
+    case X11: puttermX11(); break;
+    }
+}
+
+
+
+static void
+writeXbmHeader(enum xbmVersion const xbmVersion,
+               const char *    const name,
+               unsigned int    const width,
+               unsigned int    const height,
+               FILE *          const ofP) {
+
+    printf("#define %s_width %d\n", name, width);
+    printf("#define %s_height %d\n", name, height);
+    printf("static %s %s_bits[] = {\n",
+           xbmVersion == X10 ? "short" : "char",
+           name);
+}
+
+
+
+static void
+convertRaster(FILE *          const ifP,
+              unsigned int    const cols,
+              unsigned int    const rows,
+              int             const format,
+              FILE *          const ofP,
+              enum xbmVersion const xbmVersion) {
+              
+    unsigned int const bitsPerUnit = xbmVersion == X10 ? 16 : 8;   
+    unsigned int const padright =
+        ((cols + bitsPerUnit - 1 ) / bitsPerUnit) * bitsPerUnit - cols;
+        /* Amount of padding to round cols up to the nearest multiple of 
+           8 (if x11) or 16 (if x10).
+        */
+    unsigned int const bitrowBytes = (cols + padright) / 8;
+
+    unsigned char * bitrow;
+    unsigned int row;
+
+    putinit(xbmVersion);
+
+    bitrow = pbm_allocrow_packed(cols + padright);
+    bitrow[bitrowBytes-1] = 0;
+    
+    for (row = 0; row < rows; ++row) {
+        int const bitrowInBytes = pbm_packed_bytes(cols);
+        int const padrightIn    = bitrowInBytes * 8 - cols;
+
+        unsigned int i;
+
+        pbm_readpbmrow_packed(ifP, bitrow, cols, format);
+
+        if (padrightIn > 0) {
+            bitrow[bitrowInBytes - 1] >>= padrightIn;
+            bitrow[bitrowInBytes - 1] <<= padrightIn;
+        }
+
+        for (i = 0; i < bitrowBytes; ++i)
+            putitem(bitrow[i]);
+    }
+
+    putterm();
 
     pbm_freerow(bitrow);
+}
+
+
+
+int
+main(int    argc,
+     char * argv[]) {
+
+    struct cmdlineInfo cmdline; 
+    FILE * ifP;
+    int rows, cols, format;
+    const char * name;
+
+    pbm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+    if (cmdline.name == NULL) 
+        generateName(cmdline.inputFileName, &name);
+    else
+        name = strdup(cmdline.name);
+
+    ifP = pm_openr(cmdline.inputFileName);
+    
+    pbm_readpbminit(ifP, &cols, &rows, &format);
+    
+    writeXbmHeader(cmdline.xbmVersion, name, cols, rows, stdout);
+
+    convertRaster(ifP, cols, rows, format, stdout, cmdline.xbmVersion);
 
     strfree(name);
+    pm_close(ifP);
 
-    exit(0);
+    return 0;
 }
+
diff --git a/converter/pbm/pbmtoybm.c b/converter/pbm/pbmtoybm.c
index 1d2be3d9..508e8e92 100644
--- a/converter/pbm/pbmtoybm.c
+++ b/converter/pbm/pbmtoybm.c
@@ -80,14 +80,8 @@ putinit( cols, rows )
     bitshift = 0;
     }
 
-#if __STDC__
 static void
 putbit( bit b )
-#else /*__STDC__*/
-static void
-putbit( b )
-    bit b;
-#endif /*__STDC__*/
     {
     if ( bitsperitem == 16 )
 	putitem( );
diff --git a/converter/pbm/xbmtopbm.c b/converter/pbm/xbmtopbm.c
index 7779a9b5..63be16ef 100644
--- a/converter/pbm/xbmtopbm.c
+++ b/converter/pbm/xbmtopbm.c
@@ -1,4 +1,4 @@
-/* xbmtopbm.c - read an X bitmap file and produce a portable bitmap
+/* xbmtopbm.c - read an X bitmap file and produce a PBM image
 **
 ** Copyright (C) 1988 by Jef Poskanzer.
 **
@@ -10,246 +10,381 @@
 ** implied warranty.
 */
 
+
+#include <assert.h>
 #include <string.h>
 
+#include "pm_c_util.h"
+#include "mallocvar.h"
 #include "nstring.h"
 #include "pbm.h"
+#include "bitreverse.h"
 
-#define TRUE 1
-#define FALSE 0
 
-static void ReadBitmapFile ARGS(( FILE* stream, int* widthP, int* heightP, char** dataP ));
 
-int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    bit* bitrow;
-    register bit* bP;
-    int rows, cols, row, col, charcount;
-    char* data;
-    char mask;
-
-    pbm_init( &argc, argv );
-
-    if ( argc > 2 )
-        pm_usage( "[bitmapfile]" );
-    
-    if ( argc == 2 )
-        ifp = pm_openr( argv[1] );
-    else
-        ifp = stdin;
-
-    ReadBitmapFile( ifp, &cols, &rows, &data );
-
-    pm_close( ifp );
-
-    pbm_writepbminit( stdout, cols, rows, 0 );
-    bitrow = pbm_allocrow( cols );
-
-    for ( row = 0; row < rows; ++row )
-        {
-        charcount = 0;
-        mask = 1;
-        for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
-            {
-            if ( charcount >= 8 )
-                {
-                ++data;
-                charcount = 0;
-                mask = 1;
-                }
-            *bP = ( *data & mask ) ? PBM_BLACK : PBM_WHITE;
-            ++charcount;
-            mask = mask << 1;
-            }
-        ++data;
-        pbm_writepbmrow( stdout, bitrow, cols, 0 );
-        }
+#define MAX_LINE 500
+
+static unsigned int hexTable[256];
+    /* Hexadecimal ASCII translation table.  Constant */
+
+static void
+initHexTable(void) {
+
+    unsigned int i;
+
+    for (i = 0; i < 256; ++i)
+        hexTable[i] = 256;
+
+    hexTable['0'] =  0;
+    hexTable['1'] =  1;
+    hexTable['2'] =  2;
+    hexTable['3'] =  3;
+    hexTable['4'] =  4;
+    hexTable['5'] =  5;
+    hexTable['6'] =  6;
+    hexTable['7'] =  7;
+    hexTable['8'] =  8;
+    hexTable['9'] =  9;
+    hexTable['A'] = 10;
+    hexTable['B'] = 11;
+    hexTable['C'] = 12;
+    hexTable['D'] = 13;
+    hexTable['E'] = 14;
+    hexTable['F'] = 15;
+    hexTable['a'] = 10;
+    hexTable['b'] = 11;
+    hexTable['c'] = 12;
+    hexTable['d'] = 13;
+    hexTable['e'] = 14;
+    hexTable['f'] = 15;
+}
 
-    pm_close( stdout );
-    exit( 0 );
-    }
 
-#define MAX_LINE 500
 
 static void
-ReadBitmapFile( stream, widthP, heightP, dataP )
-     FILE* stream;
-     int* widthP;
-     int* heightP;
-     char** dataP;
-{
-  char line[MAX_LINE], name_and_type[MAX_LINE];
-  char* ptr;
-  char* t;
-  int version10, raster_length, v;
-  register int bytes, bytes_per_line, padding;
-  register int c1, c2, value1, value2;
-  int hex_table[256];
-  int found_declaration;
-  /* In scanning through the bitmap file, we have found the first
-     line of the C declaration of the array (the "static char ..."
-     or whatever line)
-     */
-  int eof;
-  /* We've encountered end of file while searching file */
-
-  *widthP = *heightP = -1;
-
-  found_declaration = FALSE;    /* Haven't found it yet; haven't even looked*/
-  eof = FALSE;                  /* Haven't encountered end of file yet */
-
-  while (!found_declaration && !eof) {
-    if ( fgets( line, MAX_LINE, stream ) == NULL )
-      eof = TRUE;
-    else {
-      if ( strlen( line ) == MAX_LINE - 1 )
-        pm_error( "line too long" );
-
-      if ( sscanf( line, "#define %s %d", name_and_type, &v ) == 2 ) {
-        if ( ( t = strrchr( name_and_type, '_' ) ) == NULL )
-          t = name_and_type;
+parseWidthHeightLine(const char *   const line,
+                     bool *         const gotWidthP,
+                     unsigned int * const widthP,
+                     bool *         const gotHeightP,
+                     unsigned int * const heightP) {
+
+    int rc;
+    char nameAndType[MAX_LINE];
+    unsigned int value;
+
+    rc = sscanf(line, "#define %s %u", nameAndType, &value);
+    if (rc == 2) {
+        const char * underscorePos = strrchr(nameAndType, '_');
+        const char * type;
+        if (underscorePos)
+            type = underscorePos + 1;
         else
-          ++t;
-        if ( STREQ( "width", t ) )
-          *widthP = v;
-        else if ( STREQ( "height", t ) )
-          *heightP = v;
-        continue;
-      }
+            type = nameAndType;
+        if (STREQ(type, "width")) {
+            *gotWidthP = TRUE;
+            *widthP = value;
+        } else if (STREQ(type, "height")) {
+            *gotHeightP = TRUE;
+            *heightP = value;
+        }
+    }
+}
+
+
+
+static void
+parseDeclaration(const char * const line,
+                 bool *       const isDeclarationP,
+                 bool *       const version10P) {
+/*----------------------------------------------------------------------------
+   Parse the XBM file line 'line' as the first line of the data structure
+   declaration, i.e. the one that looks like this:
+
+      static unsigned char myImage = {
+
+   Return as *isDeclarationP whether the line actually is such a line,
+   and if so, return as nameAndType what the variable name ('myImage'
+   in the example) is and as *version10P whether it's of the type used
+   by X10 as opposed to X11.
+-----------------------------------------------------------------------------*/
+    char nameAndType[MAX_LINE];
+    int rc;
         
-      if ( sscanf( line, "static short %s = {", name_and_type ) == 1 ) {
-        version10 = TRUE;
-        found_declaration = TRUE;
-      }
-      else if ( sscanf( line, "static char %s = {", name_and_type ) == 1 ) {
-        version10 = FALSE;
-        found_declaration = TRUE;
-      }
-      else if (sscanf(line, 
-                      "static unsigned char %s = {", name_and_type ) == 1 ) {
-        version10 = FALSE;
-        found_declaration = TRUE;
-      }
+    rc = sscanf(line, "static short %s = {", nameAndType);
+    if (rc == 1) {
+        *version10P     = TRUE;
+        *isDeclarationP = TRUE;
+    } else {
+        int rc;
+        rc = sscanf(line, "static char %s = {", nameAndType);
+        if (rc == 1) {
+            *version10P     = FALSE;
+            *isDeclarationP = TRUE;
+        } else {
+            int rc;
+            rc = sscanf(line, "static unsigned char %s = {", nameAndType);
+            if (rc == 1) {
+                *version10P     = FALSE;
+                *isDeclarationP = TRUE;
+            } else
+                *isDeclarationP = FALSE;
+        }
     }
-  }
- 
-  if (!found_declaration) 
-    pm_error("Unable to find a line in the file containing the start "
-             "of C array declaration (\"static char\" or whatever)");
-
-  if ( *widthP == -1 )
-    pm_error( "invalid width" );
-  if ( *heightP == -1 )
-    pm_error( "invalid height" );
-
-  padding = 0;
-  if ( ((*widthP % 16) >= 1) && ((*widthP % 16) <= 8) && version10 )
-    padding = 1;
-
-  bytes_per_line = (*widthP+7)/8 + padding;
+}
+
+
+
+static void
+getXbmHeader(FILE *         const ifP,
+             unsigned int * const widthP,
+             unsigned int * const heightP,
+             bool *         const version10P) {
+
+    bool foundDeclaration;
+        /* In scanning through the bitmap file, we have found the first
+           line of the C declaration of the array (the "static char ..."
+           or whatever line)
+        */
+    bool gotWidth, gotHeight;
+        /* We found the line in the bitmap file that gives the width
+           or height, respectively, of the image (and have set
+           *widthP or *heightP to the value in it).
+        */
+
+    bool eof;
+        /* We've encountered end of file while searching file */
+
+    gotWidth = FALSE;
+    gotHeight = FALSE;
+    foundDeclaration = FALSE;    /* Haven't found it yet; haven't even looked*/
+    eof = FALSE;                 /* Haven't encountered end of file yet */
+
+    while (!foundDeclaration && !eof) {
+        char * rc;
+        char line[MAX_LINE];
+
+        rc = fgets(line, MAX_LINE, ifP);
+        if (rc == NULL)
+            eof = TRUE;
+        else {
+            if (strlen(line) == MAX_LINE - 1)
+                pm_error("A line in the input file is %u characters long.  "
+                         "%u is the maximum we can handle",
+                         strlen(line), MAX_LINE-1);
+
+            parseWidthHeightLine(line, &gotWidth, widthP, &gotHeight, heightP);
+
+            parseDeclaration(line, &foundDeclaration, version10P);
+        }
+    }
+
+    if (!foundDeclaration) 
+        pm_error("Unable to find a line in the file containing the start "
+                 "of C array declaration (\"static char\" or whatever)");
+
+    if (!gotWidth)
+        pm_error("Unable to find the #define statement that gives the "
+                 "width of the image, before the data structure "
+                 "declaration.");
+    if (!gotHeight)
+        pm_error("Unable to find the #define statement that gives the "
+                 "height of the image, before the data structure "
+                 "declaration.");
+}
+
+
+
+static void
+getHexByte(FILE *         const ifP,
+           unsigned int * const valueP) {
+
+    int c1, c2;
+    unsigned int value;
+
+    c1 = getc(ifP);
+    c2 = getc(ifP);
+    if (c1 == EOF || c2 == EOF)
+        pm_error("EOF / read error");
+
+    assert(c1 >= 0); assert(c1 < 256);
+    assert(c2 >= 0); assert(c2 < 256);
     
-  raster_length =  bytes_per_line * *heightP;
-  *dataP = (char*) malloc( raster_length );
-  if ( *dataP == (char*) 0 )
-    pm_error( "out of memory" );
-
-  /* Initialize hex_table. */
-  for ( c1 = 0; c1 < 256; ++c1 )
-    hex_table[c1] = 256;
-  hex_table['0'] = 0;
-  hex_table['1'] = 1;
-  hex_table['2'] = 2;
-  hex_table['3'] = 3;
-  hex_table['4'] = 4;
-  hex_table['5'] = 5;
-  hex_table['6'] = 6;
-  hex_table['7'] = 7;
-  hex_table['8'] = 8;
-  hex_table['9'] = 9;
-  hex_table['A'] = 10;
-  hex_table['B'] = 11;
-  hex_table['C'] = 12;
-  hex_table['D'] = 13;
-  hex_table['E'] = 14;
-  hex_table['F'] = 15;
-  hex_table['a'] = 10;
-  hex_table['b'] = 11;
-  hex_table['c'] = 12;
-  hex_table['d'] = 13;
-  hex_table['e'] = 14;
-  hex_table['f'] = 15;
-
-  if ( version10 )
-    for ( bytes = 0, ptr = *dataP; bytes < raster_length; bytes += 2 ) {
-      while ( ( c1 = getc( stream ) ) != 'x' )
-        if ( c1 == EOF )
-          pm_error( "EOF / read error" );
-      c1 = getc( stream );
-      c2 = getc( stream );
-      if ( c1 == EOF || c2 == EOF )
-        pm_error( "EOF / read error" );
-      value1 = ( hex_table[c1] << 4 ) + hex_table[c2];
-      if ( value1 >= 256 )
-        pm_error( "syntax error" );
-      c1 = getc( stream );
-      c2 = getc( stream );
-      if ( c1 == EOF || c2 == EOF )
-        pm_error( "EOF / read error" );
-      value2 = ( hex_table[c1] << 4 ) + hex_table[c2];
-      if ( value2 >= 256 )
-        pm_error( "syntax error" );
-      *ptr++ = value2;
-      if ( ( ! padding ) || ( ( bytes + 2 ) % bytes_per_line ) )
-        *ptr++ = value1;
+    value = (hexTable[c1] << 4) + hexTable[c2];
+    if (value >= 256)
+        pm_error("Invalid XBM input.  What should be a two digit "
+                 "hexadecimal cipher is instead '%c%c'", c1, c2);
+
+    *valueP = value;
+}
+
+
+                     
+static void
+readX10Raster(FILE *          const ifP,
+              unsigned int    const rasterLength,
+              unsigned char * const data,
+              unsigned int    const bytesPerLine,
+              bool            const mustPad) {
+
+    unsigned int bytesDone;
+    unsigned char * p;
+
+    for (bytesDone = 0, p = &data[0];
+         bytesDone < rasterLength;
+         bytesDone += 2) {
+
+        unsigned int value1;
+        unsigned int value2;
+
+        while (getc(ifP) != 'x') {}  /* Read up through the 'x' in 0x1234 */
+
+        getHexByte(ifP, &value1);  /* Read first two hex digits */
+        getHexByte(ifP, &value2);  /* Read last two hex digits */
+
+        *p++ = value2;
+
+        if (!mustPad || ((bytesDone + 2) % bytesPerLine))
+            *p++ = value1;
     }
-  else
-    for ( bytes = 0, ptr = *dataP; bytes < raster_length; ++bytes ) {
-      /*
-       ** Skip until digit is found.
-       */
-      for ( ; ; )
-        {
-          c1 = getc( stream );
-          if ( c1 == EOF )
-            pm_error( "EOF / read error" );
-          value1 = hex_table[c1];
-          if ( value1 != 256 )
-            break;
-        }
-      /*
-       ** Loop on digits.
-       */
-      for ( ; ; ) {
-        c2 = getc( stream );
-        if ( c2 == EOF )
-          pm_error( "EOF / read error" );
-        value2 = hex_table[c2];
-        if ( value2 != 256 ) {
-          value1 = (value1 << 4) | value2;
-          if ( value1 >= 256 )
-            pm_error( "syntax error" );
+}
+
+
+
+static void
+readX11Raster(FILE * const ifP,
+              unsigned int const rasterLength,
+              unsigned char * data) {
+
+    unsigned int i;
+
+    for (i = 0; i < rasterLength; ++i) {
+        unsigned int value;
+        int c;
+
+        /* Read up through the 'x' in 0x12 */
+        while ((c = getc(ifP))) {
+            if (c == EOF)
+                pm_error("EOF where 0x expected");
+            else if (toupper(c) == 'X')
+                break;
         }
-        else if ( c2 == 'x' || c2 == 'X' )
-          if ( value1 == 0 )
-            continue;
-          else pm_error( "syntax error" );
-        else break;
-      }
-      *ptr++ = value1;
+
+        getHexByte(ifP, &value);  /* Read the two hex digits */
+
+        assert(value < 256);
+
+        data[i] = value;
     }
 }
 
 
-/*  CHANGE HISTORY:
 
-  99.09.08 bryanh    Recognize "static unsigned char" declaration.
+static void
+readBitmapFile(FILE *           const ifP,
+               unsigned int *   const widthP,
+               unsigned int *   const heightP,
+               unsigned char ** const dataP) {
+
+    bool version10;
+    unsigned int rasterLength;
+    unsigned int width, height;
+    unsigned char * data;
 
+    unsigned int bytesPerLine;
+    bool mustPad;
 
+    getXbmHeader(ifP, &width, &height, &version10);
 
+    *widthP = width;
+    *heightP = height;
 
+    mustPad = (width % 16 >= 1 && width % 16 <= 8 && version10);
+
+    bytesPerLine = (width + 7) / 8 + (mustPad ? 1 : 0);
+    
+    rasterLength = bytesPerLine * height;
+
+    MALLOCARRAY(data, rasterLength);
+    if (data == NULL)
+        pm_error("Unable to allocate memory for the %u-byte raster",
+                 rasterLength);
+
+    if (version10)
+        readX10Raster(ifP, rasterLength, data, bytesPerLine, mustPad);
+    else
+        readX11Raster(ifP, rasterLength, data);
+
+    *dataP = data;
+}
+
+
+
+int
+main(int    argc,
+     char * argv[]) {
+
+    FILE * ifP;
+    bit * bitrow;
+    unsigned int rows, cols;
+    unsigned int row;
+    unsigned char * data;
+    const char * inputFileName;
+    unsigned char * p;
+        /* Cursor in raster data data[] */
+    
+    initHexTable();
+
+    pbm_init(&argc, argv);
+
+    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
+        inputFileName = "-";
+
+    ifP = pm_openr(inputFileName);
+
+    readBitmapFile(ifP, &cols, &rows, &data);
+
+    pm_close(ifP);
+
+    pbm_writepbminit(stdout, cols, rows, 0);
+    bitrow = pbm_allocrow_packed(cols);
+
+    p = &data[0];  /* Start at beginning of raster */
+
+    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++];
+            
+        if (cols % 8 > 0) {
+            bitrow[bytesPerRow] >>= 8 - cols % 8;
+            bitrow[bytesPerRow] <<= 8 - cols % 8;
+        }
+            
+        pbm_writepbmrow_packed(stdout, bitrow, cols, 0);
+    }
+
+    free(data);
+    pm_close(stdout);
+
+    return 0;
+}
+
+/*  CHANGE HISTORY:
+
+  99.09.08 bryanh    Recognize "static unsigned char" declaration.
+
+  06.10 (afu)
+   Changed bitrow from plain to raw, write function from pbm_writepbmrow()
+   to pbm_writepbmrow_packed().
+   Retired bitwise transformation functions.
 
 */
+
diff --git a/converter/pgm/pgmtofs.c b/converter/pgm/pgmtofs.c
index b34d77c4..53a2e7b3 100644
--- a/converter/pgm/pgmtofs.c
+++ b/converter/pgm/pgmtofs.c
@@ -128,14 +128,8 @@ putitem( )
     bitshift = 8 - bitspersample;
 }
 
-#if __STDC__
 static void
 putgray( gray g )
-#else /*__STDC__*/
-    static void
-putgray( g )
-    gray g;
-#endif /*__STDC__*/
 {
     if ( bitsperitem == 8 )
         putitem( );
diff --git a/converter/pgm/pgmtolispm.c b/converter/pgm/pgmtolispm.c
index 02f2fd1e..abb85494 100644
--- a/converter/pgm/pgmtolispm.c
+++ b/converter/pgm/pgmtolispm.c
@@ -115,14 +115,8 @@ depth_to_word_size (depth)	/* Lispm architecture specific - if a bitmap is writt
 
 
 
-#if __STDC__
 static void
 putval( gray b )
-#else /*__STDC__*/
-static void
-putval( b )
-gray b;
-#endif /*__STDC__*/
     {
     if ( bitsperitem == 32 )
 	putitem( );
diff --git a/converter/ppm/ppmtogif.c b/converter/ppm/ppmtogif.c
index 3100fea1..2b8a2596 100644
--- a/converter/ppm/ppmtogif.c
+++ b/converter/ppm/ppmtogif.c
@@ -1,101 +1,56 @@
-/* ppmtogif.c - read a portable pixmap and produce a GIF file
-**
-** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>.A
-** Lempel-Zim compression based on "compress".
-**
-** Modified by Marcel Wijkstra <wijkstra@fwi.uva.nl>
-**
-** The non-LZW GIF generation stuff was adapted from the Independent
-** JPEG Group's djpeg on 2001.09.29.  The uncompressed output subroutines
-** are derived directly from the corresponding subroutines in djpeg's
-** wrgif.c source file.  Its copyright notice say:
-
- * Copyright (C) 1991-1997, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
-   The reference README file is README.JPEG in the Netpbm package.
-**
-** Copyright (C) 1989 by Jef Poskanzer.
-**
-** Permission to use, copy, modify, and distribute this software and its
-** documentation for any purpose and without fee is hereby granted, provided
-** that the above copyright notice appear in all copies and that both that
-** copyright notice and this permission notice appear in supporting
-** documentation.  This software is provided "as is" without express or
-** implied warranty.
-**
-** The Graphics Interchange Format(c) is the Copyright property of
-** CompuServe Incorporated.  GIF(sm) is a Service Mark property of
-** CompuServe Incorporated.
-*/
+/* This is a backward compatibility interface to Pamtogif.
+
+   Pamtogif replaced Ppmtogif in Netpbm 10.37 (December 2006).
 
-/* TODO: merge the LZW and uncompressed subroutines.  They are separate
-   only because they had two different lineages and the code is too
-   complicated for me quickly to rewrite it.
+   The only significant way Pamtogif is not backward compatible with
+   old Ppmtogif is that Pamtogif does not have a -alpha option.
 */
-#include <assert.h>
+#define _BSD_SOURCE   /* Make sure strdup() is in string.h */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+
 #include <string.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
 #include "mallocvar.h"
 #include "shhopt.h"
-#include "ppm.h"
+#include "nstring.h"
+#include "pam.h"
 
-#define MAXCMAPSIZE 256
 
-static unsigned int const gifMaxval = 255;
 
-static bool verbose;
-/*
- * a code_int must be able to hold 2**BITS values of type int, and also -1
- */
-typedef int code_int;
+static const char *
+dirname(const char * const fileName) {
 
-typedef long int          count_int;
+    char * buffer;
+    char * slashPos;
 
+    buffer = strdup(fileName);
+
+    slashPos = strchr(buffer, '/');
+
+    if (slashPos)
+        *slashPos = '\0';
+
+    return buffer;
+}
 
-struct cmap {
-    /* This is the information for the GIF colormap (aka palette). */
 
-    int red[MAXCMAPSIZE], green[MAXCMAPSIZE], blue[MAXCMAPSIZE];
-        /* These arrays arrays map a color index, as is found in
-           the raster part of the GIF, to an intensity value for the indicated
-           RGB component.
-        */
-    int perm[MAXCMAPSIZE], permi[MAXCMAPSIZE];
-        /* perm[i] is the position in the sorted colormap of the color which
-           is at position i in the unsorted colormap.  permi[] is the inverse
-           function of perm[].
-        */
-    int cmapsize;
-        /* Number of entries in the GIF colormap.  I.e. number of colors
-           in the image, plus possibly one fake transparency color.
-        */
-    int transparent;
-        /* color index number in GIF palette of the color that is to be
-           transparent.  -1 if no color is transparent.
-        */
-    colorhash_table cht;
-        /* A hash table that relates a PPM pixel value to to a pre-sort
-           GIF colormap index.
-        */
-    pixval maxval;
-        /* The maxval for the colors in 'cht'. */
-};
 
 struct cmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    const char *input_filespec;  /* Filespec of input file */
-    const char *alpha_filespec;  /* Filespec of alpha file; NULL if none */
-    const char *alphacolor;      /* -alphacolor option value or default */
-    unsigned int interlace; /* -interlace option value */
-    unsigned int sort;     /* -sort option value */
+    const char *input_filespec; /* Filespec of input file */
+    const char *alpha_filespec; /* Filespec of alpha file; NULL if none */
+    const char *alphacolor;     /* -alphacolor option value or default */
+    unsigned int interlace;     /* -interlace option value */
+    unsigned int sort;          /* -sort option value */
     const char *mapfile;        /* -mapfile option value.  NULL if none. */
     const char *transparent;    /* -transparent option value.  NULL if none. */
     const char *comment;        /* -comment option value; NULL if none */
-    unsigned int nolzw;    /* -nolzw option */
+    unsigned int nolzw;         /* -nolzw option */
     unsigned int verbose;
 };
 
@@ -122,8 +77,8 @@ handleLatex2htmlHack(void) {
   -Bryan 2001.11.14
 -----------------------------------------------------------------------------*/
      pm_error("latex2html, you should just try the -interlace and "
-             "-transparent options to see if they work instead of "
-             "expecting a 'usage' message from -h");
+              "-transparent options to see if they work instead of "
+              "expecting a 'usage' message from -h");
 }
 
 
@@ -204,1354 +159,223 @@ parseCommandLine(int argc, char ** argv,
 
 
 
-/*
- * Write out a word to the GIF file
- */
-static void
-Putword(int const w, FILE * const fp) {
-
-    fputc( w & 0xff, fp );
-    fputc( (w / 256) & 0xff, fp );
-}
-
-
-static int
-closestcolor(pixel         const color,
-             pixval        const maxval,
-             struct cmap * const cmapP) {
-/*----------------------------------------------------------------------------
-   Return the pre-sort colormap index of the color in the colormap *cmapP
-   that is closest to the color 'color', whose maxval is 'maxval'.
-
-   Also add 'color' to the colormap hash, with the colormap index we
-   are returning.  Caller must ensure that the color is not already in
-   there.
------------------------------------------------------------------------------*/
-    unsigned int i;
-    unsigned int imin, dmin;
-
-    pixval const r = PPM_GETR(color) * gifMaxval / maxval;
-    pixval const g = PPM_GETG(color) * gifMaxval / maxval;
-    pixval const b = PPM_GETB(color) * gifMaxval / maxval;
-
-    dmin = SQR(255) * 3;
-    imin = 0;
-    for (i=0;i < cmapP->cmapsize; i++) {
-        int const d = SQR(r-cmapP->red[i]) + 
-            SQR(g-cmapP->green[i]) + 
-            SQR(b-cmapP->blue[i]);
-        if (d < dmin) {
-            dmin = d;
-            imin = i; 
-        } 
-    }
-    ppm_addtocolorhash(cmapP->cht, &color, cmapP->permi[imin]);
-
-    return cmapP->permi[imin];
-}
-
-
-
-enum pass {MULT8PLUS0, MULT8PLUS4, MULT4PLUS2, MULT2PLUS1};
-
-
-struct pixelCursor {
-    unsigned int width;
-        /* Width of the image, in columns */
-    unsigned int height;
-        /* Height of the image, in rows */
-    bool interlace;
-        /* We're accessing the image in interlace fashion */
-    unsigned int nPixelsLeft;
-        /* Number of pixels left to be read */
-    unsigned int curCol;
-        /* Location of pointed-to pixel, column */
-    unsigned int curRow;
-        /* Location of pointed-to pixel, row */
-    enum pass pass;
-        /* The interlace pass.  Undefined if !interlace */
-};
+static const char *
+pamtogifCommand(const char *       const arg0,
+                struct cmdlineInfo const cmdline) {
 
+    const char * const pamtogifName = "pamtogif";
 
+    const char * retval;
 
-static struct pixelCursor pixelCursor;
-    /* Current location in the input pixels.  */
+    const char * commandVerb;
+    const char * mapfileOpt;
+    const char * transparentOpt;
+    const char * commentOpt;
 
+    if (strchr(arg0, '/')) {
+        const char * const arg0DirName = dirname(arg0);
+        const char * progName;
 
-static void
-initPixelCursor(unsigned int const width,
-                unsigned int const height,
-                bool         const interlace) {
-
-    pixelCursor.width       = width;
-    pixelCursor.height      = height;
-    pixelCursor.interlace   = interlace;
-    pixelCursor.pass        = MULT8PLUS0;
-    pixelCursor.curCol      = 0;
-    pixelCursor.curRow      = 0;
-    pixelCursor.nPixelsLeft = width * height;
-}
+        struct stat statbuf;
 
+        asprintfN(&progName, "%s/%s", arg0DirName, pamtogifName);
 
-
-static void
-getPixel(pixel **           const pixels,
-         pixval             const inputMaxval,
-         gray **            const alpha,
-         gray               const alphaThreshold, 
-         struct cmap *      const cmapP,
-         struct pixelCursor const pixelCursor,
-         int *              const retvalP) {
-/*----------------------------------------------------------------------------
-   Return as *retvalP the colormap index of the pixel at location
-   pointed to by 'pixelCursor' in the PPM raster 'pixels', using
-   colormap *cmapP.
------------------------------------------------------------------------------*/
-    unsigned int const x = pixelCursor.curCol;
-    unsigned int const y = pixelCursor.curRow;
-
-    int colorindex;
-
-    if (alpha && alpha[y][x] < alphaThreshold)
-        colorindex = cmapP->transparent;
-    else {
-        int presortColorindex;
-
-        presortColorindex = ppm_lookupcolor(cmapP->cht, &pixels[y][x]);
-        if (presortColorindex == -1)
-            presortColorindex = 
-                closestcolor(pixels[y][x], inputMaxval, cmapP);
-        colorindex = cmapP->perm[presortColorindex];
-    }
-    *retvalP = colorindex;
-}
-
-
-
-static void
-bumpRowInterlace(struct pixelCursor * const pixelCursorP) {
-/*----------------------------------------------------------------------------
-   Move *pixelCursorP to the next row in the interlace pattern.
------------------------------------------------------------------------------*/
-    /* There are 4 passes:
-       MULT8PLUS0: Rows 8, 16, 24, 32, etc.
-       MULT8PLUS4: Rows 4, 12, 20, 28, etc.
-       MULT4PLUS2: Rows 2, 6, 10, 14, etc.
-       MULT2PLUS1: Rows 1, 3, 5, 7, 9, etc.
-    */
-    
-    switch (pixelCursorP->pass) {
-    case MULT8PLUS0:
-        pixelCursorP->curRow += 8;
-        break;
-    case MULT8PLUS4:
-        pixelCursorP->curRow += 8;
-        break;
-    case MULT4PLUS2:
-        pixelCursorP->curRow += 4;
-        break;
-    case MULT2PLUS1:
-        pixelCursorP->curRow += 2;
-        break;
-    }
-    /* Set the proper pass for the next read.  Note that if there are
-       more than 4 rows, the sequence of passes is sequential, but
-       when there are fewer than 4, we may skip e.g. from MULT8PLUS0
-       to MULT4PLUS2.
-    */
-    while (pixelCursorP->curRow >= pixelCursorP->height) {
-        switch (pixelCursorP->pass) {
-        case MULT8PLUS0:
-            pixelCursorP->pass = MULT8PLUS4;
-            pixelCursorP->curRow = 4;
-            break;
-        case MULT8PLUS4:
-            pixelCursorP->pass = MULT4PLUS2;
-            pixelCursorP->curRow = 2;
-            break;
-        case MULT4PLUS2:
-            pixelCursorP->pass = MULT2PLUS1;
-            pixelCursorP->curRow = 1;
-            break;
-        case MULT2PLUS1:
-            /* We've read the entire image; pass and current row are
-               now undefined.
-            */
-            pixelCursorP->curRow = 0;
-            break;
-        }
-    }
-}
-
-
-
-static void
-bumpPixel(struct pixelCursor * const pixelCursorP) {
-/*----------------------------------------------------------------------------
-   Bump *pixelCursorP to point to the next pixel to go into the GIF
-
-   Must not call when there are no pixels left.
------------------------------------------------------------------------------*/
-    assert(pixelCursorP->nPixelsLeft > 0);
-
-    /* Move one column to the right */
-    ++pixelCursorP->curCol;
-    
-    if (pixelCursorP->curCol >= pixelCursorP->width) {
-        /* That pushed us past the end of a row. */
-        /* Reset to the left edge ... */
-        pixelCursorP->curCol = 0;
-        
-        /* ... of the next row */
-        if (!pixelCursorP->interlace)
-            /* Go to the following row */
-            ++pixelCursorP->curRow;
+        if (stat(progName, &statbuf) == 0)
+            commandVerb = progName;
         else
-            bumpRowInterlace(pixelCursorP);
-    }
-    --pixelCursorP->nPixelsLeft;
-}
-
-
-
-static int
-gifNextPixel(pixel **      const pixels,
-             pixval        const inputMaxval,
-             gray **       const alpha,
-             gray          const alphaThreshold, 
-             struct cmap * const cmapP) {
-/*----------------------------------------------------------------------------
-   Return the pre-sort color index (index into the unsorted GIF color map)
-   of the next pixel to be processed from the input image.
-
-   'alpha_threshold' is the gray level such that a pixel in the alpha
-   map whose value is less that that represents a transparent pixel
-   in the output.
------------------------------------------------------------------------------*/
-    int retval;
-
-    if (pixelCursor.nPixelsLeft == 0 )
-        retval = EOF;
-    else {
-        getPixel(pixels, inputMaxval, alpha, alphaThreshold, cmapP, 
-                 pixelCursor, &retval);
-
-        bumpPixel(&pixelCursor);
-    }
-    return retval;
-}
-
-
-
-static void
-write_transparent_color_index_extension(FILE *fp, const int Transparent) {
-/*----------------------------------------------------------------------------
-   Write out extension for transparent color index.
------------------------------------------------------------------------------*/
-
-    fputc( '!', fp );
-    fputc( 0xf9, fp );
-    fputc( 4, fp );
-    fputc( 1, fp );
-    fputc( 0, fp );
-    fputc( 0, fp );
-    fputc( Transparent, fp );
-    fputc( 0, fp );
-}
-
-
-
-static void
-write_comment_extension(FILE *fp, const char comment[]) {
-/*----------------------------------------------------------------------------
-   Write out extension for a comment
------------------------------------------------------------------------------*/
-    char *segment;
-    
-    fputc('!', fp);   /* Identifies an extension */
-    fputc(0xfe, fp);  /* Identifies a comment */
-
-    /* Write it out in segments no longer than 255 characters */
-    for (segment = (char *) comment; 
-         segment < comment+strlen(comment); 
-         segment += 255) {
-
-        const int length_this_segment = MIN(255, strlen(segment));
-
-        fputc(length_this_segment, fp);
-
-        fwrite(segment, 1, length_this_segment, fp);
-    }
-
-    fputc(0, fp);   /* No more comment blocks in this extension */
-}
-
-
-
-/***************************************************************************
- *
- *  GIFCOMPR.C       - GIF Image compression routines
- *
- *  Lempel-Ziv compression based on 'compress'.  GIF modifications by
- *  David Rowley (mgardi@watdcsu.waterloo.edu)
- *
- ***************************************************************************/
-
-/*
- * General DEFINEs
- */
-
-#define BITS    12
-
-#define HSIZE  5003            /* 80% occupancy */
-
-#ifdef NO_UCHAR
- typedef char   char_type;
-#else /*NO_UCHAR*/
- typedef        unsigned char   char_type;
-#endif /*NO_UCHAR*/
-
-/*
- *
- * GIF Image compression - modified 'compress'
- *
- * Based on: compress.c - File compression ala IEEE Computer, June 1984.
- *
- * By Authors:  Spencer W. Thomas       (decvax!harpo!utah-cs!utah-gr!thomas)
- *              Jim McKie               (decvax!mcvax!jim)
- *              Steve Davies            (decvax!vax135!petsd!peora!srd)
- *              Ken Turkowski           (decvax!decwrl!turtlevax!ken)
- *              James A. Woods          (decvax!ihnp4!ames!jaw)
- *              Joe Orost               (decvax!vax135!petsd!joe)
- *
- */
-#include <ctype.h>
-
-#define ARGVAL() (*++(*argv) || (--argc && *++argv))
-
-static code_int const maxmaxcode = (code_int)1 << BITS;
-    /* should NEVER generate this code */
-#define MAXCODE(n_bits)        (((code_int) 1 << (n_bits)) - 1)
-
-static long htab [HSIZE];
-static unsigned short codetab [HSIZE];
-#define HashTabOf(i)       htab[i]
-#define CodeTabOf(i)    codetab[i]
-
-/*
- * To save much memory, we overlay the table used by compress() with those
- * used by decompress().  The tab_prefix table is the same size and type
- * as the codetab.  The tab_suffix table needs 2**BITS characters.  We
- * get this from the beginning of htab.  The output stack uses the rest
- * of htab, and contains characters.  There is plenty of room for any
- * possible stack (stack used to be 8000 characters).
- */
-
-#define tab_prefixof(i) CodeTabOf(i)
-#define tab_suffixof(i)        ((char_type*)(htab))[i]
-#define de_stack               ((char_type*)&tab_suffixof((code_int)1<<BITS))
-
-static code_int free_ent = 0;                  /* first unused entry */
-
-/*
- * block compression parameters -- after all codes are used up,
- * and compression rate changes, start over.
- */
-static int clear_flg = 0;
-
-static int offset;
-static long int in_count = 1;            /* length of input */
-static long int out_count = 0;           /* # of codes output (for debugging) */
-
-/*
- * compress stdin to stdout
- *
- * Algorithm:  use open addressing double hashing (no chaining) on the
- * prefix code / next character combination.  We do a variant of Knuth's
- * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
- * secondary probe.  Here, the modular division first probe is gives way
- * to a faster exclusive-or manipulation.  Also do block compression with
- * an adaptive reset, whereby the code table is cleared when the compression
- * ratio decreases, but after the table fills.  The variable-length output
- * codes are re-sized at this point, and a special CLEAR code is generated
- * for the decompressor.  Late addition:  construct the table according to
- * file size for noticeable speed improvement on small files.  Please direct
- * questions about this implementation to ames!jaw.
- */
-
-static int ClearCode;
-static int EOFCode;
-
-/***************************************************************************
-*                          BYTE OUTPUTTER                 
-***************************************************************************/
-
-typedef struct {
-    FILE * fileP;  /* The file to which to output */
-    unsigned int count;
-        /* Number of bytes so far in the current data block */
-    unsigned char buffer[256];
-        /* The current data block, under construction */
-} byteBuffer;
-
-
-
-static byteBuffer *
-byteBuffer_create(FILE * const fileP) {
-
-    byteBuffer * byteBufferP;
-
-    MALLOCVAR_NOFAIL(byteBufferP);
-
-    byteBufferP->fileP = fileP;
-    byteBufferP->count = 0;
-
-    return byteBufferP;
-}
-
-
-
-static void
-byteBuffer_destroy(byteBuffer * const byteBufferP) {
-
-    free(byteBufferP);
-}
-
-
-
-static void
-byteBuffer_flush(byteBuffer * const byteBufferP) {
-/*----------------------------------------------------------------------------
-   Write the current data block to the output file, then reset the current 
-   data block to empty.
------------------------------------------------------------------------------*/
-    if (byteBufferP->count > 0 ) {
-        if (verbose)
-            pm_message("Writing %u byte block", byteBufferP->count);
-        fputc(byteBufferP->count, byteBufferP->fileP);
-        fwrite(byteBufferP->buffer, 1, byteBufferP->count, byteBufferP->fileP);
-        byteBufferP->count = 0;
-    }
-}
-
-
-
-static void
-byteBuffer_flushFile(byteBuffer * const byteBufferP) {
-    
-    fflush(byteBufferP->fileP);
-    
-    if (ferror(byteBufferP->fileP))
-        pm_error("error writing output file");
-}
-
-
+            commandVerb = strdup(pamtogifName);
 
-static void
-byteBuffer_out(byteBuffer *  const byteBufferP,
-               unsigned char const c) {
-/*----------------------------------------------------------------------------
-  Add a byte to the end of the current data block, and if it is now 254
-  characters, flush the data block to the output file.
------------------------------------------------------------------------------*/
-    byteBufferP->buffer[byteBufferP->count++] = c;
-    if (byteBufferP->count >= 254)
-        byteBuffer_flush(byteBufferP);
-}
-
-
-
-struct gif_dest {
-    /* This structure controls output of uncompressed GIF raster */
-
-    byteBuffer * byteBufferP;  /* Where the full bytes go */
-
-    /* State for packing variable-width codes into a bitstream */
-    int n_bits;         /* current number of bits/code */
-    int maxcode;        /* maximum code, given n_bits */
-    int cur_accum;      /* holds bits not yet output */
-    int cur_bits;       /* # of bits in cur_accum */
-
-    /* State for GIF code assignment */
-    int ClearCode;      /* clear code (doesn't change) */
-    int EOFCode;        /* EOF code (ditto) */
-    int code_counter;   /* counts output symbols */
-};
-
-
-
-static unsigned long const masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
-                                       0x001F, 0x003F, 0x007F, 0x00FF,
-                                       0x01FF, 0x03FF, 0x07FF, 0x0FFF,
-                                       0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
-
-typedef struct {
-    byteBuffer * byteBufferP;
-    unsigned int initBits;
-    unsigned int n_bits;                        /* number of bits/code */
-    code_int maxcode;                  /* maximum code, given n_bits */
-    unsigned long curAccum;
-    int curBits;
-} codeBuffer;
-
-
-
-static codeBuffer *
-codeBuffer_create(FILE *       const ofP,
-                  unsigned int const initBits) {
-
-    codeBuffer * codeBufferP;
-
-    MALLOCVAR_NOFAIL(codeBufferP);
-
-    codeBufferP->initBits    = initBits;
-    codeBufferP->n_bits      = codeBufferP->initBits;
-    codeBufferP->maxcode     = MAXCODE(codeBufferP->n_bits);
-    codeBufferP->byteBufferP = byteBuffer_create(ofP);
-    codeBufferP->curAccum    = 0;
-    codeBufferP->curBits     = 0;
-
-    return codeBufferP;
-}
-
-
-
-static void
-codeBuffer_destroy(codeBuffer * const codeBufferP) {
-
-    byteBuffer_destroy(codeBufferP->byteBufferP);
-
-    free(codeBufferP);
-}
-
-
-
-static void
-codeBuffer_output(codeBuffer * const codeBufferP,
-                  code_int     const code) {
-/*----------------------------------------------------------------------------
-   Output one GIF code to the file, through the code buffer.
-
-   The code is represented as n_bits bits in the file -- the lower
-   n_bits bits of 'code'.
-
-   If the code is EOF, flush the code buffer to the file.
-
-   In some cases, change n_bits and recalculate maxcode to go with it.
------------------------------------------------------------------------------*/
-    /*
-      Algorithm:
-      Maintain a BITS character long buffer (so that 8 codes will
-      fit in it exactly).  Use the VAX insv instruction to insert each
-      code in turn.  When the buffer fills up empty it and start over.
-    */
-    
-    codeBufferP->curAccum &= masks[codeBufferP->curBits];
+        strfree(arg0DirName);
+    } else
+        commandVerb = strdup(pamtogifName);
 
-    if (codeBufferP->curBits > 0)
-        codeBufferP->curAccum |= ((long)code << codeBufferP->curBits);
+    if (cmdline.mapfile)
+        asprintfN(&mapfileOpt, "-mapfile=%s", cmdline.mapfile);
     else
-        codeBufferP->curAccum = code;
+        mapfileOpt = strdup("");
 
-    codeBufferP->curBits += codeBufferP->n_bits;
-
-    while (codeBufferP->curBits >= 8) {
-        byteBuffer_out(codeBufferP->byteBufferP,
-                       codeBufferP->curAccum & 0xff);
-        codeBufferP->curAccum >>= 8;
-        codeBufferP->curBits -= 8;
-    }
+    if (cmdline.transparent)
+        asprintfN(&transparentOpt, "-transparent=%s", cmdline.transparent);
+    else
+        transparentOpt = strdup("");
 
-    if (clear_flg) {
-        codeBufferP->n_bits = codeBufferP->initBits;
-        codeBufferP->maxcode = MAXCODE(codeBufferP->n_bits);
-        clear_flg = 0;
-    } else if (free_ent > codeBufferP->maxcode) {
-        /* The next entry is going to be too big for the code size, so
-           increase it, if possible.
-        */
-        ++codeBufferP->n_bits;
-        if (codeBufferP->n_bits == BITS)
-            codeBufferP->maxcode = maxmaxcode;
-        else
-            codeBufferP->maxcode = MAXCODE(codeBufferP->n_bits);
-    }
+    if (cmdline.comment)
+        asprintfN(&commentOpt, "-comment=%s", cmdline.comment);
+    else
+        commentOpt = strdup("");
+
+    asprintfN(&retval, "%s - -alphacolor=%s %s %s %s %s %s %s %s",
+              commandVerb,
+              cmdline.alphacolor,
+              cmdline.interlace ? "-interlace" : "",
+              cmdline.sort ? "-sort" : "",
+              mapfileOpt,
+              transparentOpt,
+              commentOpt,
+              cmdline.nolzw ? "-nolzw" : "",
+              cmdline.verbose ? "-verbose" : "");
     
-    if (code == EOFCode) {
-        /* We're at EOF.  Output the possible partial byte in the buffer */
-        if (codeBufferP->curBits > 0) {
-            byteBuffer_out(codeBufferP->byteBufferP,
-                           codeBufferP->curAccum & 0xff);
-            codeBufferP->curBits = 0;
-        }
-        byteBuffer_flush(codeBufferP->byteBufferP);
-        
-        byteBuffer_flushFile(codeBufferP->byteBufferP);
-    }
-}
-
+    strfree(mapfileOpt);
+    strfree(transparentOpt);
+    strfree(commentOpt);
 
-
-static void
-cl_hash(long const hsize) {
-    /* reset code table */
-
-    long const m1 = -1;
-
-    long * htab_p;
-    long i;
-
-    htab_p = htab + hsize;  /* initial value */
-
-    i = hsize - 16;
-    do {                            /* might use Sys V memset(3) here */
-        *(htab_p-16) = m1;
-        *(htab_p-15) = m1;
-        *(htab_p-14) = m1;
-        *(htab_p-13) = m1;
-        *(htab_p-12) = m1;
-        *(htab_p-11) = m1;
-        *(htab_p-10) = m1;
-        *(htab_p-9) = m1;
-        *(htab_p-8) = m1;
-        *(htab_p-7) = m1;
-        *(htab_p-6) = m1;
-        *(htab_p-5) = m1;
-        *(htab_p-4) = m1;
-        *(htab_p-3) = m1;
-        *(htab_p-2) = m1;
-        *(htab_p-1) = m1;
-        htab_p -= 16;
-    } while ((i -= 16) >= 0);
-
-    for (i += 16; i > 0; --i)
-        *--htab_p = m1;
+    return retval;
 }
 
 
 
 static void
-cl_block(codeBuffer * const codeBufferP) {
-/*----------------------------------------------------------------------------
-  Clear out the hash table
------------------------------------------------------------------------------*/
-    cl_hash(HSIZE);
-    free_ent = ClearCode + 2;
-    clear_flg = 1;
+feedPamtogifNoAlpha(struct pam * const inPamP,
+                    FILE *       const pipeToPamtogif) {
     
-    codeBuffer_output(codeBufferP, (code_int)ClearCode);
-}
-
-
-
-static void
-write_raster_LZW(pixel **      const pixels,
-                 pixval        const input_maxval,
-                 gray **       const alpha,
-                 gray          const alpha_maxval, 
-                 struct cmap * const cmapP, 
-                 int           const initBits,
-                 FILE *        const ofP) {
-/*----------------------------------------------------------------------------
-   Write the raster to file 'ofP'.
-
-   The raster to write is 'pixels', which has maxval 'input_maxval',
-   modified by alpha mask 'alpha', which has maxval 'alpha_maxval'.
+    unsigned int row;
+    struct pam outPam;
+    tuple * tuplerow;
 
-   Use the colormap 'cmapP' to generate the raster ('pixels' is 
-   composed of RGB samples; the GIF raster is colormap indices).
+    tuplerow = pnm_allocpamrow(inPamP);
 
-   Write the raster using LZW compression.
------------------------------------------------------------------------------*/
-    gray const alpha_threshold = (alpha_maxval + 1) / 2;
-        /* gray levels below this in the alpha mask indicate transparent
-           pixels in the output image.
-        */
-    code_int ent;
-    code_int disp;
-    int hshift;
-    bool eof;
-    codeBuffer * codeBufferP;
-    
-    codeBufferP = codeBuffer_create(ofP, initBits);
+    outPam = *inPamP;
+    outPam.file = pipeToPamtogif;
     
-    /*
-     * Set up the necessary values
-     */
-    offset = 0;
-    out_count = 0;
-    clear_flg = 0;
-    in_count = 1;
-
-    ClearCode = (1 << (initBits - 1));
-    EOFCode = ClearCode + 1;
-    free_ent = ClearCode + 2;
-
-    ent = gifNextPixel(pixels, input_maxval, alpha, alpha_threshold, cmapP);
-
-    {
-        long fcode;
-        hshift = 0;
-        for (fcode = HSIZE; fcode < 65536L; fcode *= 2L)
-            ++hshift;
-        hshift = 8 - hshift;                /* set hash code range bound */
-    }
-    cl_hash(HSIZE);            /* clear hash table */
-
-    codeBuffer_output(codeBufferP, (code_int)ClearCode);
-
-    eof = FALSE;
-    while (!eof) {
-        int gifpixel;
-            /* The value for the pixel in the GIF image.  I.e. the colormap
-               index.  Or -1 to indicate "no more pixels."
-            */
-        gifpixel = gifNextPixel(pixels, 
-                                input_maxval, alpha, alpha_threshold, cmapP);
-        if (gifpixel == EOF) eof = TRUE;
-        if (!eof) {
-            long const fcode = (long) (((long) gifpixel << BITS) + ent);
-            code_int i;
-                /* xor hashing */
-
-            ++in_count;
-
-            i = (((code_int)gifpixel << hshift) ^ ent);    
-
-            if (HashTabOf (i) == fcode) {
-                ent = CodeTabOf (i);
-                continue;
-            } else if ((long)HashTabOf(i) < 0)      /* empty slot */
-                goto nomatch;
-            disp = HSIZE - i;        /* secondary hash (after G. Knott) */
-            if (i == 0)
-                disp = 1;
-        probe:
-            if ((i -= disp) < 0)
-                i += HSIZE;
-
-            if (HashTabOf(i) == fcode) {
-                ent = CodeTabOf(i);
-                continue;
-            }
-            if ((long)HashTabOf(i) > 0)
-                goto probe;
-        nomatch:
-            codeBuffer_output(codeBufferP, (code_int)ent);
-            ++out_count;
-            ent = gifpixel;
-            if (free_ent < maxmaxcode) {
-                CodeTabOf(i) = free_ent++; /* code -> hashtable */
-                HashTabOf(i) = fcode;
-            } else
-                cl_block(codeBufferP);
-        }
-    }
-    /* Put out the final code. */
-    codeBuffer_output(codeBufferP, (code_int)ent);
-    ++out_count;
-    codeBuffer_output(codeBufferP, (code_int) EOFCode);
-
-    codeBuffer_destroy(codeBufferP);
-}
-
+    pnm_writepaminit(&outPam);
 
+    for (row = 0; row < inPamP->height; ++row) {
+        pnm_readpamrow(inPamP, tuplerow);
 
-/* Routine to convert variable-width codes into a byte stream */
-
-static void
-outputUncompressed(struct gif_dest * const dinfoP,
-                   int               const code) {
-
-    /* Emit a code of n_bits bits */
-    /* Uses cur_accum and cur_bits to reblock into 8-bit bytes */
-    dinfoP->cur_accum |= ((int) code) << dinfoP->cur_bits;
-    dinfoP->cur_bits += dinfoP->n_bits;
-
-    while (dinfoP->cur_bits >= 8) {
-        byteBuffer_out(dinfoP->byteBufferP, dinfoP->cur_accum & 0xFF);
-        dinfoP->cur_accum >>= 8;
-        dinfoP->cur_bits -= 8;
+        pnm_writepamrow(&outPam, tuplerow);
     }
-}
-
-
-static void
-writeRasterUncompressedInit(FILE *            const ofP,
-                            struct gif_dest * const dinfoP, 
-                            int               const i_bits) {
-/*----------------------------------------------------------------------------
-   Initialize pseudo-compressor
------------------------------------------------------------------------------*/
-
-    /* init all the state variables */
-    dinfoP->n_bits = i_bits;
-    dinfoP->maxcode = MAXCODE(dinfoP->n_bits);
-    dinfoP->ClearCode = (1 << (i_bits - 1));
-    dinfoP->EOFCode = dinfoP->ClearCode + 1;
-    dinfoP->code_counter = dinfoP->ClearCode + 2;
-    /* init output buffering vars */
-    dinfoP->byteBufferP = byteBuffer_create(ofP);
-    dinfoP->cur_accum = 0;
-    dinfoP->cur_bits = 0;
-    /* GIF specifies an initial Clear code */
-    outputUncompressed(dinfoP, dinfoP->ClearCode);
+    pnm_freepamrow(tuplerow);
 }
 
 
 
 static void
-writeRasterUncompressedPixel(struct gif_dest * const dinfoP, 
-                             unsigned int      const colormapIndex) {
-/*----------------------------------------------------------------------------
-   "Compress" one pixel value and output it as a symbol.
-
-   'colormapIndex' must be less than dinfoP->n_bits wide.
------------------------------------------------------------------------------*/
-    assert(colormapIndex >> dinfoP->n_bits == 0);
-
-    outputUncompressed(dinfoP, colormapIndex);
-    /* Issue Clear codes often enough to keep the reader from ratcheting up
-     * its symbol size.
-     */
-    if (dinfoP->code_counter < dinfoP->maxcode) {
-        ++dinfoP->code_counter;
-    } else {
-        outputUncompressed(dinfoP, dinfoP->ClearCode);
-        dinfoP->code_counter = dinfoP->ClearCode + 2;	/* reset the counter */
-    }
-}
-
-
-
-static void
-writeRasterUncompressedTerm(struct gif_dest * const dinfoP) {
-
-    outputUncompressed(dinfoP, dinfoP->EOFCode);
-
-    if (dinfoP->cur_bits > 0)
-        byteBuffer_out(dinfoP->byteBufferP, dinfoP->cur_accum & 0xFF);
-
-    byteBuffer_flush(dinfoP->byteBufferP);
-
-    byteBuffer_destroy(dinfoP->byteBufferP);
-}
-
-
-
-static void
-writeRasterUncompressed(FILE *         const ofP, 
-                        pixel **       const pixels,
-                        pixval         const inputMaxval,
-                        gray **        const alpha,
-                        gray           const alphaMaxval, 
-                        struct cmap *  const cmapP, 
-                        int            const initBits) {
-/*----------------------------------------------------------------------------
-   Write the raster to file 'ofP'.
-   
-   Same as write_raster_LZW(), except written out one code per
-   pixel (plus some clear codes), so no compression.  And no use
-   of the LZW patent.
------------------------------------------------------------------------------*/
-    gray const alphaThreshold = (alphaMaxval + 1) / 2;
-        /* gray levels below this in the alpha mask indicate transparent
-           pixels in the output image.
-        */
-    bool eof;
-
-    struct gif_dest gifDest;
-
-    writeRasterUncompressedInit(ofP, &gifDest, initBits);
-
-    eof = FALSE;
-    while (!eof) {
-        int gifpixel;
-            /* The value for the pixel in the GIF image.  I.e. the colormap
-               index.  Or -1 to indicate "no more pixels."
-            */
-        gifpixel = gifNextPixel(pixels, 
-                                inputMaxval, alpha, alphaThreshold, cmapP);
-        if (gifpixel == EOF)
-            eof = TRUE;
-        else
-            writeRasterUncompressedPixel(&gifDest, gifpixel);
-    }
-    writeRasterUncompressedTerm(&gifDest);
-}
-
-
-
-/******************************************************************************
- *
- * GIF Specific routines
- *
- *****************************************************************************/
-
-static void
-writeGifHeader(FILE * const fp,
-               int const Width, int const Height, 
-               int const GInterlace, int const Background, 
-               int const BitsPerPixel, struct cmap * const cmapP,
-               const char comment[]) {
-
-    int B;
-    int const Resolution = BitsPerPixel;
-    int const ColorMapSize = 1 << BitsPerPixel;
-
-    /* Write the Magic header */
-    if (cmapP->transparent != -1 || comment)
-        fwrite("GIF89a", 1, 6, fp);
-    else
-        fwrite("GIF87a", 1, 6, fp);
-
-    /* Write out the screen width and height */
-    Putword( Width, fp );
-    Putword( Height, fp );
-
-    /* Indicate that there is a global color map */
-    B = 0x80;       /* Yes, there is a color map */
-
-    /* OR in the resolution */
-    B |= (Resolution - 1) << 4;
-
-    /* OR in the Bits per Pixel */
-    B |= (BitsPerPixel - 1);
-
-    /* Write it out */
-    fputc( B, fp );
-
-    /* Write out the Background color */
-    fputc( Background, fp );
-
-    /* Byte of 0's (future expansion) */
-    fputc( 0, fp );
-
-    {
-        /* Write out the Global Color Map */
-        /* Note that the Global Color Map is always a power of two colors
-           in size, but *cmapP could be smaller than that.  So we pad with
-           black.
-        */
-        int i;
-        for ( i=0; i < ColorMapSize; ++i ) {
-            if ( i < cmapP->cmapsize ) {
-                fputc( cmapP->red[i], fp );
-                fputc( cmapP->green[i], fp );
-                fputc( cmapP->blue[i], fp );
-            } else {
-                fputc( 0, fp );
-                fputc( 0, fp );
-                fputc( 0, fp );
-            }
+copyRasterWithAlpha(struct pam * const inPamP,
+                    struct pam * const alphaPamP,
+                    struct pam * const outPamP,
+                    unsigned int const alphaPlane) {
+
+    tuple * tuplerow;
+    tuple * alpharow;
+    unsigned int row;
+
+    inPamP->allocation_depth = outPamP->depth;
+
+    tuplerow = pnm_allocpamrow(inPamP);
+    alpharow = pnm_allocpamrow(alphaPamP);
+
+    for (row = 0; row < inPamP->height; ++row) {
+        unsigned int col;
+            
+        pnm_readpamrow(inPamP, tuplerow);
+        pnm_readpamrow(alphaPamP, alpharow);
+
+        for (col = 0; col < inPamP->width; ++col) {
+            tuplerow[col][alphaPlane] = pnm_scalesample(alpharow[col][0],
+                                                        alphaPamP->maxval,
+                                                        inPamP->maxval);
         }
+        pnm_writepamrow(outPamP, tuplerow);
     }
-        
-    if ( cmapP->transparent >= 0 ) 
-        write_transparent_color_index_extension(fp, cmapP->transparent);
-
-    if ( comment )
-        write_comment_extension(fp, comment);
-}
-
-
-
-static void
-writeImageHeader(FILE *       const ofP,
-                 unsigned int const leftOffset,
-                 unsigned int const topOffset,
-                 unsigned int const gWidth,
-                 unsigned int const gHeight,
-                 unsigned int const gInterlace,
-                 unsigned int const initCodeSize) {
-
-    Putword(leftOffset, ofP);
-    Putword(topOffset,  ofP);
-    Putword(gWidth,     ofP);
-    Putword(gHeight,    ofP);
-
-    /* Write out whether or not the image is interlaced */
-    if (gInterlace)
-        fputc(0x40, ofP);
-    else
-        fputc(0x00, ofP);
-
-    /* Write out the initial code size */
-    fputc(initCodeSize, ofP);
-}
-
-
-
-static void
-gifEncode(FILE *        const ofP, 
-          pixel **      const pixels,
-          pixval        const inputMaxval,
-          int           const gWidth,
-          int           const gHeight, 
-          gray **       const alpha,
-          gray          const alphaMaxval,
-          int           const gInterlace,
-          int           const background, 
-          int           const bitsPerPixel,
-          struct cmap * const cmapP,
-          char          const comment[],
-          bool          const nolzw) {
-
-    unsigned int const leftOffset = 0;
-    unsigned int const topOffset  = 0;
-
-    unsigned int const initCodeSize = bitsPerPixel <= 1 ? 2 : bitsPerPixel;
-        /* The initial code size */
-
-    writeGifHeader(ofP, gWidth, gHeight, gInterlace, background,
-                   bitsPerPixel, cmapP, comment);
-
-    /* Write an Image separator */
-    fputc(',', ofP);
-
-    writeImageHeader(ofP, leftOffset, topOffset, gWidth, gHeight, gInterlace,
-                     initCodeSize);
-
-    initPixelCursor(gWidth, gHeight, gInterlace);
-
-    /* Write the actual raster */
-    if (nolzw)
-        writeRasterUncompressed(ofP, pixels, 
-                                inputMaxval, alpha, alphaMaxval, cmapP, 
-                                initCodeSize + 1);
-    else
-        write_raster_LZW(pixels, 
-                         inputMaxval, alpha, alphaMaxval, cmapP, 
-                         initCodeSize + 1, ofP);
-
-    /* Write out a zero length data block (to end the series) */
-    fputc(0, ofP);
-
-    /* Write the GIF file terminator */
-    fputc(';', ofP);
-}
-
-
-
-static int
-compute_transparent(const char colorarg[], 
-                    struct cmap * const cmapP) {
-/*----------------------------------------------------------------------------
-   Figure out the color index (index into the colormap) of the color
-   that is to be transparent in the GIF.
-
-   colorarg[] is the string that specifies the color the user wants to
-   be transparent (e.g. "red", "#fefefe").  Its maxval is the maxval
-   of the colormap.  'cmap' is the full colormap except that its
-   'transparent' component isn't valid.
-
-   colorarg[] is a standard Netpbm color specification, except that
-   may have a "=" prefix, which means it specifies a particular exact
-   color, as opposed to without the "=", which means "the color that
-   is closest to this and actually in the image."
-
-   Return -1 if colorarg[] specifies an exact color and that color is not
-   in the image.  Also issue an informational message.
------------------------------------------------------------------------------*/
-    int retval;
-
-    const char *colorspec;
-    bool exact;
-    int presort_colorindex;
-    pixel transcolor;
-
-    if (colorarg[0] == '=') {
-        colorspec = &colorarg[1];
-        exact = TRUE;
-    } else {
-        colorspec = colorarg;
-        exact = FALSE;
-    }
-        
-    transcolor = ppm_parsecolor((char*)colorspec, cmapP->maxval);
-    presort_colorindex = ppm_lookupcolor(cmapP->cht, &transcolor);
-    
-    if (presort_colorindex != -1)
-        retval = cmapP->perm[presort_colorindex];
-    else if (!exact)
-        retval = cmapP->perm[closestcolor(transcolor, cmapP->maxval, cmapP)];
-    else {
-        retval = -1;
-        pm_message(
-            "Warning: specified transparent color does not occur in image.");
-    }
-    return retval;
+    pnm_freepamrow(alpharow);
+    pnm_freepamrow(tuplerow);
 }
 
 
 
 static void
-sort_colormap(int const sort, struct cmap * const cmapP) {
-/*----------------------------------------------------------------------------
-   Sort (in place) the colormap *cmapP.
-
-   Create the perm[] and permi[] mappings for the colormap.
-
-   'sort' is logical:  true means to sort the colormap by red intensity,
-   then by green intensity, then by blue intensity.  False means a null
-   sort -- leave it in the same order in which we found it.
------------------------------------------------------------------------------*/
-    int * const Red = cmapP->red;
-    int * const Blue = cmapP->blue;
-    int * const Green = cmapP->green;
-    int * const perm = cmapP->perm;
-    int * const permi = cmapP->permi;
-    unsigned int const cmapsize = cmapP->cmapsize;
-    
-    int i;
-
-    for (i=0; i < cmapsize; i++)
-        permi[i] = i;
-
-    if (sort) {
-        pm_message("sorting colormap");
-        for (i=0; i < cmapsize; i++) {
-            int j;
-            for (j=i+1; j < cmapsize; j++)
-                if (((Red[i]*MAXCMAPSIZE)+Green[i])*MAXCMAPSIZE+Blue[i] >
-                    ((Red[j]*MAXCMAPSIZE)+Green[j])*MAXCMAPSIZE+Blue[j]) {
-                    int tmp;
-                    
-                    tmp=permi[i]; permi[i]=permi[j]; permi[j]=tmp;
-                    tmp=Red[i]; Red[i]=Red[j]; Red[j]=tmp;
-                    tmp=Green[i]; Green[i]=Green[j]; Green[j]=tmp;
-                    tmp=Blue[i]; Blue[i]=Blue[j]; Blue[j]=tmp; } }
+feedPamtogifWithAlpha(struct pam * const inPamP,
+                      struct pam * const alphaPamP,
+                      FILE *       const pipeToPamtogif) {
+
+    unsigned int alphaPlane;
+    struct pam outPam;
+
+    if (inPamP->width != alphaPamP->width ||
+        inPamP->height != alphaPamP->height)
+        pm_error("-alpha image dimensions (%u w x %u h) do not match "
+                 "the input image dimensions (%u x %u)",
+                 alphaPamP->width, alphaPamP->height,
+                 inPamP->width, inPamP->height);
+
+    outPam = *inPamP;
+    outPam.file        = pipeToPamtogif;
+    outPam.format      = PAM_FORMAT;
+    outPam.plainformat = 0;
+
+    if (inPamP->depth == 1) {
+        alphaPlane = 1;
+        strcpy(outPam.tuple_type, "GRAYSCALE_ALPHA");
+    } else if (inPamP->depth == 3) {
+        alphaPlane = 3;
+        strcpy(outPam.tuple_type, "RGB_ALPHA");
     }
+    outPam.depth = alphaPlane + 1;
 
-    for (i=0; i < cmapsize; i++)
-        perm[permi[i]] = i;
-}
+    pnm_writepaminit(&outPam);
 
-
-
-static void
-normalize_to_255(colorhist_vector const chv, struct cmap * const cmapP) {
-/*----------------------------------------------------------------------------
-   With a PPM color histogram vector 'chv' as input, produce a colormap
-   of integers 0-255 as output in *cmapP.
------------------------------------------------------------------------------*/
-    int i;
-    pixval const maxval = cmapP->maxval;
-
-    if ( maxval != 255 )
-        pm_message(
-            "maxval is not 255 - automatically rescaling colors" );
-
-    for ( i = 0; i < cmapP->cmapsize; ++i ) {
-        if ( maxval == 255 ) {
-            cmapP->red[i] = (int) PPM_GETR( chv[i].color );
-            cmapP->green[i] = (int) PPM_GETG( chv[i].color );
-            cmapP->blue[i] = (int) PPM_GETB( chv[i].color );
-        } else {
-            cmapP->red[i] = (int) PPM_GETR( chv[i].color ) * 255 / maxval;
-            cmapP->green[i] = (int) PPM_GETG( chv[i].color ) * 255 / maxval;
-            cmapP->blue[i] = (int) PPM_GETB( chv[i].color ) * 255 / maxval;
-        }
-    }
-}
-
-
-
-static void add_to_colormap(struct cmap * const cmapP, 
-                            const char *  const colorspec, 
-                            int *         const new_indexP) {
-/*----------------------------------------------------------------------------
-  Add a new entry to the colormap.  Make the color that specified by
-  'colorspec', and return the index of the new entry as *new_indexP.
-
-  'colorspec' is a color specification given by the user, e.g.
-  "red" or "rgb:ff/03.0d".  The maxval for this color specification is
-  that for the colormap *cmapP.
------------------------------------------------------------------------------*/
-    pixel const transcolor = ppm_parsecolor((char*)colorspec, cmapP->maxval);
-    
-    *new_indexP = cmapP->cmapsize++; 
-
-    cmapP->red[*new_indexP] = PPM_GETR(transcolor);
-    cmapP->green[*new_indexP] = PPM_GETG(transcolor); 
-    cmapP->blue[*new_indexP] = PPM_GETB(transcolor); 
+    copyRasterWithAlpha(inPamP, alphaPamP, &outPam, alphaPlane);
 }
 
 
 
 static void
-colormap_from_file(const char filespec[], unsigned int const maxcolors,
-                   colorhist_vector * const chvP, pixval * const maxvalP,
-                   int * const colorsP) {
-/*----------------------------------------------------------------------------
-   Read a colormap from the PPM file filespec[].  Return the color histogram
-   vector (which is practically a colormap) of the input image as *cvhP
-   and the maxval for that histogram as *maxvalP.
------------------------------------------------------------------------------*/
-    FILE *mapfile;
-    int cols, rows;
-    pixel ** colormap_ppm;
-
-    mapfile = pm_openr(filespec);
-    colormap_ppm = ppm_readppm(mapfile, &cols, &rows, maxvalP);
-    pm_close(mapfile);
+feedPamtogif(struct pam * const inPamP,
+             const char * const alphaFilespec,
+             FILE *       const pipeToPamtogif) {
     
-    /* Figure out the colormap from the <mapfile>. */
-    pm_message("computing other colormap...");
-    *chvP = 
-        ppm_computecolorhist(colormap_ppm, cols, rows, maxcolors, colorsP);
-    
-    ppm_freearray(colormap_ppm, rows); 
-}
-
-
-
-static void
-get_alpha(const char * const alpha_filespec, int const cols, int const rows,
-          gray *** const alphaP, gray * const maxvalP) {
-
-    if (alpha_filespec) {
-        int alpha_cols, alpha_rows;
-        *alphaP = pgm_readpgm(pm_openr(alpha_filespec),
-                              &alpha_cols, &alpha_rows, maxvalP);
-        if (alpha_cols != cols || alpha_rows != rows)
-            pm_error("alpha mask is not the same dimensions as the "
-                     "input file (alpha is %dW x %dH; image is %dW x %dH)",
-                     alpha_cols, alpha_rows, cols, rows);
-    } else 
-        *alphaP = NULL;
-}
-
-
-
-static void
-compute_ppm_colormap(pixel ** const pixels, int const cols, int const rows,
-                     int const input_maxval, bool const have_alpha, 
-                     const char * const mapfile, colorhist_vector * const chvP,
-                     colorhash_table * const chtP,
-                     pixval * const colormap_maxvalP, 
-                     int * const colorsP) {
-/*----------------------------------------------------------------------------
-   Compute a colormap, PPM style, for the image 'pixels', which is
-   'cols' by 'rows' with maxval 'input_maxval'.  If 'mapfile' is
-   non-null, Use the colors in that (PPM) file for the color map
-   instead of the colors in 'pixels'.
-
-   Return the colormap as *chvP and *chtP.  Return the maxval for that
-   colormap as *colormap_maxvalP.
-
-   While we're at it, count the colors and validate that there aren't
-   too many.  Return the count as *colorsP.  In determining if there are
-   too many, allow one slot for a fake transparency color if 'have_alpha'
-   is true.  If there are too many, issue an error message and abort the
-   program.
------------------------------------------------------------------------------*/
-    unsigned int maxcolors;
-        /* The most colors we can tolerate in the image.  If we have
-           our own made-up entry in the colormap for transparency, it
-           isn't included in this count.
-        */
-
-    if (have_alpha)
-        maxcolors = MAXCMAPSIZE - 1;
-    else
-        maxcolors = MAXCMAPSIZE;
-
-    if (mapfile) {
-        /* Read the colormap from a separate colormap file. */
-        colormap_from_file(mapfile, maxcolors, chvP, colormap_maxvalP, 
-                           colorsP);
-    } else {
-        /* Figure out the color map from the input file */
-        pm_message("computing colormap...");
-        *chvP = ppm_computecolorhist(pixels, cols, rows, maxcolors, colorsP); 
-        *colormap_maxvalP = input_maxval;
-    }
-
-    if (*chvP == NULL)
-        pm_error("too many colors - try doing a 'pnmquant %d'", maxcolors);
-    pm_message("%d colors found", *colorsP);
-
-    /* And make a hash table for fast lookup. */
-    *chtP = ppm_colorhisttocolorhash(*chvP, *colorsP);
+    if (alphaFilespec) {
+        FILE * afP;
+        struct pam alphaPam;
+        afP = pm_openr(alphaFilespec);
+        pnm_readpaminit(afP, &alphaPam, PAM_STRUCT_SIZE(tuple_type));
+        feedPamtogifWithAlpha(inPamP, &alphaPam, pipeToPamtogif);
+        pm_close(afP);
+    } else
+        feedPamtogifNoAlpha(inPamP, pipeToPamtogif);
 }
 
 
 
 int
-main(int argc, char *argv[]) {
+main(int    argc,
+     char * argv[]) {
+
     struct cmdlineInfo cmdline;
     FILE * ifP;
-    int rows, cols;
-    int BitsPerPixel;
-    pixel ** pixels;   /* The input image, in PPM format */
-    pixval input_maxval;  /* Maxval for 'pixels' */
-    gray ** alpha;     /* The supplied alpha mask; NULL if none */
-    gray alpha_maxval; /* Maxval for 'alpha' */
-
-    struct cmap cmap;
-        /* The colormap, with all its accessories */
-    colorhist_vector chv;
-    int fake_transparent;
-        /* colormap index of the fake transparency color we're using to
-           implement the alpha mask.  Undefined if we're not doing an alpha
-           mask.
-        */
+    struct pam inPam;
+    const char * command;
+    FILE * pipeToPamtogif;
+    int rc;
 
-    ppm_init( &argc, argv );
+    pnm_init(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
-    verbose = cmdline.verbose;
-
-    ifP = pm_openr(cmdline.input_filespec);
-
-    pixels = ppm_readppm(ifP, &cols, &rows, &input_maxval);
+    command = pamtogifCommand(argv[0], cmdline);
 
-    pm_close(ifP);
-
-    get_alpha(cmdline.alpha_filespec, cols, rows, &alpha, &alpha_maxval);
+    if (cmdline.verbose)
+        pm_message("Executing shell command '%s'", command);
+    
+    pipeToPamtogif = popen(command, "w");
 
-    compute_ppm_colormap(pixels, cols, rows, input_maxval, (alpha != NULL), 
-                         cmdline.mapfile, 
-                         &chv, &cmap.cht, &cmap.maxval, &cmap.cmapsize);
+    if (pipeToPamtogif == NULL)
+        pm_error("Shell command '%s', via popen(), failed.", command);
 
-    /* Now turn the ppm colormap into the appropriate GIF colormap. */
+    ifP = pm_openr(cmdline.input_filespec);
+    pnm_readpaminit(ifP, &inPam, PAM_STRUCT_SIZE(allocation_depth));
 
-    normalize_to_255(chv, &cmap);
+    feedPamtogif(&inPam, cmdline.alpha_filespec, pipeToPamtogif);
 
-    ppm_freecolorhist(chv);
+    rc = pclose(pipeToPamtogif);
 
-    if (alpha) {
-        /* Add a fake entry to the end of the colormap for transparency.  
-           Make its color black. 
-        */
-        add_to_colormap(&cmap, cmdline.alphacolor, &fake_transparent);
-    }
-    sort_colormap(cmdline.sort, &cmap);
-
-    BitsPerPixel = pm_maxvaltobits(cmap.cmapsize-1);
-
-    if (alpha) {
-        cmap.transparent = cmap.perm[fake_transparent];
-    } else {
-        if (cmdline.transparent)
-            cmap.transparent = 
-                compute_transparent(cmdline.transparent, &cmap);
-        else 
-            cmap.transparent = -1;
-    }
-    /* All set, let's do it. */
-    gifEncode(stdout, pixels, input_maxval, cols, rows, 
-              alpha, alpha_maxval, 
-              cmdline.interlace, 0, BitsPerPixel, &cmap, cmdline.comment,
-              cmdline.nolzw);
+    if (rc != 0)
+        pm_error("Pamtogif process failed.  pclose() failed.");
 
-    ppm_freearray(pixels, rows);
-    if (alpha)
-        pgm_freearray(alpha, rows);
+    strfree(command);
 
-    fclose(stdout);
+    pm_close(ifP);
+    pm_close(stdout);
 
     return 0;
 }
diff --git a/converter/ppm/ppmtoilbm.c b/converter/ppm/ppmtoilbm.c
index 6c04c9be..c0d58edb 100644
--- a/converter/ppm/ppmtoilbm.c
+++ b/converter/ppm/ppmtoilbm.c
@@ -635,20 +635,9 @@ ppm_to_ham(fp, cols, rows, maxval, colormap, colors, cmapmaxval, hamplanes)
 
 
 static long
-#ifdef __STDC__
 do_ham_body(FILE *ifP, FILE *ofp, int cols, int rows,
             pixval maxval, pixval hammaxval, int nPlanes,
             pixel *colormap, int colors)
-#else
-do_ham_body(ifP, ofp, cols, rows, maxval, hammaxval, nPlanes, colormap, colors)
-    FILE *ifP, *ofp;
-    int cols, rows;
-    pixval maxval;      /* maxval of image color components */
-    pixval hammaxval;   /* maxval of HAM color changes */
-    int nPlanes;
-    pixel *colormap;
-    int colors;
-#endif
 {
     register int col, row, i;
     rawtype *raw_rowbuf;
@@ -876,16 +865,8 @@ ppm_to_deep(fp, cols, rows, maxval, bitspercolor)
 
 
 static long
-#if __STDC__
 do_deep_body(FILE *ifP, FILE *ofp, int cols, int rows, pixval maxval, 
              int bitspercolor)
-#else
-do_deep_body(ifP, ofp, cols, rows, maxval, bitspercolor)
-    FILE *ifP, *ofp;
-    int cols, rows;
-    pixval maxval;
-    int bitspercolor;
-#endif
 {
     register int row, col;
     pixel *pP;
@@ -1014,16 +995,8 @@ ppm_to_dcol(fp, cols, rows, maxval, dcol)
 
 
 static long
-#if __STDC__
 do_dcol_body(FILE *ifP, FILE *ofp, int cols, int rows, pixval maxval, 
              DirectColor *dcol)
-#else
-do_dcol_body(ifP, ofp, cols, rows, maxval, dcol)
-    FILE *ifP, *ofp;
-    int cols, rows;
-    pixval maxval;
-    DirectColor *dcol;
-#endif
 {
     register int row, col;
     pixel *pP;
@@ -1161,18 +1134,8 @@ ppm_to_std(fp, cols, rows, maxval, colormap, colors, cmapmaxval,
 
 
 static long
-#if __STDC__
 do_std_body(FILE *ifP, FILE *ofp, int cols, int rows, pixval maxval,
             pixel *colormap, int colors, int nPlanes)
-#else
-do_std_body(ifP, ofp, cols, rows, maxval, colormap, colors, nPlanes)
-    FILE *ifP, *ofp;
-    int cols, rows;
-    pixval maxval;
-    pixel *colormap;
-    int colors;
-    int nPlanes;
-#endif
 {
     register int row, col, i;
     pixel *pP;
@@ -1783,12 +1746,7 @@ runbyte1(size)
 /************ other utility functions ************/
 
 static void
-#if __STDC__
 put_big_short(short s)
-#else
-put_big_short(s)
-    short s;
-#endif
 {
     if ( pm_writebigshort( stdout, s ) == -1 )
         pm_error( "write error" );
diff --git a/converter/ppm/ppmtomitsu.c b/converter/ppm/ppmtomitsu.c
index 3934ae45..837d9e2b 100644
--- a/converter/ppm/ppmtomitsu.c
+++ b/converter/ppm/ppmtomitsu.c
@@ -20,362 +20,70 @@ x**  - mymalloc() and check_and_rotate() functions for often used
 ** implied warranty.
 */
 
+#include <assert.h>
 #include <string.h>
+#include <stdio.h>
 
 #include "pm_c_util.h"
-#include "ppm.h"
 #include "nstring.h"
 #include "mallocvar.h"
+#include "ppm.h"
 
 #include "mitsu.h"
 
 
-#include <stdio.h>
-
 #define HASHSIZE 2048
 #define myhash(x) ((PPM_GETR(x)*3 + PPM_GETG(x)*5 + PPM_GETB(x)*7) % HASHSIZE)
 
 typedef struct hashinfo {
         pixel     color;
         long      flag;
-        struct hashinfo *next;
+        struct hashinfo * next;
 } hashinfo;
 
-#ifdef __STDC__
-static void lineputinit(int cols, int rows, int sharpness, int enlarge, int
-                        copy, struct mediasize medias);
-static void frametransferinit(int cols, int rows, int sharpness, int enlarge,
-                              int copy, struct mediasize medias);
-static void lookuptableinit(int sharpness, int enlarge, int copy,
-                            struct mediasize medias);
-static void lookuptabledata(int cols, int rows, int enlarge,
-                            struct mediasize medias);
-static void check_and_rotate(int cols, int rows, int enlarge,
-                             struct mediasize medias);
-#define CONST const
-#else /*__STDC__*/
-static int lineputinit();
-static int lookuptableinit();
-static int lookuptabledata();
-static int frametransferinit();
-static int check_and_rotate();
-#define CONST
-#endif
-
 #define cmd(arg)           fputc((arg), stdout)
 #define datum(arg)         fputc((char)(arg), stdout)
 #define data(arg,num)      fwrite((arg), sizeof(char), (num), stdout)
 
 
-#ifdef __STDC__
-int main(int argc, char *argv[] )
-#else
-int main( argc, argv )
-    int argc;
-    char* argv[];
-#endif
-    {
-    FILE             *ifp;
-    /*hashinfo         colorhashtable[HASHSIZE];*/
-    struct hashinfo  *hashrun;
-    pixel            *xP;
-    int              argn;
-    bool             dpi300;
-    int              cols, rows, format, col, row;
-    int              sharpness, enlarge, copy, tiny;
-    pixval           maxval;
-    struct mediasize medias;
-    char             media[16];
-    const char * const usage = "[-sharpness <1-4>] [-enlarge <1-3>] [-media <a,a4,as,a4s>] [-copy <1-9>] [-tiny] [-dpi300] [ppmfile]";
-
-    ppm_init(&argc, argv);
-
-    dpi300 = FALSE;
-    argn = 1;
-    sharpness = 32;
-    enlarge   = 1;
-    copy      = 1;
-    memset(media, '\0', 16);
-    tiny      = FALSE;
-
-    /* check for flags */
-    while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
-    if (pm_keymatch(argv[argn], "-sharpness", 2)) {
-        ++argn;
-        if (argn == argc || sscanf(argv[argn], "%d", &sharpness) != 1)
-            pm_usage(usage);
-        else if (sharpness < 1 || sharpness > 4)
-            pm_usage(usage);
-        }
-    else if (pm_keymatch(argv[argn], "-enlarge", 2)) {
-        ++argn;
-        if (argn == argc || sscanf(argv[argn], "%d", &enlarge) != 1)
-            pm_usage(usage);
-        else if (enlarge < 1 || enlarge > 3)
-            pm_usage(usage);
-        }
-    else if (pm_keymatch(argv[argn], "-media", 2)) {
-        ++argn;
-        if (argn == argc || sscanf(argv[argn], "%15s", media) < 1)
-            pm_usage(usage);
-        else if (TOUPPER(media[0]) != 'A')
-            pm_usage(usage);
-    }
-    else if (pm_keymatch(argv[argn], "-copy", 2)) {
-        ++argn;
-        if (argn == argc || sscanf(argv[argn], "%d", &copy) != 1)
-            pm_usage(usage);
-        else if (copy < 1 || copy > 9)
-            pm_usage(usage);
-        }
-    else if (pm_keymatch(argv[argn], "-dpi300", 2))
-        dpi300 = TRUE;
-    else if (pm_keymatch(argv[argn], "-tiny", 2))
-        tiny = TRUE;
-    else
-        pm_usage(usage);
-        ++argn;
-    }
-
-    if (argn < argc) {
-        ifp = pm_openr(argv[argn]);
-        ++argn;
-    }
-    else
-        ifp = stdin;
-
-    if (argn != argc)
-        pm_usage(usage);
-
-    if (TOUPPER(media[0]) == 'A')
-        switch (TOUPPER(media[1])) {
-        case 'S':
-            medias = MSize_AS;
-            break;
-        case '4':
-            if(TOUPPER(media[2]) == 'S')
-                medias = MSize_A4S;
-            else {
-                medias = MSize_A4;
-            }
-            break;
-        default:
-            medias = MSize_A;
-        }
-    else
-        medias = MSize_User;
 
-        if (dpi300) {
-                medias.maxcols *= 2;
-                medias.maxrows *= 2;
-        }
+static void
+check_and_rotate(int              const cols,
+                 int              const rows,
+                 int              const enlarge,
+                 struct mediasize const medias) {
 
-    if (tiny) {
-        pixel            *pixelrow;
-        char             *redrow, *greenrow, *bluerow;
-
-        ppm_readppminit(ifp, &cols, &rows, &maxval, &format);
-        pixelrow = (pixel *) ppm_allocrow(cols);
-        MALLOCARRAY_NOFAIL(redrow, cols);
-        MALLOCARRAY_NOFAIL(greenrow, cols);
-        MALLOCARRAY_NOFAIL(bluerow, cols);
-        lineputinit(cols, rows, sharpness, enlarge, copy, medias);
-
-        for ( row = 0; row < rows; ++row ) {
-            ppm_readppmrow(ifp, pixelrow, cols, maxval, format);
-            switch(PPM_FORMAT_TYPE(format)) {
-            /* color */
-            case PPM_TYPE:
-                for (col = 0, xP = pixelrow; col < cols; col++, xP++) {
-                    /* First red. */
-                    redrow[col] = PPM_GETR(*xP);
-                    /* Then green. */
-                    greenrow[col] = PPM_GETG(*xP);
-                    /* And blue. */
-                    bluerow[col] = PPM_GETB(*xP);
-                }
-                data(redrow,   cols);
-                data(greenrow, cols);
-                data(bluerow,  cols);
-                break;
-            /* grayscale */
-            default:
-                for (col = 0, xP = pixelrow; col < cols; col++, xP++)
-                    bluerow[col] = PPM_GETB(*xP);
-                data(bluerow, cols);
-                data(bluerow, cols);
-                data(bluerow, cols);
-                break;
-            }
-        }
-        pm_close(ifp);
+    if (cols > rows) {
+        ROTATEIMG(DOROTATE);                        /* rotate image */
+        if (enlarge * rows > medias.maxcols || enlarge * cols > medias.maxrows)
+            pm_error("Image too large, MaxPixels = %u x %u",
+                     medias.maxrows, medias.maxcols);
+        HPIXELS(cols);
+        VPIXELS(rows);
+        HPIXELSOFF((medias.maxcols/enlarge - rows)/2);
+        VPIXELSOFF((medias.maxrows/enlarge - cols)/2);
+        pm_message("rotating image for output");
+    } else {
+        ROTATEIMG(DONTROTATE);
+        if (enlarge * rows > medias.maxrows || enlarge * cols > medias.maxcols)
+            pm_error("Image too large, MaxPixels = %u x %u",
+                     medias.maxrows, medias.maxcols);
+        HPIXELS(cols);
+        VPIXELS(rows);
+        HPIXELSOFF((medias.maxcols/enlarge - cols)/2);
+        VPIXELSOFF((medias.maxrows/enlarge - rows)/2);
     }
-    else {
-        pixel            **pixelpic;
-        int              colanz, colval;
-        int                 i;
-        colorhist_vector table;
-
-        ppm_readppminit( ifp, &cols, &rows, &maxval, &format );
-        pixelpic = ppm_allocarray( cols, rows );
-        for (row = 0; row < rows; row++)
-            ppm_readppmrow( ifp, pixelpic[row], cols, maxval, format );
-        pm_close(ifp);
-
-        /* first check wether we can use the lut transfer */
+}
 
-        table = ppm_computecolorhist(pixelpic, cols, rows, MAXLUTCOL+1, 
-                                     &colanz);
-        if (table != NULL) {
-            hashinfo *colorhashtable;
 
-            MALLOCARRAY_NOFAIL(colorhashtable, HASHSIZE);
-            for (i=0; i<HASHSIZE; i++) {
-                colorhashtable[i].flag = -1;
-                colorhashtable[i].next = NULL;
-            }
 
-            /* we can use the lookuptable */
-            pm_message("found %d colors - using the lookuptable-method",
-                       colanz);
-            lookuptableinit(sharpness, enlarge, copy, medias);
-            switch(PPM_FORMAT_TYPE(format)) {
-            /* color */
-            case PPM_TYPE:
-                for (colval=0; colval<colanz; colval++) {
-                    cmd('$');
-                    datum(colval);
-                    datum(PPM_GETR((table[colval]).color));
-                    datum(PPM_GETG((table[colval]).color));
-                    datum(PPM_GETB((table[colval]).color));
-
-                    hashrun = &colorhashtable[myhash((table[colval]).color)];
-                    if (hashrun->flag == -1) {
-                        hashrun->color = (table[colval]).color;
-                        hashrun->flag  = colval;
-                    }
-                    else {
-                        while (hashrun->next != NULL)
-                            hashrun = hashrun->next;
-                        MALLOCVAR_NOFAIL(hashrun->next);
-                        hashrun = hashrun->next;
-                        hashrun->color = (table[colval]).color;
-                        hashrun->flag  = colval;
-                        hashrun->next  = NULL;
-                    }
-                }
-                break;
-            /* other */
-            default:
-                for (colval=0; colval<colanz; colval++) {
-                    cmd('$');
-                    datum(colval);
-                    datum(PPM_GETB((table[colval]).color));
-                    datum(PPM_GETB((table[colval]).color));
-                    datum(PPM_GETB((table[colval]).color));
-
-                    hashrun = &colorhashtable[myhash((table[colval]).color)];
-                    if (hashrun->flag == -1) {
-                        hashrun->color = (table[colval]).color;
-                        hashrun->flag  = colval;
-                    }
-                    else {
-                        while (hashrun->next != NULL)
-                            hashrun = hashrun->next;
-                        MALLOCVAR_NOFAIL(hashrun->next);
-                        hashrun = hashrun->next;
-                        hashrun->color = (table[colval]).color;
-                        hashrun->flag  = colval;
-                        hashrun->next  = NULL;
-                    }
-                }
-            }
-            lookuptabledata(cols, rows, enlarge, medias);
-            for (row=0; row<rows; row++) {
-                xP = pixelpic[row];
-                for (col=0; col<cols; col++, xP++) {
-                    hashrun = &colorhashtable[myhash(*xP)];
-                    while (!PPM_EQUAL((hashrun->color), *xP))
-                        if (hashrun->next != NULL)
-                            hashrun = hashrun->next;
-                        else {
-                            pm_error("you just found a lethal bug.");
-                        }
-                    datum(hashrun->flag);
-                }
-            }
-            free(colorhashtable);
-        }
-        else {
-        /* $#%@^!& no lut possible, so send the pic as 24bit */
-            pm_message("found too many colors for fast lookuptable mode");
-            frametransferinit(cols, rows, sharpness, enlarge, copy, medias);
-            switch(PPM_FORMAT_TYPE(format)) {
-            /* color */
-            case PPM_TYPE:
-                COLORDES(RED);
-                DATASTART;                    /* red coming */
-                for (row=0; row<rows; row++) {
-                    xP = pixelpic[row];
-                    for (col=0; col<cols; col++, xP++)
-                        datum(PPM_GETR(*xP));
-                }
-                COLORDES(GREEN);
-                DATASTART;                    /* green coming */
-                for (row=0; row<rows; row++) {
-                    xP = pixelpic[row];
-                    for (col=0; col<cols; col++, xP++)
-                        datum(PPM_GETG(*xP));
-                }
-                COLORDES(BLUE);
-                DATASTART;                    /* blue coming */
-                for (row=0; row<rows; row++) {
-                    xP = pixelpic[row];
-                    for (col=0; col<cols; col++, xP++)
-                        datum(PPM_GETB(*xP));
-                }
-                break;
-            /* grayscale */
-            default:
-                COLORDES(RED);
-                DATASTART;                    /* red coming */
-                for (row=0; row<rows; row++) {
-                    xP = pixelpic[row];
-                    for (col=0; col<cols; col++, xP++)
-                        datum(PPM_GETB(*xP));
-                }
-                COLORDES(GREEN);
-                DATASTART;                    /* green coming */
-                for (row=0; row<rows; row++) {
-                    xP = pixelpic[row];
-                    for (col=0; col<cols; col++, xP++)
-                        datum(PPM_GETB(*xP));
-                }
-                COLORDES(BLUE);
-                DATASTART;                    /* blue coming */
-                for (row=0; row<rows; row++) {
-                    xP = pixelpic[row];
-                    for (col=0; col<cols; col++, xP++)
-                        datum(PPM_GETB(*xP));
-                }
-            }
-        }
-    }
-    PRINTIT;
-    exit(0);
-}
-
-#ifdef __STDC__
-static void lineputinit(int cols, int rows,
-                        int sharpness, int enlarge, int copy,
-                        struct mediasize medias)
-#else /*__STDC__*/
-static int lineputinit(cols, rows, sharpness, enlarge, copy, medias)
-    int cols, rows;
-    int sharpness, enlarge, copy;
-    struct mediasize medias;
-#endif /*__STDC__*/
-{
+static void
+lineputinit(int              const cols,
+            int              const rows,
+            int              const sharpness,
+            int              const enlarge,
+            int              const copy,
+            struct mediasize const medias) {
     ONLINE;
     CLRMEM;
     MEDIASIZE(medias);
@@ -426,18 +134,16 @@ static int lineputinit(cols, rows, sharpness, enlarge, copy, medias)
     }
     check_and_rotate(cols, rows, enlarge, medias);
     DATASTART;
-    return;
 }
 
-#ifdef __STDC__
-static void lookuptableinit(int sharpness, int enlarge, int copy,
-                            struct mediasize medias)
-#else /*__STDC__*/
-static int lookuptableinit(sharpness, enlarge, copy, medias)
-    int sharpness, enlarge, copy;
-    struct mediasize medias;
-#endif /*__STDC__*/
-{
+
+
+static void
+lookuptableinit(int              const sharpness,
+                int              const enlarge,
+                int              const copy,
+                struct mediasize const medias) {
+
     ONLINE;
     CLRMEM;
     MEDIASIZE(medias);
@@ -486,36 +192,31 @@ static int lookuptableinit(sharpness, enlarge, copy, medias)
     }
 
     LOADLOOKUPTABLE;
-    return;
 }
 
-#ifdef __STDC__
-static void lookuptabledata(int cols, int rows, int enlarge,
-                                                        struct mediasize medias)
-#else /*__STDC__*/
-static int lookuptabledata(cols, rows, enlarge, medias)
-    int   rows, cols;
-    int   enlarge;
-    struct mediasize medias;
-#endif /*__STDC__*/
-{
+
+
+static void
+lookuptabledata(int              const cols,
+                int              const rows,
+                int              const enlarge,
+                struct mediasize const medias) {
+
     DONELOOKUPTABLE;
     check_and_rotate(cols, rows, enlarge, medias);
     DATASTART;
-    return;
 }
 
-#ifdef __STDC__
-static void frametransferinit(int cols, int rows, int sharpness,
-                              int enlarge, int copy, struct mediasize medias)
-#else
-static int frametransferinit(cols, rows, sharpness, enlarge, copy, medias)
 
-    int     rows, cols;
-    int     sharpness, enlarge, copy;
-    struct mediasize medias;
-#endif
-{
+
+static void
+frametransferinit(int              const cols,
+                  int              const rows,
+                  int              const sharpness,
+                  int              const enlarge,
+                  int              const copy,
+                  struct mediasize const medias) {
+
     ONLINE;
     CLRMEM;
     MEDIASIZE(medias);
@@ -565,40 +266,411 @@ static int frametransferinit(cols, rows, sharpness, enlarge, copy, medias)
         SHARPNESS(SP_USER);
     }
     check_and_rotate(cols, rows, enlarge, medias);
-    return;
 }
 
 
-#ifdef __STDC__
+
+static void
+colorRow(colorhist_vector const table,
+         unsigned int     const colanz,
+         hashinfo *       const colorhashtable) {
+                
+    unsigned int colval;
+    for (colval = 0; colval < colanz; ++colval) {
+        struct hashinfo * const hashchain =
+            &colorhashtable[myhash((table[colval]).color)];
+
+        struct hashinfo * hashrun;
+
+        cmd('$');
+        datum(colval);
+        datum(PPM_GETR((table[colval]).color));
+        datum(PPM_GETG((table[colval]).color));
+        datum(PPM_GETB((table[colval]).color));
+        
+        hashrun = hashchain;  /* start at beginning of chain */
+
+        if (hashrun->flag == -1) {
+            hashrun->color = (table[colval]).color;
+            hashrun->flag  = colval;
+        } else {
+            while (hashrun->next != NULL)
+                hashrun = hashrun->next;
+            MALLOCVAR_NOFAIL(hashrun->next);
+            hashrun = hashrun->next;
+            hashrun->color = (table[colval]).color;
+            hashrun->flag  = colval;
+            hashrun->next  = NULL;
+        }
+    }
+}
+
+
+
 static void
-check_and_rotate(int cols, int rows, int enlarge, struct mediasize medias)
-#else
-static int
-check_and_rotate(cols, rows, enlarge, medias)
-    int cols, rows, enlarge;
+grayRow(colorhist_vector const table,
+        unsigned int     const colanz,
+        hashinfo *       const colorhashtable) {
+
+    unsigned int colval;
+    for (colval = 0; colval < colanz; ++colval) {
+        struct hashinfo * const hashchain =
+            &colorhashtable[myhash((table[colval]).color)];
+        struct hashinfo * hashrun;
+
+        cmd('$');
+        datum(colval);
+        datum(PPM_GETB((table[colval]).color));
+        datum(PPM_GETB((table[colval]).color));
+        datum(PPM_GETB((table[colval]).color));
+        
+        hashrun = hashchain;  /* start at beginning of chain */
+
+        if (hashrun->flag == -1) {
+            hashrun->color = (table[colval]).color;
+            hashrun->flag  = colval;
+                    }
+        else {
+            while (hashrun->next != NULL)
+                hashrun = hashrun->next;
+            MALLOCVAR_NOFAIL(hashrun->next);
+            hashrun = hashrun->next;
+            hashrun->color = (table[colval]).color;
+            hashrun->flag  = colval;
+            hashrun->next  = NULL;
+        }
+    }
+}
+
+
+
+static void
+useLookupTable(pixel **         const pixels,
+               colorhist_vector const table,
+               int              const sharpness,
+               int              const enlarge,
+               int              const copy,
+               struct mediasize const medias,
+               unsigned int     const cols,
+               unsigned int     const rows,
+               int              const format,
+               unsigned int     const colanz) {
+
+    hashinfo * colorhashtable;
+
+    pm_message("found %u colors - using the lookuptable-method", colanz);
+
+    MALLOCARRAY_NOFAIL(colorhashtable, HASHSIZE);
+    {
+        unsigned int i;
+        for (i = 0; i < HASHSIZE; ++i) {
+            colorhashtable[i].flag = -1;
+                    colorhashtable[i].next = NULL;
+        }
+    }
+
+    lookuptableinit(sharpness, enlarge, copy, medias);
+    switch(PPM_FORMAT_TYPE(format)) {
+    case PPM_TYPE:
+        colorRow(table, colanz, colorhashtable);
+        break;
+    default:
+        grayRow(table, colanz, colorhashtable);
+    }
+    lookuptabledata(cols, rows, enlarge, medias);
+    {
+        unsigned int row;
+        for (row = 0; row < rows; ++row) {
+            unsigned int col;
+            for (col = 0; col < cols; ++col) {
+                pixel * const pixrow = pixels[row];
+                struct hashinfo * const hashchain =
+                    &colorhashtable[myhash(pixrow[col])];
+                struct hashinfo * p;
+                
+                p = hashchain;
+                while (!PPM_EQUAL((p->color), pixrow[col])) {
+                    assert(p->next);
+                    p = p->next;
+                }
+                datum(p->flag);
+            }
+        }
+    }
+    free(colorhashtable);
+}
+
+
+
+static void
+noLookupColor(pixel **     const pixels,
+              unsigned int const cols,
+              unsigned int const rows) {
+
+    unsigned int row;
+    COLORDES(RED);
+    DATASTART;                    /* red coming */
+    for (row = 0; row < rows; ++row) {
+        pixel * const pixrow = pixels[row];
+        unsigned int col;
+        for (col = 0; col < cols; ++col)
+            datum(PPM_GETR(pixrow[col]));
+    }
+    COLORDES(GREEN);
+    DATASTART;                    /* green coming */
+    for (row = 0; row < rows; ++row) {
+        pixel * const pixrow = pixels[row];
+        unsigned int col;
+        for (col = 0; col < cols; ++col)
+            datum(PPM_GETG(pixrow[col]));
+    }
+    COLORDES(BLUE);
+    DATASTART;                    /* blue coming */
+    for (row = 0; row < rows; ++row) {
+        pixel * const pixrow = pixels[row];
+        unsigned int col;
+        for (col = 0; col < cols; ++col)
+            datum(PPM_GETB(pixrow[col]));
+    }
+}
+
+
+
+static void
+noLookupGray(pixel **     const pixels,
+             unsigned int const cols,
+             unsigned int const rows) {
+
+    unsigned int row;
+    COLORDES(RED);
+    DATASTART;                    /* red coming */
+    for (row = 0; row < rows; ++row) {
+        pixel * const pixrow = pixels[row];
+        unsigned int col;
+        for (col = 0; col < cols; ++col)
+            datum(PPM_GETB(pixrow[col]));
+    }
+    COLORDES(GREEN);
+    DATASTART;                    /* green coming */
+    for (row = 0; row < rows; ++row) {
+        pixel * const pixrow = pixels[row];
+        unsigned int col;
+        for (col = 0; col < cols; ++col)
+            datum(PPM_GETB(pixrow[col]));
+    }
+    COLORDES(BLUE);
+    DATASTART;                    /* blue coming */
+    for (row = 0; row < rows; ++row) {
+        pixel * const pixrow = pixels[row];
+        unsigned int col;
+        for (col = 0; col < cols; ++col)
+            datum(PPM_GETB(pixrow[col]));
+    }
+}
+
+
+
+static void
+useNoLookupTable(pixel **         const pixels,
+                 int              const sharpness,
+                 int              const enlarge,
+                 int              const copy,
+                 struct mediasize const medias,
+                 unsigned int     const cols,
+                 unsigned int     const rows,
+                 int              const format) {
+
+    /* $#%@^!& no lut possible, so send the pic as 24bit */
+
+    pm_message("found too many colors for fast lookuptable mode");
+
+    frametransferinit(cols, rows, sharpness, enlarge, copy, medias);
+    switch(PPM_FORMAT_TYPE(format)) {
+    case PPM_TYPE:
+        noLookupColor(pixels, cols, rows);
+        break;
+    default:
+        noLookupGray(pixels, cols, rows);
+    }
+}
+
+
+
+static void
+doTiny(FILE *           const ifP,
+       unsigned int     const cols,
+       unsigned int     const rows,
+       pixval           const maxval,
+       int              const format,
+       int              const sharpness,
+       int              const enlarge,
+       int              const copy,
+       struct mediasize const medias) {
+       
+    pixel * pixelrow;
+    unsigned char * redrow;
+    unsigned char * grnrow;
+    unsigned char * blurow;
+    unsigned int row;
+
+    pixelrow = ppm_allocrow(cols);
+    MALLOCARRAY_NOFAIL(redrow, cols);
+    MALLOCARRAY_NOFAIL(grnrow, cols);
+    MALLOCARRAY_NOFAIL(blurow, cols);
+    lineputinit(cols, rows, sharpness, enlarge, copy, medias);
+
+    for (row = 0; row < rows; ++row) {
+        ppm_readppmrow(ifP, pixelrow, cols, maxval, format);
+        switch(PPM_FORMAT_TYPE(format)) {
+        case PPM_TYPE: {            /* color */
+            unsigned int col;
+            for (col = 0; col < cols; ++col) {
+                redrow[col] = PPM_GETR(pixelrow[col]);
+                grnrow[col] = PPM_GETG(pixelrow[col]);
+                blurow[col] = PPM_GETB(pixelrow[col]);
+            }
+            data(redrow, cols);
+            data(grnrow, cols);
+            data(blurow, cols);
+        } break;
+        default: {           /* grayscale */
+            unsigned int col;
+            for (col = 0; col < cols; ++col)
+                blurow[col] = PPM_GETB(pixelrow[col]);
+            data(blurow, cols);
+            data(blurow, cols);
+            data(blurow, cols);
+            }
+        }
+    }
+}
+
+
+
+int
+main(int argc, char * argv[]) {
+    FILE * ifP;
+    int              argn;
+    bool             dpi300;
+    int              cols, rows, format;
+    pixval           maxval;
+    int              sharpness, enlarge, copy, tiny;
     struct mediasize medias;
-#endif
-{
-    if (cols > rows) {
-        ROTATEIMG(DOROTATE);                        /* rotate image */
-        if (enlarge*rows > medias.maxcols || enlarge*cols > medias.maxrows) {
-            pm_error("Image too large, MaxPixels = %d x %d", medias.maxrows, medias.maxcols);
+    char             media[16];
+    const char * const usage = "[-sharpness <1-4>] [-enlarge <1-3>] [-media <a,a4,as,a4s>] [-copy <1-9>] [-tiny] [-dpi300] [ppmfile]";
+
+    ppm_init(&argc, argv);
+
+    dpi300 = FALSE;
+    argn = 1;
+    sharpness = 32;
+    enlarge   = 1;
+    copy      = 1;
+    memset(media, '\0', 16);
+    tiny      = FALSE;
+
+    /* check for flags */
+    while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
+    if (pm_keymatch(argv[argn], "-sharpness", 2)) {
+        ++argn;
+        if (argn == argc || sscanf(argv[argn], "%d", &sharpness) != 1)
+            pm_usage(usage);
+        else if (sharpness < 1 || sharpness > 4)
+            pm_usage(usage);
         }
-        HPIXELS(cols);
-        VPIXELS(rows);
-        HPIXELSOFF((medias.maxcols/enlarge - rows)/2);
-        VPIXELSOFF((medias.maxrows/enlarge - cols)/2);
-        pm_message("rotating image for output");
+    else if (pm_keymatch(argv[argn], "-enlarge", 2)) {
+        ++argn;
+        if (argn == argc || sscanf(argv[argn], "%d", &enlarge) != 1)
+            pm_usage(usage);
+        else if (enlarge < 1 || enlarge > 3)
+            pm_usage(usage);
+        }
+    else if (pm_keymatch(argv[argn], "-media", 2)) {
+        ++argn;
+        if (argn == argc || sscanf(argv[argn], "%15s", media) < 1)
+            pm_usage(usage);
+        else if (TOUPPER(media[0]) != 'A')
+            pm_usage(usage);
     }
-    else {
-        ROTATEIMG(DONTROTATE);
-        if (enlarge*rows > medias.maxrows || enlarge*cols > medias.maxcols) {
-            pm_error("Image too large, MaxPixels = %d x %d", medias.maxrows, medias.maxcols);
+    else if (pm_keymatch(argv[argn], "-copy", 2)) {
+        ++argn;
+        if (argn == argc || sscanf(argv[argn], "%d", &copy) != 1)
+            pm_usage(usage);
+        else if (copy < 1 || copy > 9)
+            pm_usage(usage);
         }
-        HPIXELS(cols);
-        VPIXELS(rows);
-        HPIXELSOFF((medias.maxcols/enlarge - cols)/2);
-        VPIXELSOFF((medias.maxrows/enlarge - rows)/2);
+    else if (pm_keymatch(argv[argn], "-dpi300", 2))
+        dpi300 = TRUE;
+    else if (pm_keymatch(argv[argn], "-tiny", 2))
+        tiny = TRUE;
+    else
+        pm_usage(usage);
+        ++argn;
     }
+
+    if (argn < argc) {
+        ifP = pm_openr(argv[argn]);
+        ++argn;
+    }
+    else
+        ifP = stdin;
+
+    if (argn != argc)
+        pm_usage(usage);
+
+    if (TOUPPER(media[0]) == 'A')
+        switch (TOUPPER(media[1])) {
+        case 'S':
+            medias = MSize_AS;
+            break;
+        case '4':
+            if(TOUPPER(media[2]) == 'S')
+                medias = MSize_A4S;
+            else {
+                medias = MSize_A4;
+            }
+            break;
+        default:
+            medias = MSize_A;
+        }
+    else
+        medias = MSize_User;
+
+    if (dpi300) {
+        medias.maxcols *= 2;
+        medias.maxrows *= 2;
+    }
+
+    ppm_readppminit(ifP, &cols, &rows, &maxval, &format);
+    
+    if (tiny) {
+        doTiny(ifP, cols, rows, maxval, format,
+               sharpness, enlarge, copy, medias);
+
+    } else {
+        pixel ** pixels;
+        int colanz;
+        colorhist_vector table;
+        unsigned int row;
+
+        pixels = ppm_allocarray(cols, rows);
+        for (row = 0; row < rows; row++)
+            ppm_readppmrow(ifP, pixels[row], cols, maxval, format);
+
+        /* first check wether we can use the lut transfer */
+
+        table = ppm_computecolorhist(pixels, cols, rows, MAXLUTCOL+1, 
+                                     &colanz);
+        if (table)
+            useLookupTable(pixels, table, sharpness, enlarge, copy, medias,
+                           cols, rows, format, colanz);
+        else
+            useNoLookupTable(pixels, sharpness, enlarge, copy, medias,
+                             cols, rows, format);
+        ppm_freearray(pixels, rows);
+    }
+    PRINTIT;
+    pm_close(ifP);
+    return 0;
 }
 
diff --git a/converter/ppm/ppmtomitsu.test b/converter/ppm/ppmtomitsu.test
new file mode 100644
index 00000000..1805838a
--- /dev/null
+++ b/converter/ppm/ppmtomitsu.test
@@ -0,0 +1,12 @@
+echo Test 1.  Should print 3110813682 101562
+./ppmtomitsu ../../testimg.ppm | cksum 
+echo Test 2.  Should print 239186803 34399
+pnmquant 100 ../../testimg.ppm | ./ppmtomitsu | cksum 
+echo Test 3.  Should print 816221676 310
+./ppmtomitsu ../../testgrid.pbm | cksum 
+echo Test 4.  Should print 629834989 752
+./ppmtomitsu -tiny ../../testgrid.pbm | cksum 
+echo Test 5.  Should print 3999654426 101549
+./ppmtomitsu -tiny ../../testimg.ppm | cksum 
+echo Test 2.  Should print 3078685526 101549
+pnmquant 100 ../../testimg.ppm | ./ppmtomitsu -tiny | cksum 
diff --git a/converter/ppm/ppmtompeg/Makefile b/converter/ppm/ppmtompeg/Makefile
index 6db72ea9..e5ad6c58 100644
--- a/converter/ppm/ppmtompeg/Makefile
+++ b/converter/ppm/ppmtompeg/Makefile
@@ -39,7 +39,15 @@ endif
 #
 
 MP_BASE_OBJS = mfwddct.o postdct.o huff.o bitio.o mheaders.o
-MP_ENCODE_OBJS = iframe.o pframe.o bframe.o psearch.o bsearch.o block.o 
+MP_ENCODE_OBJS = \
+  frames.o \
+  iframe.o \
+  pframe.o \
+  bframe.o \
+  psearch.o \
+  bsearch.o \
+  block.o 
+
 MP_OTHER_OBJS = mpeg.o subsample.o param.o rgbtoycc.o \
 	readframe.o combine.o jrevdct.o frame.o fsize.o frametype.o \
 	specifics.o rate.o opts.o input.o gethostname.o
diff --git a/converter/ppm/ppmtompeg/bframe.c b/converter/ppm/ppmtompeg/bframe.c
index 5dfb76d3..1dbc1846 100644
--- a/converter/ppm/ppmtompeg/bframe.c
+++ b/converter/ppm/ppmtompeg/bframe.c
@@ -84,7 +84,6 @@ static struct bframeStats {
  *====================*/
 
 extern Block **dct, **dctr, **dctb;
-extern dct_data_type **dct_data;
 #define NO_MOTION 0
 #define MOTION 1
 #define SKIP 2  /* used in useMotion in dct_data */
diff --git a/converter/ppm/ppmtompeg/bsearch.c b/converter/ppm/ppmtompeg/bsearch.c
index 142987f5..70edfef6 100644
--- a/converter/ppm/ppmtompeg/bsearch.c
+++ b/converter/ppm/ppmtompeg/bsearch.c
@@ -77,6 +77,7 @@
 #include "frames.h"
 #include "motion_search.h"
 #include "fsize.h"
+#include "block.h"
 
 
 /*==================*
diff --git a/converter/ppm/ppmtompeg/frames.c b/converter/ppm/ppmtompeg/frames.c
new file mode 100644
index 00000000..a0764890
--- /dev/null
+++ b/converter/ppm/ppmtompeg/frames.c
@@ -0,0 +1,58 @@
+#include "mallocvar.h"
+#include "fsize.h"
+
+#include "frames.h"
+
+
+Block **dct=NULL, **dctr=NULL, **dctb=NULL;
+dct_data_type   **dct_data; /* used in p/bframe.c */
+
+
+/*===========================================================================*
+ *
+ * AllocDctBlocks
+ *
+ *  allocate memory for dct blocks
+ *
+ * RETURNS: nothing
+ *
+ * SIDE EFFECTS:    creates dct, dctr, dctb
+ *
+ *===========================================================================*/
+void
+AllocDctBlocks(void) {
+
+    int dctx, dcty;
+    int i;
+
+    dctx = Fsize_x / DCTSIZE;
+    dcty = Fsize_y / DCTSIZE;
+
+    MALLOCARRAY(dct, dcty);
+    ERRCHK(dct, "malloc");
+    for (i = 0; i < dcty; ++i) {
+        dct[i] = (Block *) malloc(sizeof(Block) * dctx);
+        ERRCHK(dct[i], "malloc");
+    }
+
+    MALLOCARRAY(dct_data, dcty);
+    ERRCHK(dct_data, "malloc");
+    for (i = 0; i < dcty; ++i) {
+        MALLOCARRAY(dct_data[i], dctx);
+        ERRCHK(dct[i], "malloc");
+    }
+
+    MALLOCARRAY(dctr, dcty/2);
+    ERRCHK(dctr, "malloc");
+    MALLOCARRAY(dctb, dcty/2);
+    ERRCHK(dctb, "malloc");
+    for (i = 0; i < dcty/2; ++i) {
+        MALLOCARRAY(dctr[i], dctx/2);
+        ERRCHK(dctr[i], "malloc");
+        MALLOCARRAY(dctb[i], dctx/2);
+        ERRCHK(dctb[i], "malloc");
+    }
+}
+
+
+
diff --git a/converter/ppm/ppmtompeg/headers/bitio.h b/converter/ppm/ppmtompeg/headers/bitio.h
index 89e61fbb..a24c21cd 100644
--- a/converter/ppm/ppmtompeg/headers/bitio.h
+++ b/converter/ppm/ppmtompeg/headers/bitio.h
@@ -60,9 +60,7 @@
 #define BIT_IO_INCLUDED
 
 
-/*==============*
- * HEADER FILES *
- *==============*/
+#include <stdio.h>
 
 #include "general.h"
 #include "ansi.h"
diff --git a/converter/ppm/ppmtompeg/headers/block.h b/converter/ppm/ppmtompeg/headers/block.h
index 46050492..22d306a1 100644
--- a/converter/ppm/ppmtompeg/headers/block.h
+++ b/converter/ppm/ppmtompeg/headers/block.h
@@ -1,3 +1,46 @@
+#ifndef BLOCK_H_INCLUDED
+
+#include "frame.h"
+#include "mtypes.h"
+
+/* DIFFERENCE FUNCTIONS */
+
+int32
+LumBlockMAD(const LumBlock * const currentBlockP,
+            const LumBlock * const motionBlockP,
+            int32            const bestSoFar);
+
+int32
+LumBlockMSE(const LumBlock * const currentBlockP,
+            const LumBlock * const motionBlockP,
+            int32            const bestSoFar);
+
+int32
+LumMotionError(const LumBlock * const currentBlockP,
+               MpegFrame *      const prev,
+               int              const by,
+               int              const bx,
+               vector           const m,
+               int32            const bestSoFar);
+
+int32
+LumAddMotionError(const LumBlock * const currentBlockP,
+                  const LumBlock * const blockSoFarP,
+                  MpegFrame *      const prev,
+                  int              const by,
+                  int              const bx,
+                  vector           const m,
+                  int32            const bestSoFar);
+
+int32
+LumMotionErrorSubSampled(const LumBlock * const currentBlockP,
+                         MpegFrame *      const prevFrame,
+                         int              const by,
+                         int              const bx,
+                         vector           const m,
+                         int              const startY,
+                         int              const startX);
+
 void
 ComputeDiffDCTs(MpegFrame * const current,
                 MpegFrame * const prev,
@@ -51,3 +94,4 @@ AddBMotionBlock(Block          block,
 void
 BlockifyFrame(MpegFrame * const frameP);
 
+#endif
diff --git a/converter/ppm/ppmtompeg/headers/frame.h b/converter/ppm/ppmtompeg/headers/frame.h
index 6df3d19f..acd74419 100644
--- a/converter/ppm/ppmtompeg/headers/frame.h
+++ b/converter/ppm/ppmtompeg/headers/frame.h
@@ -130,18 +130,4 @@ Frame_Resize(MpegFrame * const omf,
              int         const outsize_x,
              int         const outsize_y);
 
-
-extern void	  Frame_Free _ANSI_ARGS_((MpegFrame * const frame));
-extern void	  Frame_Exit _ANSI_ARGS_((void));
-extern void	  Frame_AllocPPM _ANSI_ARGS_((MpegFrame * frame));
-extern void	  Frame_AllocYCC _ANSI_ARGS_((MpegFrame * const mf));
-extern void	  Frame_AllocDecoded _ANSI_ARGS_((MpegFrame * const frame,
-						  boolean const makeReference));
-extern void	  Frame_AllocHalf _ANSI_ARGS_((MpegFrame * const frame));
-extern void	  Frame_AllocBlocks _ANSI_ARGS_((MpegFrame * const mf));
-extern void	  Frame_Resize _ANSI_ARGS_((MpegFrame * const omf, MpegFrame * const mf,
-					    int const insize_x, int const insize_y,
-					    int const outsize_x, int const outsize_y));
-
-
-#endif /* FRAME_INCLUDED */
+#endif
diff --git a/converter/ppm/ppmtompeg/headers/frames.h b/converter/ppm/ppmtompeg/headers/frames.h
index 14304c48..17820127 100644
--- a/converter/ppm/ppmtompeg/headers/frames.h
+++ b/converter/ppm/ppmtompeg/headers/frames.h
@@ -16,6 +16,7 @@
 #include "ansi.h"
 #include "mtypes.h"
 #include "mheaders.h"
+#include "iframe.h"
 #include "frame.h"
 
 
@@ -86,11 +87,13 @@ typedef struct dct_data_tye_struct {
   int fmotionX, fmotionY, bmotionX, bmotionY;
 } dct_data_type;
 
-void    EncodeYDC _ANSI_ARGS_((int32 const dc_term, int32 * const pred_term, BitBucket * const bb));
-void
-EncodeCDC(int32       const dc_term,
-          int32     * const pred_term,
-          BitBucket * const bb);
+
+/*==================*
+ * GLOBAL VARIABLES *
+ *==================*/
+
+extern Block    **dct, **dctr, **dctb;
+extern dct_data_type **dct_data;
 
 
 /*========*
@@ -101,63 +104,6 @@ EncodeCDC(int32       const dc_term,
 #define int_ceil_div(a,b,c)     ((b*(c = a/b) < a) ? (c+1) : c)
 #define int_floor_div(a,b,c)    ((b*(c = a/b) > a) ? (c-1) : c)
 
-/* assumes many things:
- * block indices are (y,x)
- * variables y_dc_pred, cr_dc_pred, and cb_dc_pred
- * flat block fb exists
- */
-#define GEN_I_BLOCK(frameType, frame, bb, mbAI, qscale) {                   \
-    boolean overflow, overflowChange=FALSE;                             \
-        int overflowValue = 0;                                              \
-        do {                                                                \
-      overflow =  Mpost_QuantZigBlock(dct[y][x], fb[0],                 \
-             qscale, TRUE)==MPOST_OVERFLOW;                     \
-          overflow |= Mpost_QuantZigBlock(dct[y][x+1], fb[1],               \
-                 qscale, TRUE)==MPOST_OVERFLOW;                     \
-      overflow |= Mpost_QuantZigBlock(dct[y+1][x], fb[2],               \
-                         qscale, TRUE)==MPOST_OVERFLOW;                     \
-      overflow |= Mpost_QuantZigBlock(dct[y+1][x+1], fb[3],             \
-                         qscale, TRUE)==MPOST_OVERFLOW;                     \
-      overflow |= Mpost_QuantZigBlock(dctb[y >> 1][x >> 1],             \
-                         fb[4], qscale, TRUE)==MPOST_OVERFLOW;              \
-      overflow |= Mpost_QuantZigBlock(dctr[y >> 1][x >> 1],             \
-             fb[5], qscale, TRUE)==MPOST_OVERFLOW;              \
-          if ((overflow) && (qscale!=31)) {                                 \
-           overflowChange = TRUE; overflowValue++;                          \
-       qscale++;                                                        \
-       } else overflow = FALSE;                                         \
-    } while (overflow);                                                 \
-        Mhead_GenMBHeader(bb,                           \
-            frameType /* pict_code_type */, mbAI /* addr_incr */,   \
-            qscale /* q_scale */,                               \
-            0 /* forw_f_code */, 0 /* back_f_code */,           \
-            0 /* horiz_forw_r */, 0 /* vert_forw_r */,          \
-            0 /* horiz_back_r */, 0 /* vert_back_r */,          \
-            0 /* motion_forw */, 0 /* m_horiz_forw */,          \
-            0 /* m_vert_forw */, 0 /* motion_back */,           \
-            0 /* m_horiz_back */, 0 /* m_vert_back */,          \
-            0 /* mb_pattern */, TRUE /* mb_intra */);           \
-                                        \
-    /* Y blocks */                              \
-        EncodeYDC(fb[0][0], &y_dc_pred, bb);                            \
-    Mpost_RLEHuffIBlock(fb[0], bb);                         \
-    EncodeYDC(fb[1][0], &y_dc_pred, bb);                        \
-        Mpost_RLEHuffIBlock(fb[1], bb);                             \
-    EncodeYDC(fb[2][0], &y_dc_pred, bb);                        \
-    Mpost_RLEHuffIBlock(fb[2], bb);                         \
-    EncodeYDC(fb[3][0], &y_dc_pred, bb);                        \
-    Mpost_RLEHuffIBlock(fb[3], bb);                         \
-                                        \
-    /* CB block */                              \
-    EncodeCDC(fb[4][0], &cb_dc_pred, bb);                   \
-    Mpost_RLEHuffIBlock(fb[4], bb);                     \
-                                        \
-    /* CR block */                              \
-    EncodeCDC(fb[5][0], &cr_dc_pred, bb);                   \
-    Mpost_RLEHuffIBlock(fb[5], bb);                     \
-    if (overflowChange) qscale -= overflowValue;                        \
-    }
-
 #define BLOCK_TO_FRAME_COORD(bx1, bx2, x1, x2) {    \
     x1 = (bx1)*DCTSIZE;             \
     x2 = (bx2)*DCTSIZE;             \
@@ -254,6 +200,9 @@ encodeMotionVector(int      const x,
  *===============================*/
 
 void
+AllocDctBlocks(void);
+
+void
 ComputeBMotionLumBlock(MpegFrame * const prev,
                        MpegFrame * const next,
                        int         const by,
@@ -271,8 +220,6 @@ BMotionSearch(const LumBlock * const currentBlockP,
               motion *         const motionP,
               int              const oldMode);
 
-void GenIFrame (BitBucket * const bb,
-                MpegFrame * const mf);
 void GenPFrame (BitBucket * const bb,
                 MpegFrame * const current,
                 MpegFrame * const prev);
@@ -280,11 +227,6 @@ void GenBFrame (BitBucket * const bb,
                 MpegFrame * const curr,
                 MpegFrame * const prev,
                 MpegFrame * const next);
-void    AllocDctBlocks _ANSI_ARGS_((void ));
-
-
-float
-IFrameTotalTime(void);
 
 float
 PFrameTotalTime(void);
@@ -293,11 +235,6 @@ float
 BFrameTotalTime(void);
 
 void
-ShowIFrameSummary(unsigned int const inputFrameBits, 
-                  unsigned int const totalBits, 
-                  FILE *       const fpointer);
-
-void
 ShowPFrameSummary(unsigned int const inputFrameBits, 
                   unsigned int const totalBits, 
                   FILE *       const fpointer);
@@ -307,87 +244,6 @@ ShowBFrameSummary(unsigned int const inputFrameBits,
                   unsigned int const totalBits, 
                   FILE *       const fpointer);
 
-/* DIFFERENCE FUNCTIONS */
-
-int32
-LumBlockMAD(const LumBlock * const currentBlockP,
-            const LumBlock * const motionBlockP,
-            int32            const bestSoFar);
-
-int32
-LumBlockMSE(const LumBlock * const currentBlockP,
-            const LumBlock * const motionBlockP,
-            int32            const bestSoFar);
-
-int32
-LumMotionError(const LumBlock * const currentBlockP,
-               MpegFrame *      const prev,
-               int              const by,
-               int              const bx,
-               vector           const m,
-               int32            const bestSoFar);
-
-int32
-LumAddMotionError(const LumBlock * const currentBlockP,
-                  const LumBlock * const blockSoFarP,
-                  MpegFrame *      const prev,
-                  int              const by,
-                  int              const bx,
-                  vector           const m,
-                  int32            const bestSoFar);
-
-int32
-LumMotionErrorA(const LumBlock * const currentBlockP,
-                MpegFrame *      const prevFrame,
-                int              const by,
-                int              const bx,
-                vector           const m,
-                int32            const bestSoFar);
-
-int32
-LumMotionErrorB(const LumBlock * const currentP,
-                MpegFrame *      const prevFrame,
-                int              const by,
-                int              const bx,
-                vector           const m,
-                int32            const bestSoFar);
-
-int32
-LumMotionErrorC(const LumBlock * const currentP,
-                MpegFrame *      const prevFrame,
-                int              const by,
-                int              const bx,
-                vector           const m,
-                int32            const bestSoFar);
-
-int32
-LumMotionErrorD(const LumBlock * const currentP,
-                MpegFrame *      const prevFrame,
-                int              const by,
-                int              const bx,
-                vector           const m,
-                int32            const bestSoFar);
-
-int32
-LumMotionErrorSubSampled(const LumBlock * const currentBlockP,
-                         MpegFrame *      const prevFrame,
-                         int              const by,
-                         int              const bx,
-                         vector           const m,
-                         int              const startY,
-                         int              const startX);
-
-void
-BlockComputeSNR(MpegFrame * const current,
-                float *     const snr,
-                float *     const psnr);
-
-int32
-time_elapsed(void);
-
-void
-AllocDctBlocks(void);
-
 /*==================*
  * GLOBAL VARIABLES *
  *==================*/
@@ -413,7 +269,7 @@ extern int  fCodeI,fCodeP,fCodeB;
 extern boolean    forceEncodeLast;
 extern int TIME_RATE;
 
-#endif /* FRAMES_INCLUDED */
+#endif
 
 
 /*
diff --git a/converter/ppm/ppmtompeg/headers/iframe.h b/converter/ppm/ppmtompeg/headers/iframe.h
new file mode 100644
index 00000000..c4f77c74
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/iframe.h
@@ -0,0 +1,118 @@
+#ifndef IFRAME_H_INCLUDED
+#define IFRAME_H_INCLUDED
+
+#include "frame.h"
+
+void
+SetFCode(void);
+
+void
+SetSlicesPerFrame(int const number);
+
+void
+SetBlocksPerSlice(void);
+
+void
+SetIQScale(int const qI);
+
+int
+GetIQScale(void);
+
+void
+GenIFrame(BitBucket * const bb, 
+          MpegFrame * const current);
+
+void
+ResetIFrameStats(void);
+
+float
+IFrameTotalTime(void);
+
+
+void
+ShowIFrameSummary(unsigned int const inputFrameBits, 
+                  unsigned int const totalBits, 
+                  FILE *       const fpointer);
+
+void
+EncodeYDC(int32       const dc_term,
+          int32 *     const pred_term,
+          BitBucket * const bb);
+
+void
+EncodeCDC(int32       const dc_term,
+          int32     * const pred_term,
+          BitBucket * const bb);
+
+void
+BlockComputeSNR(MpegFrame * const current,
+                float *     const snr,
+                float *     const psnr);
+
+void
+WriteDecodedFrame(MpegFrame * const frame);
+
+void
+PrintItoIBitRate(int const numBits,
+                 int const frameNum);
+
+int32 time_elapsed(void);
+
+/* assumes many things:
+ * block indices are (y,x)
+ * variables y_dc_pred, cr_dc_pred, and cb_dc_pred
+ * flat block fb exists
+ */
+#define GEN_I_BLOCK(frameType, frame, bb, mbAI, qscale) {                   \
+    boolean overflow, overflowChange=FALSE;                             \
+        int overflowValue = 0;                                              \
+        do {                                                                \
+      overflow =  Mpost_QuantZigBlock(dct[y][x], fb[0],                 \
+             qscale, TRUE)==MPOST_OVERFLOW;                     \
+          overflow |= Mpost_QuantZigBlock(dct[y][x+1], fb[1],               \
+                 qscale, TRUE)==MPOST_OVERFLOW;                     \
+      overflow |= Mpost_QuantZigBlock(dct[y+1][x], fb[2],               \
+                         qscale, TRUE)==MPOST_OVERFLOW;                     \
+      overflow |= Mpost_QuantZigBlock(dct[y+1][x+1], fb[3],             \
+                         qscale, TRUE)==MPOST_OVERFLOW;                     \
+      overflow |= Mpost_QuantZigBlock(dctb[y >> 1][x >> 1],             \
+                         fb[4], qscale, TRUE)==MPOST_OVERFLOW;              \
+      overflow |= Mpost_QuantZigBlock(dctr[y >> 1][x >> 1],             \
+             fb[5], qscale, TRUE)==MPOST_OVERFLOW;              \
+          if ((overflow) && (qscale!=31)) {                                 \
+           overflowChange = TRUE; overflowValue++;                          \
+       qscale++;                                                        \
+       } else overflow = FALSE;                                         \
+    } while (overflow);                                                 \
+        Mhead_GenMBHeader(bb,                           \
+            frameType /* pict_code_type */, mbAI /* addr_incr */,   \
+            qscale /* q_scale */,                               \
+            0 /* forw_f_code */, 0 /* back_f_code */,           \
+            0 /* horiz_forw_r */, 0 /* vert_forw_r */,          \
+            0 /* horiz_back_r */, 0 /* vert_back_r */,          \
+            0 /* motion_forw */, 0 /* m_horiz_forw */,          \
+            0 /* m_vert_forw */, 0 /* motion_back */,           \
+            0 /* m_horiz_back */, 0 /* m_vert_back */,          \
+            0 /* mb_pattern */, TRUE /* mb_intra */);           \
+                                        \
+    /* Y blocks */                              \
+        EncodeYDC(fb[0][0], &y_dc_pred, bb);                            \
+    Mpost_RLEHuffIBlock(fb[0], bb);                         \
+    EncodeYDC(fb[1][0], &y_dc_pred, bb);                        \
+        Mpost_RLEHuffIBlock(fb[1], bb);                             \
+    EncodeYDC(fb[2][0], &y_dc_pred, bb);                        \
+    Mpost_RLEHuffIBlock(fb[2], bb);                         \
+    EncodeYDC(fb[3][0], &y_dc_pred, bb);                        \
+    Mpost_RLEHuffIBlock(fb[3], bb);                         \
+                                        \
+    /* CB block */                              \
+    EncodeCDC(fb[4][0], &cb_dc_pred, bb);                   \
+    Mpost_RLEHuffIBlock(fb[4], bb);                     \
+                                        \
+    /* CR block */                              \
+    EncodeCDC(fb[5][0], &cr_dc_pred, bb);                   \
+    Mpost_RLEHuffIBlock(fb[5], bb);                     \
+    if (overflowChange) qscale -= overflowValue;                        \
+    }
+
+#endif
diff --git a/converter/ppm/ppmtompeg/headers/motion_search.h b/converter/ppm/ppmtompeg/headers/motion_search.h
index ab83cbca..62f3abab 100644
--- a/converter/ppm/ppmtompeg/headers/motion_search.h
+++ b/converter/ppm/ppmtompeg/headers/motion_search.h
@@ -100,6 +100,9 @@ PMotionSearch(const LumBlock * const currentBlockP,
               int              const bx, 
               vector *         const motionP);
 
+void
+MotionSearchPreComputation(MpegFrame * const frameP);
+
 /*==================*
  * GLOBAL VARIABLES *
  *==================*/
diff --git a/converter/ppm/ppmtompeg/headers/mpeg.h b/converter/ppm/ppmtompeg/headers/mpeg.h
index 23875c2c..56862c42 100644
--- a/converter/ppm/ppmtompeg/headers/mpeg.h
+++ b/converter/ppm/ppmtompeg/headers/mpeg.h
@@ -90,8 +90,9 @@ void
 ReadDecodedRefFrame(MpegFrame *  const frameP, 
                     unsigned int const frameNumber);
 
-extern void	WriteDecodedFrame _ANSI_ARGS_((MpegFrame * const frame));
-extern void	SetBitRateFileName _ANSI_ARGS_((char *fileName));
+void
+SetBitRateFileName(const char * const fileName);
+
 extern void	SetFrameRate _ANSI_ARGS_((void));
 
 
diff --git a/converter/ppm/ppmtompeg/headers/mproto.h b/converter/ppm/ppmtompeg/headers/mproto.h
index c3b0f4b3..d8fefd84 100644
--- a/converter/ppm/ppmtompeg/headers/mproto.h
+++ b/converter/ppm/ppmtompeg/headers/mproto.h
@@ -74,7 +74,6 @@
 #include "bitio.h"
 
 
-#define DCTSIZE2    DCTSIZE*DCTSIZE
 typedef short DCTELEM;
 typedef DCTELEM DCTBLOCK[DCTSIZE2];
 
@@ -111,9 +110,6 @@ void	ReadEYUV _ANSI_ARGS_((MpegFrame * mf, FILE *fpointer, int width,
 boolean	ReadPPM _ANSI_ARGS_((MpegFrame *mf, FILE *fpointer));
 void PPMtoYCC _ANSI_ARGS_((MpegFrame * mf));
 
-void	MotionSearchPreComputation _ANSI_ARGS_((MpegFrame *frame));
-boolean	PMotionSearch _ANSI_ARGS_((LumBlock currentBlock, MpegFrame *prev,
-				   int by, int bx, int *motionY, int *motionX));
 void	ComputeHalfPixelData _ANSI_ARGS_((MpegFrame *frame));
 void mp_validate_size _ANSI_ARGS_((int *x, int *y));
 void AllocYCC _ANSI_ARGS_((MpegFrame * mf));
@@ -126,7 +122,3 @@ void j_rev_dct _ANSI_ARGS_((DCTBLOCK data ));
 void j_rev_dct_sparse _ANSI_ARGS_((DCTBLOCK data , int pos ));
 void j_rev_dct _ANSI_ARGS_((DCTBLOCK data ));
 
-/* block.c */
-void	BlockToData _ANSI_ARGS_((uint8 **data, Block block, int by, int bx));
-void	AddMotionBlock _ANSI_ARGS_((Block block, uint8 **prev, int by, int bx,
-		       int my, int mx));
diff --git a/converter/ppm/ppmtompeg/headers/parallel.h b/converter/ppm/ppmtompeg/headers/parallel.h
index 90edd874..cf27ce66 100644
--- a/converter/ppm/ppmtompeg/headers/parallel.h
+++ b/converter/ppm/ppmtompeg/headers/parallel.h
@@ -87,7 +87,7 @@ void
 NoteFrameDone(int frameStart, int frameEnd);
 
 void
-SetIOConvert(boolean const separate);
+SetIOConvert(bool const separate);
 
 void
 SetRemoteShell(const char * const shell);
diff --git a/converter/ppm/ppmtompeg/headers/prototypes.h b/converter/ppm/ppmtompeg/headers/prototypes.h
index a284888f..b421af35 100644
--- a/converter/ppm/ppmtompeg/headers/prototypes.h
+++ b/converter/ppm/ppmtompeg/headers/prototypes.h
@@ -44,33 +44,26 @@ void    ResetBFrameStats _ANSI_ARGS_((void));
 void    ResetPFrameStats _ANSI_ARGS_((void));
 void SetSearchRange (int const pixelsP,
                      int const pixelsB);
-void    ResetIFrameStats _ANSI_ARGS_((void));
 void
 SetPixelSearch(const char * const searchType);
-void    SetIQScale _ANSI_ARGS_((int const qI));
 void    SetPQScale _ANSI_ARGS_((int qP));
 void    SetBQScale _ANSI_ARGS_((int qB));
-float   EstimateSecondsPerIFrame _ANSI_ARGS_((void));
 float   EstimateSecondsPerPFrame _ANSI_ARGS_((void));
 float   EstimateSecondsPerBFrame _ANSI_ARGS_((void));
 void    SetGOPSize _ANSI_ARGS_((int size));
 void
 SetStatFileName(const char * const fileName);
-void    SetSlicesPerFrame _ANSI_ARGS_((int const number));
-void    SetBlocksPerSlice _ANSI_ARGS_((void));
 
 
 void DCTFrame _ANSI_ARGS_((MpegFrame * mf));
 
 void PPMtoYCC _ANSI_ARGS_((MpegFrame * mf));
 
-void    MotionSearchPreComputation _ANSI_ARGS_((MpegFrame * const frame));
+void    MotionSearchPreComputation _ANSI_ARGS_((MpegFrame *frame));
 
 void    ComputeHalfPixelData _ANSI_ARGS_((MpegFrame *frame));
 void mp_validate_size _ANSI_ARGS_((int *x, int *y));
 
-extern void SetFCode _ANSI_ARGS_((void));
-
 
 /* psearch.c */
 void    ShowPMVHistogram _ANSI_ARGS_((FILE *fpointer));
diff --git a/converter/ppm/ppmtompeg/headers/subsample.h b/converter/ppm/ppmtompeg/headers/subsample.h
new file mode 100644
index 00000000..deedf251
--- /dev/null
+++ b/converter/ppm/ppmtompeg/headers/subsample.h
@@ -0,0 +1,39 @@
+#ifndef SUBSAMPLE_H_INCLUDED
+#define SUBSAMPLE_H_INCLUDED
+
+#include "frame.h"
+#include "mtypes.h"
+
+int32
+LumMotionErrorA(const LumBlock * const currentBlockP,
+                MpegFrame *      const prevFrame,
+                int              const by,
+                int              const bx,
+                vector           const m,
+                int32            const bestSoFar);
+
+int32
+LumMotionErrorB(const LumBlock * const currentP,
+                MpegFrame *      const prevFrame,
+                int              const by,
+                int              const bx,
+                vector           const m,
+                int32            const bestSoFar);
+
+int32
+LumMotionErrorC(const LumBlock * const currentP,
+                MpegFrame *      const prevFrame,
+                int              const by,
+                int              const bx,
+                vector           const m,
+                int32            const bestSoFar);
+
+int32
+LumMotionErrorD(const LumBlock * const currentP,
+                MpegFrame *      const prevFrame,
+                int              const by,
+                int              const bx,
+                vector           const m,
+                int32            const bestSoFar);
+
+#endif
diff --git a/converter/ppm/ppmtompeg/iframe.c b/converter/ppm/ppmtompeg/iframe.c
index f4d7665a..c6735505 100644
--- a/converter/ppm/ppmtompeg/iframe.c
+++ b/converter/ppm/ppmtompeg/iframe.c
@@ -11,10 +11,9 @@
  *  GetIQScale                               *
  *  ResetIFrameStats                             *
  *  ShowIFrameSummary                            *
- *  EstimateSecondsPerIFrame                         *
  *  EncodeYDC                                *
  *  EncodeCDC                                *
- *      time_elapsed                                                         *
+ *  time_elapsed                                                         *
  *                                       *
  *===========================================================================*/
 
@@ -67,6 +66,8 @@
 #include "specifics.h"
 #include "opts.h"
 
+#include "iframe.h"
+
 /*==================*
  * STATIC VARIABLES *
  *==================*/
@@ -128,24 +129,11 @@ int fCodeI, fCodeP, fCodeB;
 boolean printSNR = FALSE;
 boolean printMSE = FALSE;
 boolean decodeRefFrames = FALSE;
-Block **dct=NULL, **dctr=NULL, **dctb=NULL;
-dct_data_type   **dct_data; /* used in p/bframe.c */
 int  TIME_RATE;
 
 
-/*=====================*
- * EXPORTED PROCEDURES *
- *=====================*/
-extern void PrintItoIBitRate _ANSI_ARGS_((int const numBits, int const frameNum));
-
-/*===============================*
- * INTERNAL PROCEDURE prototypes *
- *===============================*/
-void AllocDctBlocks(void );
-int SetFCodeHelper (int const sr);
-void CalcDistortion (MpegFrame * const current, int const y, int const x);
 
-int
+static int
 SetFCodeHelper(int const SR) {
 
     int     range,fCode;
@@ -296,6 +284,68 @@ GetIQScale(void) {
 
 
 
+static void
+CalcDistortion(MpegFrame * const current,
+               int         const y,
+               int         const x) {
+
+    int qscale, distort=0;
+    Block decblk;
+    FlatBlock fblk;
+    int datarate = 0;
+  
+    for (qscale = 1; qscale < 32; qscale ++) {
+        distort = 0;
+        datarate = 0;
+        Mpost_QuantZigBlock(dct[y][x], fblk, qscale, TRUE);
+        Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
+        if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
+        mpeg_jrevdct((int16 *)decblk);
+        distort += mse(current->y_blocks[y][x], decblk);
+
+        Mpost_QuantZigBlock(dct[y][x+1], fblk, qscale, TRUE);
+        Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
+        if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
+        mpeg_jrevdct((int16 *)decblk);
+        distort += mse(current->y_blocks[y][x+1], decblk);
+
+        Mpost_QuantZigBlock(dct[y+1][x], fblk, qscale, TRUE);
+        Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
+        if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
+        mpeg_jrevdct((int16 *)decblk);
+        distort += mse(current->y_blocks[y+1][x], decblk);
+
+        Mpost_QuantZigBlock(dct[y+1][x+1], fblk, qscale, TRUE);
+        Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
+        if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
+        mpeg_jrevdct((int16 *)decblk);
+        distort += mse(current->y_blocks[y+1][x+1], decblk);
+
+        Mpost_QuantZigBlock(dctb[y >> 1][x >> 1], fblk, qscale, TRUE);
+        Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
+        if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
+        mpeg_jrevdct((int16 *)decblk);
+        distort += mse(current->cb_blocks[y>>1][x>>1], decblk);
+
+        Mpost_QuantZigBlock(dctr[y >> 1][x >> 1], fblk, qscale, TRUE);
+        Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
+        if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
+        mpeg_jrevdct((int16 *)decblk);
+        distort += mse(current->cr_blocks[y >> 1][x >> 1], decblk);
+
+        if (!collect_distortion_detailed) {
+            fprintf(distortion_fp, "\t%d\n", distort);
+        } else if (collect_distortion_detailed == 1) {
+            fprintf(distortion_fp, "\t%d\t%d\n", distort, datarate);
+        } else {
+            fprintf(fp_table_rate[qscale-1], "%d\n", datarate);
+            fprintf(fp_table_dist[qscale-1], "%d\n", distort);
+        }
+    }
+}
+
+
+
 /*===========================================================================*
  *
  * GenIFrame
@@ -618,24 +668,6 @@ ShowIFrameSummary(unsigned int const inputFrameBits,
 
 /*===========================================================================*
  *
- * EstimateSecondsPerIFrame
- *
- *  estimates the number of seconds required per I-frame
- *
- * RETURNS: seconds (floating point value)
- *
- * SIDE EFFECTS:    none
- *
- *===========================================================================*/
-float
-EstimateSecondsPerIFrame()
-{
-    return (float)totalTime/((float)TIME_RATE*(float)numFrames);
-}
-
-
-/*===========================================================================*
- *
  * EncodeYDC
  *
  *  Encode the DC portion of a DCT of a luminance block
@@ -926,53 +958,6 @@ PrintItoIBitRate(int const numBits,
 
 
 
-/*===========================================================================*
- *
- * AllocDctBlocks
- *
- *  allocate memory for dct blocks
- *
- * RETURNS: nothing
- *
- * SIDE EFFECTS:    creates dct, dctr, dctb
- *
- *===========================================================================*/
-void
-AllocDctBlocks(void) {
-    int dctx, dcty;
-    int i;
-
-    dctx = Fsize_x / DCTSIZE;
-    dcty = Fsize_y / DCTSIZE;
-
-    dct = (Block **) malloc(sizeof(Block *) * dcty);
-    ERRCHK(dct, "malloc");
-    for (i = 0; i < dcty; i++) {
-        dct[i] = (Block *) malloc(sizeof(Block) * dctx);
-        ERRCHK(dct[i], "malloc");
-    }
-
-    dct_data = (dct_data_type **) malloc(sizeof(dct_data_type *) * dcty);
-    ERRCHK(dct_data, "malloc");
-    for (i = 0; i < dcty; i++) {
-        dct_data[i] = (dct_data_type *) malloc(sizeof(dct_data_type) * dctx);
-        ERRCHK(dct[i], "malloc");
-    }
-
-    dctr = (Block **) malloc(sizeof(Block *) * (dcty >> 1));
-    dctb = (Block **) malloc(sizeof(Block *) * (dcty >> 1));
-    ERRCHK(dctr, "malloc");
-    ERRCHK(dctb, "malloc");
-    for (i = 0; i < (dcty >> 1); i++) {
-        dctr[i] = (Block *) malloc(sizeof(Block) * (dctx >> 1));
-        dctb[i] = (Block *) malloc(sizeof(Block) * (dctx >> 1));
-        ERRCHK(dctr[i], "malloc");
-        ERRCHK(dctb[i], "malloc");
-    }
-}
-
-
-
 /*======================================================================*
  *
  * time_elapsed
@@ -997,66 +982,4 @@ int32 time_elapsed(void) {
 
 
 
-void
-CalcDistortion(MpegFrame * const current,
-               int         const y,
-               int         const x) {
-
-    int qscale, distort=0;
-    Block decblk;
-    FlatBlock fblk;
-    int datarate = 0;
-  
-    for (qscale = 1; qscale < 32; qscale ++) {
-        distort = 0;
-        datarate = 0;
-        Mpost_QuantZigBlock(dct[y][x], fblk, qscale, TRUE);
-        Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
-        if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
-        mpeg_jrevdct((int16 *)decblk);
-        distort += mse(current->y_blocks[y][x], decblk);
-
-        Mpost_QuantZigBlock(dct[y][x+1], fblk, qscale, TRUE);
-        Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
-        if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
-        mpeg_jrevdct((int16 *)decblk);
-        distort += mse(current->y_blocks[y][x+1], decblk);
-
-        Mpost_QuantZigBlock(dct[y+1][x], fblk, qscale, TRUE);
-        Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
-        if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
-        mpeg_jrevdct((int16 *)decblk);
-        distort += mse(current->y_blocks[y+1][x], decblk);
-
-        Mpost_QuantZigBlock(dct[y+1][x+1], fblk, qscale, TRUE);
-        Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
-        if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
-        mpeg_jrevdct((int16 *)decblk);
-        distort += mse(current->y_blocks[y+1][x+1], decblk);
-
-        Mpost_QuantZigBlock(dctb[y >> 1][x >> 1], fblk, qscale, TRUE);
-        Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
-        if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
-        mpeg_jrevdct((int16 *)decblk);
-        distort += mse(current->cb_blocks[y>>1][x>>1], decblk);
-
-        Mpost_QuantZigBlock(dctr[y >> 1][x >> 1], fblk, qscale, TRUE);
-        Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
-        if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
-        mpeg_jrevdct((int16 *)decblk);
-        distort += mse(current->cr_blocks[y >> 1][x >> 1], decblk);
-
-        if (!collect_distortion_detailed) {
-            fprintf(distortion_fp, "\t%d\n", distort);
-        } else if (collect_distortion_detailed == 1) {
-            fprintf(distortion_fp, "\t%d\t%d\n", distort, datarate);
-        } else {
-            fprintf(fp_table_rate[qscale-1], "%d\n", datarate);
-            fprintf(fp_table_dist[qscale-1], "%d\n", distort);
-        }
-    }
-}
-
-
-
 
diff --git a/converter/ppm/ppmtompeg/jpeg.c b/converter/ppm/ppmtompeg/jpeg.c
index 3aad6364..a6e1eced 100644
--- a/converter/ppm/ppmtompeg/jpeg.c
+++ b/converter/ppm/ppmtompeg/jpeg.c
@@ -15,6 +15,7 @@
  * HEADER FILES *
  *==============*/
 #define _XOPEN_SOURCE    /* Make sure stdio.h contains fileno() */
+#include <unistd.h>
 #include <stdio.h>
 #include "all.h"
 /* With the lossless jpeg patch applied to the Jpeg library
diff --git a/converter/ppm/ppmtompeg/mheaders.c b/converter/ppm/ppmtompeg/mheaders.c
index 8a51c089..4cfe49ac 100644
--- a/converter/ppm/ppmtompeg/mheaders.c
+++ b/converter/ppm/ppmtompeg/mheaders.c
@@ -278,24 +278,350 @@ const double VidRateNum[9]={1.0, 23.976, 24.0, 25.0, 29.97, 30.0,
                              50.0 ,59.94, 60.0};
 
 
-/*===============================*
- * INTERNAL PROCEDURE prototypes *
- *===============================*/
-
-static void	GenMBAddrIncr _ANSI_ARGS_((BitBucket *bb, uint32 addr_incr));
-static void	GenPictHead _ANSI_ARGS_((BitBucket *bb, uint32 temp_ref,
-		    uint32 code_type, uint32 vbv_delay,
-		    int32 full_pel_forw_flag, uint32 forw_f_code,
-		    int32 full_pel_back_flag, uint32 back_f_code,
-		    uint8 *extra_info, uint32 extra_info_size,
-		    uint8 *ext_data, uint32 ext_data_size,
-		    uint8 *user_data, uint32 user_data_size));
-static void	GenMBType _ANSI_ARGS_((BitBucket *bb, uint32 pict_code_type,
-		  uint32 mb_quant, uint32 motion_forw, uint32 motion_back,
-		  uint32 mb_pattern, uint32 mb_intra));
-static void	GenMotionCode _ANSI_ARGS_((BitBucket * const bb, int32 const vector));
-static void	GenBlockPattern _ANSI_ARGS_((BitBucket *bb,
-					     uint32 mb_pattern));
+/*=====================*
+ * INTERNAL PROCEDURES *
+ *=====================*/
+
+/*===========================================================================*
+ *
+ * GenMBType
+ *
+ *	generate macroblock type with given attributes
+ *	append result to the specified bitstream
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+GenMBType(bbPtr, pict_code_type, mb_quant, motion_forw, motion_back,
+          mb_pattern, mb_intra)
+    BitBucket *bbPtr;
+    uint32 pict_code_type;
+    uint32 mb_quant;
+    uint32 motion_forw;
+    uint32 motion_back;
+    uint32 mb_pattern;
+    uint32 mb_intra;
+{
+    int code;
+
+    switch (pict_code_type) {
+    case 1:
+        if ((motion_forw != 0) || (motion_back != 0) || (mb_pattern != 0) || (mb_intra != 1)) {
+            perror("Illegal parameters for macroblock type.");
+            exit(-1);
+        }
+        if (mb_quant) {
+            Bitio_Write(bbPtr, 0x1, 2);
+        } else {
+            Bitio_Write(bbPtr, 0x1, 1);
+        }
+        break;
+
+    case 2:
+        code = 0;
+        if (mb_quant) {
+            code += 16;
+        }
+        if (motion_forw) {
+            code += 8;
+        }
+        if (motion_back) {
+            code += 4;
+        }
+        if (mb_pattern) {
+            code += 2;
+        }
+        if (mb_intra) {
+            code += 1;
+        }
+
+        switch (code) {
+        case 1:
+            Bitio_Write(bbPtr, 0x3, 5);
+            break;
+        case 2:
+            Bitio_Write(bbPtr, 0x1, 2);
+            break;
+        case 8:
+            Bitio_Write(bbPtr, 0x1, 3);
+            break;
+        case 10:
+            Bitio_Write(bbPtr, 0x1, 1);
+            break;
+        case 17:
+            Bitio_Write(bbPtr, 0x1, 6);
+            break;
+        case 18:
+            Bitio_Write(bbPtr, 0x1, 5);
+            break;
+        case 26:
+            Bitio_Write(bbPtr, 0x2, 5);
+            break;
+        default:
+            perror("Illegal parameters for macroblock type.");
+            exit(-1);
+            break;
+        }
+        break;
+
+    case 3:
+        code = 0;
+        if (mb_quant) {
+            code += 16;
+        }
+        if (motion_forw) {
+            code += 8;
+        }
+        if (motion_back) {
+            code += 4;
+        }
+        if (mb_pattern) {
+            code += 2;
+        }
+        if (mb_intra) {
+            code += 1;
+        }
+
+        switch (code) {
+        case 12:
+            Bitio_Write(bbPtr, 0x2, 2);
+            break;
+        case 14:
+            Bitio_Write(bbPtr, 0x3, 2);
+            break;
+        case 4:
+            Bitio_Write(bbPtr, 0x2, 3);
+            break;
+        case 6:
+            Bitio_Write(bbPtr, 0x3, 3);
+            break;
+        case 8:
+            Bitio_Write(bbPtr, 0x2, 4);
+            break;
+        case 10:
+            Bitio_Write(bbPtr, 0x3, 4);
+            break;
+        case 1:
+            Bitio_Write(bbPtr, 0x3, 5);
+            break;
+        case 30:
+            Bitio_Write(bbPtr, 0x2, 5);
+            break;
+        case 26:
+            Bitio_Write(bbPtr, 0x3, 6);
+            break;
+        case 22:
+            Bitio_Write(bbPtr, 0x2, 6);
+            break;
+        case 17:
+            Bitio_Write(bbPtr, 0x1, 6);
+            break;
+        default:
+            perror("Illegal parameters for macroblock type.");
+            exit(-1);
+            break;
+        }
+        break;
+    }
+}
+
+
+/*===========================================================================*
+ *
+ * GenMotionCode
+ *
+ *	generate motion vector output with given value
+ *	append result to the specified bitstream
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+GenMotionCode(BitBucket * const bbPtr,
+              int32       const vector) {
+
+    uint32 code, num;
+
+    if ((vector < -16) || (vector > 16)) {
+        perror("Motion vector out of range.");
+        fprintf(stderr, "Motion vector out of range:  vector = %d\n", vector);
+        exit(-1);
+    }
+    code = mbMotionVectorTable[vector + 16][0];
+    num = mbMotionVectorTable[vector + 16][1];
+
+    Bitio_Write(bbPtr, code, num);
+}
+
+
+/*===========================================================================*
+ *
+ * GenBlockPattern
+ *
+ *	generate macroblock pattern output
+ *	append result to the specified bitstream
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+GenBlockPattern(bbPtr, mb_pattern)
+    BitBucket *bbPtr;
+    uint32 mb_pattern;
+{
+    uint32 code, num;
+
+    code = mbPatTable[mb_pattern][0];
+    num = mbPatTable[mb_pattern][1];
+
+    Bitio_Write(bbPtr, code, num);
+}
+
+
+/*===========================================================================*
+ *
+ * GenMBAddrIncr
+ *
+ *	generate macroblock address increment output
+ *	append result to the specified bitstream
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+GenMBAddrIncr(bbPtr, addr_incr)
+    BitBucket *bbPtr;
+    uint32 addr_incr;
+{
+    uint32 code;
+    uint32 num;
+
+    code = mbAddrIncrTable[addr_incr][0];
+    num = mbAddrIncrTable[addr_incr][1];
+
+    Bitio_Write(bbPtr, code, num);
+}
+
+
+/*===========================================================================*
+ *
+ * GenPictHead
+ *
+ *	generate picture header with given attributes
+ *	append result to the specified bitstream
+ *
+ * RETURNS:	nothing
+ *
+ * SIDE EFFECTS:    none
+ *
+ *===========================================================================*/
+static void
+GenPictHead(bbPtr, temp_ref, code_type, vbv_delay, full_pel_forw_flag,
+            forw_f_code, full_pel_back_flag, back_f_code, extra_info,
+            extra_info_size, ext_data, ext_data_size, user_data,
+            user_data_size)
+    BitBucket *bbPtr;
+    uint32 temp_ref;
+    uint32 code_type;
+    uint32 vbv_delay;
+    int32 full_pel_forw_flag;
+    uint32 forw_f_code;
+    int32 full_pel_back_flag;
+    uint32 back_f_code;
+    uint8 *extra_info;
+    uint32 extra_info_size;
+    uint8 *ext_data;
+    uint32 ext_data_size;
+    uint8 *user_data;
+    uint32 user_data_size;
+{
+    /* Write picture start code. */
+    Bitio_Write(bbPtr, PICT_START_CODE, 32);
+
+    /* Temp reference. */
+    Bitio_Write(bbPtr, temp_ref, 10);
+
+    /* Code_type. */
+    if (code_type == 0)
+        code_type = 1;
+
+    Bitio_Write(bbPtr, code_type, 3);
+
+    /* vbv_delay. */
+    vbv_delay = 0xffff;		    /* see page 36 (section 2.4.3.4) */
+    Bitio_Write(bbPtr, vbv_delay, 16);
+
+    if ((code_type == 2) || (code_type == 3)) {
+
+        /* Full pel forw flag. */
+
+        if (full_pel_forw_flag)
+            Bitio_Write(bbPtr, 0x01, 1);
+        else
+            Bitio_Write(bbPtr, 0x00, 1);
+
+        /* Forw f code. */
+
+        Bitio_Write(bbPtr, forw_f_code, 3);
+    }
+    if (code_type == 3) {
+
+        /* Full pel back flag. */
+
+        if (full_pel_back_flag)
+            Bitio_Write(bbPtr, 0x01, 1);
+        else
+            Bitio_Write(bbPtr, 0x00, 1);
+
+        /* Back f code. */
+
+        Bitio_Write(bbPtr, back_f_code, 3);
+    }
+    /* Extra bit picture info. */
+
+    if (extra_info != NULL) {
+        unsigned int i;
+        for (i = 0; i < extra_info_size; ++i) {
+            Bitio_Write(bbPtr, 0x01, 1);
+            Bitio_Write(bbPtr, extra_info[i], 8);
+        }
+    }
+    Bitio_Write(bbPtr, 0x00, 1);
+
+    /* next start code */
+    Bitio_BytePad(bbPtr);
+
+    /* Write ext data if present. */
+
+    if (ext_data != NULL) {
+        unsigned int i;
+
+        Bitio_Write(bbPtr, EXT_START_CODE, 32);
+
+        for (i = 0; i < ext_data_size; ++i)
+            Bitio_Write(bbPtr, ext_data[i], 8);
+        Bitio_BytePad(bbPtr);
+    }
+    /* Write user data if present. */
+    if (user_data != NULL) {
+        unsigned int i;
+        Bitio_Write(bbPtr, USER_START_CODE, 32);
+
+        for (i = 0; i < user_data_size; ++i)
+            Bitio_Write(bbPtr, user_data[i], 8);
+
+        Bitio_BytePad(bbPtr);
+    }
+}
 
 
 /*=====================*
@@ -767,7 +1093,8 @@ if ( addr_incr != 1 )
     }
 
     /* Generate mb type code. */
-    GenMBType(bbPtr, pict_code_type, mb_quant, motion_forw, motion_back, mb_pattern, mb_intra);
+    GenMBType(bbPtr, pict_code_type, mb_quant,
+              motion_forw, motion_back, mb_pattern, mb_intra);
 
     /* MB quant. */
     if (mb_quant) {
@@ -831,353 +1158,6 @@ if ( addr_incr != 1 )
 }
 
 
-/*=====================*
- * INTERNAL PROCEDURES *
- *=====================*/
-
-/*===========================================================================*
- *
- * GenMBType
- *
- *	generate macroblock type with given attributes
- *	append result to the specified bitstream
- *
- * RETURNS:	nothing
- *
- * SIDE EFFECTS:    none
- *
- *===========================================================================*/
-static void
-GenMBType(bbPtr, pict_code_type, mb_quant, motion_forw, motion_back,
-	  mb_pattern, mb_intra)
-    BitBucket *bbPtr;
-    uint32 pict_code_type;
-    uint32 mb_quant;
-    uint32 motion_forw;
-    uint32 motion_back;
-    uint32 mb_pattern;
-    uint32 mb_intra;
-{
-    int code;
-
-    switch (pict_code_type) {
-    case 1:
-	if ((motion_forw != 0) || (motion_back != 0) || (mb_pattern != 0) || (mb_intra != 1)) {
-	    perror("Illegal parameters for macroblock type.");
-	    exit(-1);
-	}
-	if (mb_quant) {
-	    Bitio_Write(bbPtr, 0x1, 2);
-	} else {
-	    Bitio_Write(bbPtr, 0x1, 1);
-	}
-	break;
-
-    case 2:
-	code = 0;
-	if (mb_quant) {
-	    code += 16;
-	}
-	if (motion_forw) {
-	    code += 8;
-	}
-	if (motion_back) {
-	    code += 4;
-	}
-	if (mb_pattern) {
-	    code += 2;
-	}
-	if (mb_intra) {
-	    code += 1;
-	}
-
-	switch (code) {
-	case 1:
-	    Bitio_Write(bbPtr, 0x3, 5);
-	    break;
-	case 2:
-	    Bitio_Write(bbPtr, 0x1, 2);
-	    break;
-	case 8:
-	    Bitio_Write(bbPtr, 0x1, 3);
-	    break;
-	case 10:
-	    Bitio_Write(bbPtr, 0x1, 1);
-	    break;
-	case 17:
-	    Bitio_Write(bbPtr, 0x1, 6);
-	    break;
-	case 18:
-	    Bitio_Write(bbPtr, 0x1, 5);
-	    break;
-	case 26:
-	    Bitio_Write(bbPtr, 0x2, 5);
-	    break;
-	default:
-	    perror("Illegal parameters for macroblock type.");
-	    exit(-1);
-	    break;
-	}
-	break;
-
-    case 3:
-	code = 0;
-	if (mb_quant) {
-	    code += 16;
-	}
-	if (motion_forw) {
-	    code += 8;
-	}
-	if (motion_back) {
-	    code += 4;
-	}
-	if (mb_pattern) {
-	    code += 2;
-	}
-	if (mb_intra) {
-	    code += 1;
-	}
-
-	switch (code) {
-	case 12:
-	    Bitio_Write(bbPtr, 0x2, 2);
-	    break;
-	case 14:
-	    Bitio_Write(bbPtr, 0x3, 2);
-	    break;
-	case 4:
-	    Bitio_Write(bbPtr, 0x2, 3);
-	    break;
-	case 6:
-	    Bitio_Write(bbPtr, 0x3, 3);
-	    break;
-	case 8:
-	    Bitio_Write(bbPtr, 0x2, 4);
-	    break;
-	case 10:
-	    Bitio_Write(bbPtr, 0x3, 4);
-	    break;
-	case 1:
-	    Bitio_Write(bbPtr, 0x3, 5);
-	    break;
-	case 30:
-	    Bitio_Write(bbPtr, 0x2, 5);
-	    break;
-	case 26:
-	    Bitio_Write(bbPtr, 0x3, 6);
-	    break;
-	case 22:
-	    Bitio_Write(bbPtr, 0x2, 6);
-	    break;
-	case 17:
-	    Bitio_Write(bbPtr, 0x1, 6);
-	    break;
-	default:
-	    perror("Illegal parameters for macroblock type.");
-	    exit(-1);
-	    break;
-	}
-	break;
-    }
-}
-
-
-/*===========================================================================*
- *
- * GenMotionCode
- *
- *	generate motion vector output with given value
- *	append result to the specified bitstream
- *
- * RETURNS:	nothing
- *
- * SIDE EFFECTS:    none
- *
- *===========================================================================*/
-static void
-GenMotionCode(BitBucket * const bbPtr,
-              int32       const vector) {
-
-    uint32 code, num;
-
-    if ((vector < -16) || (vector > 16)) {
-	perror("Motion vector out of range.");
-	fprintf(stderr, "Motion vector out of range:  vector = %d\n", vector);
-	exit(-1);
-    }
-    code = mbMotionVectorTable[vector + 16][0];
-    num = mbMotionVectorTable[vector + 16][1];
-
-    Bitio_Write(bbPtr, code, num);
-}
-
-
-/*===========================================================================*
- *
- * GenBlockPattern
- *
- *	generate macroblock pattern output
- *	append result to the specified bitstream
- *
- * RETURNS:	nothing
- *
- * SIDE EFFECTS:    none
- *
- *===========================================================================*/
-static void
-GenBlockPattern(bbPtr, mb_pattern)
-    BitBucket *bbPtr;
-    uint32 mb_pattern;
-{
-    uint32 code, num;
-
-    code = mbPatTable[mb_pattern][0];
-    num = mbPatTable[mb_pattern][1];
-
-    Bitio_Write(bbPtr, code, num);
-}
-
-
-/*===========================================================================*
- *
- * GenMBAddrIncr
- *
- *	generate macroblock address increment output
- *	append result to the specified bitstream
- *
- * RETURNS:	nothing
- *
- * SIDE EFFECTS:    none
- *
- *===========================================================================*/
-static void
-GenMBAddrIncr(bbPtr, addr_incr)
-    BitBucket *bbPtr;
-    uint32 addr_incr;
-{
-    uint32 code;
-    uint32 num;
-
-    code = mbAddrIncrTable[addr_incr][0];
-    num = mbAddrIncrTable[addr_incr][1];
-
-    Bitio_Write(bbPtr, code, num);
-}
-
-
-/*===========================================================================*
- *
- * GenPictHead
- *
- *	generate picture header with given attributes
- *	append result to the specified bitstream
- *
- * RETURNS:	nothing
- *
- * SIDE EFFECTS:    none
- *
- *===========================================================================*/
-static void
-GenPictHead(bbPtr, temp_ref, code_type, vbv_delay, full_pel_forw_flag,
-	    forw_f_code, full_pel_back_flag, back_f_code, extra_info,
-	    extra_info_size, ext_data, ext_data_size, user_data,
-	    user_data_size)
-    BitBucket *bbPtr;
-    uint32 temp_ref;
-    uint32 code_type;
-    uint32 vbv_delay;
-    int32 full_pel_forw_flag;
-    uint32 forw_f_code;
-    int32 full_pel_back_flag;
-    uint32 back_f_code;
-    uint8 *extra_info;
-    uint32 extra_info_size;
-    uint8 *ext_data;
-    uint32 ext_data_size;
-    uint8 *user_data;
-    uint32 user_data_size;
-{
-    int i;
-
-    /* Write picture start code. */
-    Bitio_Write(bbPtr, PICT_START_CODE, 32);
-
-    /* Temp reference. */
-    Bitio_Write(bbPtr, temp_ref, 10);
-
-    /* Code_type. */
-    if (code_type == 0) {
-	code_type = 1;
-    }
-    Bitio_Write(bbPtr, code_type, 3);
-
-    /* vbv_delay. */
-    vbv_delay = 0xffff;		    /* see page 36 (section 2.4.3.4) */
-    Bitio_Write(bbPtr, vbv_delay, 16);
-
-    if ((code_type == 2) || (code_type == 3)) {
-
-	/* Full pel forw flag. */
-
-	if (full_pel_forw_flag) {
-	    Bitio_Write(bbPtr, 0x01, 1);
-	} else {
-	    Bitio_Write(bbPtr, 0x00, 1);
-	}
-
-	/* Forw f code. */
-
-	Bitio_Write(bbPtr, forw_f_code, 3);
-    }
-    if (code_type == 3) {
-
-	/* Full pel back flag. */
-
-	if (full_pel_back_flag) {
-	    Bitio_Write(bbPtr, 0x01, 1);
-	} else {
-	    Bitio_Write(bbPtr, 0x00, 1);
-	}
-
-	/* Back f code. */
-
-	Bitio_Write(bbPtr, back_f_code, 3);
-    }
-    /* Extra bit picture info. */
-
-    if (extra_info != NULL) {
-	for (i = 0; i < extra_info_size; i++) {
-	    Bitio_Write(bbPtr, 0x01, 1);
-	    Bitio_Write(bbPtr, extra_info[i], 8);
-	}
-    }
-    Bitio_Write(bbPtr, 0x00, 1);
-
-    /* next start code */
-    Bitio_BytePad(bbPtr);
-
-    /* Write ext data if present. */
-
-    if (ext_data != NULL) {
-	Bitio_Write(bbPtr, EXT_START_CODE, 32);
-
-	for (i = 0; i < ext_data_size; i++) {
-	    Bitio_Write(bbPtr, ext_data[i], 8);
-	}
-	Bitio_BytePad(bbPtr);
-    }
-    /* Write user data if present. */
-    if (user_data != NULL) {
-	Bitio_Write(bbPtr, USER_START_CODE, 32);
-
-	for (i = 0; i < user_data_size; i++) {
-	    Bitio_Write(bbPtr, user_data[i], 8);
-	}
-	Bitio_BytePad(bbPtr);
-    }
-}
-
-
 #ifdef UNUSED_PROCEDURES
 
 /* GenMBEnd only used for `D` pictures. Shouldn't really ever be called. */
diff --git a/converter/ppm/ppmtompeg/mpeg.c b/converter/ppm/ppmtompeg/mpeg.c
index fafbb97a..de662e88 100644
--- a/converter/ppm/ppmtompeg/mpeg.c
+++ b/converter/ppm/ppmtompeg/mpeg.c
@@ -276,9 +276,8 @@ SetReferenceFrameType(const char * const type) {
 
 
 void
-SetBitRateFileName(fileName)
-    char *fileName;
-{
+SetBitRateFileName(const char * const fileName) {
+
     strcpy(bitRateFileName, fileName);
 }
 
@@ -318,7 +317,7 @@ finishFrameOutput(MpegFrame * const frameP,
 
 static void
 outputIFrame(MpegFrame * const frameP,
-             BitBucket * const bb,
+             BitBucket * const bbP,
              int         const realStart,
              int         const realEnd,
              MpegFrame * const pastRefFrameP,
@@ -326,7 +325,7 @@ outputIFrame(MpegFrame * const frameP,
       
     /* only start a new GOP with I */
     /* don't start GOP if only doing frames */
-    if ((!separateFiles) && (currentGOP >= gopSize)) {
+    if (!separateFiles && currentGOP >= gopSize) {
         boolean const closed = 
             (totalFramesSent == frameP->id || pastRefFrameP == NULL);
 
@@ -344,7 +343,7 @@ outputIFrame(MpegFrame * const frameP,
             }
       
             Mhead_GenSequenceHeader(
-                bb, Fsize_x, Fsize_y,
+                bbP, Fsize_x, Fsize_y,
                 /* pratio */    aspectRatio,
                 /* pict_rate */ frameRate, /* bit_rate */ bit_rate,
                 /* buf_size */  buf_size,  /* c_param_flag */ 1,
@@ -359,7 +358,7 @@ outputIFrame(MpegFrame * const frameP,
                        closed ? "YES" : "NO", frameP->id);
     
         ++num_gop;
-        Mhead_GenGOPHeader(bb,  /* drop_frame_flag */ 0,
+        Mhead_GenGOPHeader(bbP,  /* drop_frame_flag */ 0,
                            tc_hrs, tc_min, tc_sec, tc_pict,
                            closed, /* broken_link */ 0,
                            /* ext_data */ NULL, /* ext_data_size */ 0,
@@ -368,16 +367,16 @@ outputIFrame(MpegFrame * const frameP,
         if (pastRefFrameP == NULL)
             SetGOPStartTime(0);
         else
-            SetGOPStartTime(pastRefFrameP->id+1);
+            SetGOPStartTime(pastRefFrameP->id + 1);
     }
       
-    if ((frameP->id >= realStart) && (frameP->id <= realEnd))
-        GenIFrame(bb, frameP);
+    if (frameP->id >= realStart && frameP->id <= realEnd)
+        GenIFrame(bbP, frameP);
       
-    numI--;
+    --numI;
     timeMask &= 0x6;
       
-    currentGOP++;
+    ++currentGOP;
     IncrementTCTime();
 }
 
@@ -393,10 +392,10 @@ outputPFrame(MpegFrame * const frameP,
     if ((frameP->id >= realStart) && (frameP->id <= realEnd))
         GenPFrame(bbP, frameP, pastRefFrameP);
 
-    numP--;
+    --numP;
     timeMask &= 0x5;
     
-    currentGOP++;
+    ++currentGOP;
     IncrementTCTime();
 }
 
@@ -498,6 +497,9 @@ processBFrames(MpegFrame *          const pastRefFrameP,
 
    But do only those B frames whose frame numbers are within the range
    'realStart' through 'realEnd'.
+
+   Output the frames to the output stream 'wholeStreamBbP'.  If NULL,
+   output each frame to its own individual file instead.
 -----------------------------------------------------------------------------*/
     boolean const separateFiles = (wholeStreamBbP == NULL);
     unsigned int const firstBFrameNum = pastRefFrameP->id + 1;
@@ -551,7 +553,7 @@ processBFrames(MpegFrame *          const pastRefFrameP,
 
 static void
 processRefFrame(MpegFrame *    const frameP, 
-                BitBucket *    const bb_arg,
+                BitBucket *    const wholeStreamBbP,
                 int            const realStart,
                 int            const realEnd,
                 MpegFrame *    const pastRefFrameP,
@@ -564,26 +566,28 @@ processRefFrame(MpegFrame *    const frameP,
 
    But only if its frame number is within the range 'realStart'
    through 'realEnd'.
+
+   Output the frame to the output stream 'wholeStreamBbP'.  If NULL,
+   output it to its own individual file instead.
 -----------------------------------------------------------------------------*/
     if (frameP->id >= realStart && frameP->id <= realEnd) {
-        boolean separateFiles;
-        BitBucket * bb;
+        bool const separateFiles = (wholeStreamBbP == NULL);
   
-        separateFiles = (bb_arg == NULL);
+        BitBucket * bbP;
   
-        if ( separateFiles )
-            bb = bitioNew(outputFileName, frameP->id, remoteIO);
+        if (separateFiles)
+            bbP = bitioNew(outputFileName, frameP->id, remoteIO);
         else
-            bb = bb_arg;
+            bbP = wholeStreamBbP;
   
         /* first, output this reference frame */
         switch (frameP->type) {
         case TYPE_IFRAME:
-            outputIFrame(frameP, bb, realStart, realEnd, pastRefFrameP, 
+            outputIFrame(frameP, bbP, realStart, realEnd, pastRefFrameP, 
                          separateFiles);
             break;
         case TYPE_PFRAME:
-            outputPFrame(frameP, bb, realStart, realEnd, pastRefFrameP);
+            outputPFrame(frameP, bbP, realStart, realEnd, pastRefFrameP);
             ShowRemainingTime(childProcess);
             break;
         default:
@@ -593,7 +597,7 @@ processRefFrame(MpegFrame *    const frameP,
         
         ++(*framesOutputP);
         
-        finishFrameOutput(frameP, bb, separateFiles, referenceFrame,
+        finishFrameOutput(frameP, bbP, separateFiles, referenceFrame,
                           childProcess, remoteIO);
     }
 }
@@ -702,7 +706,7 @@ readAndSaveFrame(struct inputSource * const inputSourceP,
 static void
 doFirstFrameStuff(enum frameContext const context,
                   const char *      const userDataFileName,
-                  BitBucket *       const bb,
+                  BitBucket *       const bbP,
                   int               const fsize_x,
                   int               const fsize_y,
                   int               const aspectRatio,
@@ -713,8 +717,12 @@ doFirstFrameStuff(enum frameContext const context,
 /*----------------------------------------------------------------------------
    Do stuff we have to do after reading the first frame in a sequence
    of frames requested of GenMPEGStream().
+
+   *bbP is the output stream to which to write any header stuff we have
+   to write.  If 'context' is such that there is no header stuff to write,
+   then 'bbP' is irrelevant.
 -----------------------------------------------------------------------------*/
-    *inputFrameBitsP = 24*Fsize_x*Fsize_y;
+    *inputFrameBitsP = 24 * Fsize_x * Fsize_y;
     SetBlocksPerSlice();
           
     if (context == CONTEXT_WHOLESTREAM) {
@@ -722,7 +730,7 @@ doFirstFrameStuff(enum frameContext const context,
         char * userData;
         unsigned int userDataSize;
 
-        assert(bb != NULL);
+        assert(bbP != NULL);
 
         DBG_PRINT(("Generating sequence header\n"));
         if (bitstreamMode == FIXED_RATE) {
@@ -770,7 +778,7 @@ doFirstFrameStuff(enum frameContext const context,
             userDataSize = strlen(userData);
             strfree(userDataString);
         }
-        Mhead_GenSequenceHeader(bb, Fsize_x, Fsize_y,
+        Mhead_GenSequenceHeader(bbP, Fsize_x, Fsize_y,
                                 /* pratio */ aspectRatio,
                                 /* pict_rate */ frameRate, 
                                 /* bit_rate */ bit_rate,
@@ -990,13 +998,21 @@ doAFrame(unsigned int         const frameNumber,
          unsigned int *       const framesReadP,
          unsigned int *       const framesOutputP,
          bool *               const firstFrameDoneP,
-         BitBucket *          const bbP,
+         BitBucket *          const wholeStreamBbP,
          unsigned int *       const inputFrameBitsP,
          bool *               const endOfStreamP) {
 /*----------------------------------------------------------------------------
    *endOfStreamP returned means we were unable to do a frame because
    the input stream has ended.  In that case, none of the other outputs
    are valid.
+
+   Process an input frame.  This can involve writing its description
+   to the output stream, saving it for later use, and/or writing
+   descriptions of previously saved frames to the output stream
+   because we now have enough information to do so.
+
+   Output the frames to the output stream 'wholeStreamBbP'.  If NULL,
+   output each frame to its own individual file instead.
 -----------------------------------------------------------------------------*/
     char const frameType = FType_Type(frameNumber);
     
@@ -1026,21 +1042,21 @@ doAFrame(unsigned int         const frameNumber,
             *endOfStreamP = FALSE;
 
             if (!*firstFrameDoneP) {
-                doFirstFrameStuff(context, userDataFileName,
-                                  bbP, Fsize_x, Fsize_y, aspectRatio,
+                doFirstFrameStuff(context, userDataFileName, wholeStreamBbP,
+                                  Fsize_x, Fsize_y, aspectRatio,
                                   frameRate, qtable, niqtable, 
                                   inputFrameBitsP);
             
                 *firstFrameDoneP = TRUE;
             }
-            processRefFrame(frameP, bbP, frameStart, frameEnd,
+            processRefFrame(frameP, wholeStreamBbP, frameStart, frameEnd,
                             pastRefFrameP, childProcess, outputFileName, 
                             framesReadP, framesOutputP);
                 
             if (pastRefFrameP) {
                 processBFrames(pastRefFrameP, frameP, realStart, realEnd,
                                inputSourceP, remoteIO, childProcess, 
-                               &IOtime, bbP, outputFileName,
+                               &IOtime, wholeStreamBbP, outputFileName,
                                framesReadP, framesOutputP, &currentGOP);
             }
             if (pastRefFrameP != NULL)
@@ -1086,17 +1102,20 @@ GenMPEGStream(struct inputSource * const inputSourceP,
    we stop where the stream ends if that is before 'frameEnd'.
 
 -----------------------------------------------------------------------------*/
-    BitBucket * bbP;
+    BitBucket * streamBbP;
+        /* The output stream to which we write all the frames.  NULL
+           means the frames are going to individual frame files.
+        */
     unsigned int frameNumber;
     bool endOfStream;
     bool firstFrameDone;
     int numBits;
     unsigned int firstFrame, lastFrame;
-    /* Frame numbers of the first and last frames we look at.  This
-       could be more than the the frames we actually encode because
-       we may need context (i.e. to encode a B frame, we need the subsequent
-       I or P frame).
-    */
+        /* Frame numbers of the first and last frames we look at.
+           This could be more than the the frames we actually encode
+           because we may need context (i.e. to encode a B frame, we
+           need the subsequent I or P frame).
+        */
     unsigned int framesRead;
         /* Number of frames we have read; for statistical purposes */
     MpegFrame * pastRefFrameP;
@@ -1150,10 +1169,10 @@ GenMPEGStream(struct inputSource * const inputSourceP,
     if (showBitRatePerFrame)
         OpenBitRateFile();  /* May modify showBitRatePerFrame */
 
-    if (context == CONTEXT_WHOLESTREAM || context == CONTEXT_GOP)
-        bbP = Bitio_New(ofP);
+    if (context == CONTEXT_JUSTFRAMES)
+        streamBbP = NULL;
     else
-        bbP = NULL;
+        streamBbP = Bitio_New(ofP);
 
     initTCTime(firstFrame);
 
@@ -1171,7 +1190,7 @@ GenMPEGStream(struct inputSource * const inputSourceP,
                  frameStart, frameEnd, realStart, realEnd,
                  childProcess, outputFileName,
                  pastRefFrameP, &pastRefFrameP,
-                 &framesRead, &framesOutput, &firstFrameDone, bbP,
+                 &framesRead, &framesOutput, &firstFrameDone, streamBbP,
                  inputFrameBitsP, &endOfStream);
     }
     
@@ -1180,10 +1199,10 @@ GenMPEGStream(struct inputSource * const inputSourceP,
     
     /* SEQUENCE END CODE */
     if (context == CONTEXT_WHOLESTREAM)
-        Mhead_GenSequenceEnder(bbP);
+        Mhead_GenSequenceEnder(streamBbP);
     
-    if (context == CONTEXT_WHOLESTREAM)
-        numBits = bbP->cumulativeBits;
+    if (streamBbP)
+        numBits = streamBbP->cumulativeBits;
     else {
         /* What should the correct value be?  Most likely 1.  "numBits" is
            used below, so we need to make sure it's properly initialized 
@@ -1192,9 +1211,8 @@ GenMPEGStream(struct inputSource * const inputSourceP,
         numBits = 1;
     }
 
-    if (context != CONTEXT_JUSTFRAMES) {
-        Bitio_Flush(bbP);
-        bbP = NULL;
+    if (streamBbP) {
+        Bitio_Flush(streamBbP);
         fclose(ofP);
     }
     handleBitRate(realEnd, numBits, childProcess, showBitRatePerFrame);
diff --git a/converter/ppm/ppmtompeg/pframe.c b/converter/ppm/ppmtompeg/pframe.c
index e72fe5d6..de91e32c 100644
--- a/converter/ppm/ppmtompeg/pframe.c
+++ b/converter/ppm/ppmtompeg/pframe.c
@@ -60,8 +60,6 @@ static int32    totalTime = 0;
 static int      qscaleP;
 static float    totalSNR = 0.0;
 static float    totalPSNR = 0.0;
-extern Block    **dct, **dctr, **dctb;
-extern dct_data_type   **dct_data;
 
 /*=====================*
  * INTERNAL PROCEDURES *
diff --git a/converter/ppm/ppmtompeg/psearch.c b/converter/ppm/ppmtompeg/psearch.c
index aea1a29b..83c62d04 100644
--- a/converter/ppm/ppmtompeg/psearch.c
+++ b/converter/ppm/ppmtompeg/psearch.c
@@ -16,6 +16,8 @@
 #include "prototypes.h"
 #include "fsize.h"
 #include "param.h"
+#include "subsample.h"
+#include "block.h"
 
 
 /*==================*
diff --git a/converter/ppm/ppmtompeg/subsample.c b/converter/ppm/ppmtompeg/subsample.c
index 5ec71814..69401a1d 100644
--- a/converter/ppm/ppmtompeg/subsample.c
+++ b/converter/ppm/ppmtompeg/subsample.c
@@ -43,6 +43,7 @@
 #include "bitio.h"
 #include "prototypes.h"
 
+#include "subsample.h"
 
 
 static void
diff --git a/converter/ppm/ppmtopict.c b/converter/ppm/ppmtopict.c
index e2428fb6..22456857 100644
--- a/converter/ppm/ppmtopict.c
+++ b/converter/ppm/ppmtopict.c
@@ -282,15 +282,8 @@ int i;
 	(void) putc(i & 0xff, fd);
 }
 
-#if __STDC__
 static void
 putLong( FILE *fd, long i )
-#else /*__STDC__*/
-static void
-putLong(fd, i)
-FILE *fd;
-long i;
-#endif /*__STDC__*/
 {
 	(void) putc((int)((i >> 24) & 0xff), fd);
 	(void) putc(((int)(i >> 16) & 0xff), fd);
diff --git a/converter/ppm/sldtoppm.c b/converter/ppm/sldtoppm.c
index 6b51f291..e0760448 100644
--- a/converter/ppm/sldtoppm.c
+++ b/converter/ppm/sldtoppm.c
@@ -66,15 +66,9 @@ struct svector {
     struct spoint t;          /* To point */
 };
 
-static int extend ARGS((smallint ch));
-static int sli ARGS((void));
-static int slib ARGS((void));
-static void vscale ARGS((int *px, int *py));
-static void slider ARGS((void (*slvec) ARGS((struct svector *vec, int color)),
-                    void (*slflood) ARGS((struct spolygon *poly, int color)) ));
-static void slidefind ARGS((char *sname, int dironly, int ucasen));
-static void draw ARGS((struct svector *vec, int color));
-static void flood ARGS((struct spolygon *const poly, int const color));
+typedef void (slvecfn)(struct svector * vec, int color);
+typedef void (slfloodfn)(struct spolygon * poly, int color);
+
 
 static int ixdots, iydots;        /* Screen size in dots */
 static FILE *slfile;              /* Slide file descriptor */
@@ -104,21 +98,26 @@ static int adjust = FALSE;        /* Adjust to correct aspect ratio ? */
 static struct slhead slfrof;          /* Slide file header */
 static long xfac, yfac;           /* Aspect ratio scale factors */
 
-static int sdrawkcab;             /* Slide drawing kinematic conversion of
-                     ass-backwards data flag */
+static int sdrawkcab;
+    /* Slide drawing kinematic conversion of ass-backwards data flag */
+
+
 
 /*  EXTEND  --  Turn a smallint into an int with sign extension, whether
-        or not that happens automatically.  */
+    or not that happens automatically.
+*/
 
-static int extend(smallint ch)
-{
+static int
+extend(smallint ch) {
     return ((int) ((ch & 0x80) ? (ch | ~0xFF) : ch));
 }
 
+
+
 /*  SLI  --  Input word from slide file  */
 
-static int sli()
-{
+static int
+sli(void) {
     short wd;
 
     if (fread(&wd, sizeof wd, 1, slfile) != 1) {
@@ -131,10 +130,12 @@ static int sli()
     return wd;
 }
 
+
+
 /*  SLIB  --  Input byte from slide file  */
 
-static int slib()
-{
+static int 
+slib(void) {
     smallint ch = 0;
 
     if (fread(&ch, sizeof ch, 1, slfile) != 1) {
@@ -143,25 +144,171 @@ static int slib()
     return extend(ch);
 }
 
+
+
 /*  VSCALE -- scale screen coordinates for mismatched display.  */
 
-static void vscale(px, py)
-  int *px, *py;
-{
+static void
+vscale(int * const px,
+       int * const py) {
+
     *px = (((unsigned) *px) * xfac) >> 16;
     *py = (((unsigned) *py) * yfac) >> 16;
 }
 
+
+
+/*  SLIDEFIND  --  Find  a  slide  in  a  library  or,  if  DIRONLY is
+           nonzero, print a directory listing of the  library.
+           If  UCASEN  is nonzero, the requested slide name is
+           converted to upper case. */
+
+static void
+slidefind(const char * const sname,
+          bool         const dironly,
+          bool         const ucasen) {
+
+    char uname[32];
+    unsigned char libent[36];
+    long pos;
+
+    if (dironly)
+        pm_message("Slides in library:");
+    else {
+        int i;
+        const char * ip;
+        
+        ip = sname; /* initial value */
+        
+        for (i = 0; i < 31; i++) {
+            char ch = *ip++;
+            if (ch == EOS)
+                break;
+            if (ucasen && ISLOWER(ch))
+                ch = TOUPPER(ch);
+            uname[i] = ch;
+        }
+        uname[i] = EOS;
+    }
+    
+    /* Read slide library header and verify. */
+    
+    if ((fread(libent, 32, 1, slfile) != 1) ||
+        (!STREQ((char *)libent, "AutoCAD Slide Library 1.0\015\012\32"))) {
+        pm_error("not an AutoCAD slide library file.");
+    }
+    pos = 32;
+    
+    /* Search for a slide with the requested name. */
+    
+    while (TRUE) {
+        if ((fread(libent, 36, 1, slfile) != 1) ||
+            (strlen((char *)libent) == 0)) {
+            if (dironly) {
+                return;
+            }
+            pm_error("slide %s not in library.", sname);
+        }
+        pos += 36;
+        if (dironly) {
+            pm_message("  %s", libent);
+        } else if (STREQ((char *)libent, uname)) {
+            long dpos = (((((libent[35] << 8) | libent[34]) << 8) |
+                          libent[33]) << 8) | libent[32];
+            if ((slfile == stdin) || (fseek(slfile, dpos, 0) == -1)) {
+                dpos -= pos;
+        
+                while (dpos-- > 0)
+                    getc(slfile);
+            }
+            break;
+        }
+    }
+}
+
+
+
+/*  DRAW  --  Draw a vector in the given AutoCAD color.  */
+
+static slvecfn draw;
+
+static void
+draw(struct svector * vec,
+     int              color) {
+
+    pixel rgbcolor;
+
+    if (blither) {
+        pm_message("Vector (%d, %d) - (%d, %d)  Color %d",
+           vec->f.x, vec->f.y, vec->t.x, vec->t.y, color);
+    }
+    assert(vec->f.x >= 0 && vec->f.x < pixcols);
+    assert(vec->f.y >= 0 && vec->f.y < pixrows);
+    assert(vec->t.x >= 0 && vec->t.x < pixcols);
+    assert(vec->t.y >= 0 && vec->t.y < pixrows);
+    PPM_ASSIGN(rgbcolor,
+               acadcol[color][0], acadcol[color][1], acadcol[color][2]);
+    ppmd_line(pixels, pixcols, pixrows, pixmaxval,
+              vec->f.x, iydots - vec->f.y, vec->t.x, iydots - vec->t.y,
+              PPMD_NULLDRAWPROC,
+              (char *) &rgbcolor);
+}
+
+
+
+/*  FLOOD  --  Draw a filled polygon.  */
+
+static slfloodfn flood;
+
+static void
+flood(struct spolygon * const poly,
+      int               const color) {
+
+    unsigned int i;
+    struct fillobj * handle;
+    pixel rgbcolor;
+
+    handle = ppmd_fill_create();
+
+    if (blither) {
+        unsigned int i;
+        pm_message("Polygon: %d points, fill type %d, color %d",
+                   poly->npoints, poly->fill, color);
+        for (i = 0; i < poly->npoints; i++) {
+            pm_message("   Point %d:  (%d, %d)", i + 1,
+                       poly->pt[i].x, poly->pt[i].y);
+        }
+    }
+
+    PPM_ASSIGN(rgbcolor,
+               acadcol[color][0], acadcol[color][1], acadcol[color][2]);
+    for (i = 0; i < poly->npoints; i++) {
+        assert(poly->pt[i].x >= 0 && poly->pt[i].x < pixcols);
+        assert(poly->pt[i].y >= 0 && poly->pt[i].y < pixrows);
+        ppmd_line(pixels, pixcols, pixrows, pixmaxval,
+                  poly->pt[i].x, iydots - poly->pt[i].y, 
+                  poly->pt[(i + 1) % poly->npoints].x,
+                  iydots - poly->pt[(i + 1) % poly->npoints].y,
+                  ppmd_fill_drawproc, handle);
+    }
+    ppmd_fill(pixels, pixcols, pixrows, pixmaxval,
+              handle, PPMD_NULLDRAWPROC, (char *) &rgbcolor);
+    
+    ppmd_fill_destroy(handle);
+}
+
+
+
 /*  SLIDER  --  Read slide file.  This is called with the name of the
         file to be read and function pointers to the routines
         which process vectors and polygon fill requests
         respectively.
 */
 
-static void slider(slvec, slflood)
-  void (*slvec) ARGS((struct svector *vec, int color));
-  void (*slflood) ARGS((struct spolygon *poly, int color));
-{
+static void
+slider(slvecfn   slvec,
+       slfloodfn slflood) {
+
     int i, rescale;
     unsigned char ubfr[4];        /* Utility character buffer */
     int lx, ly;               /* Last x and y point */
@@ -174,14 +321,14 @@ static void slider(slvec, slflood)
     short rtest;              /* Value to test byte reversal */
     short btest = 0x1234;         /* Value to test byte-reversal */
     static struct slhead slhi =       /* Master slide header sample */
-        {"AutoCAD Slide\r\n\32", 86,2, 0,0, 0.0, 0};
+    {"AutoCAD Slide\r\n\32", 86,2, 0,0, 0.0, 0};
     int curcolor = 7;             /* Current vector color */
     pixel rgbcolor;           /* Pixel used to clear pixmap */
-
+    
     lx = ly = 32000;
-
+    
     /* Process the header of the slide file.  */
-
+    
     sdrawkcab = FALSE;            /* Initially guess byte order is OK */
     fread(slfrof.slh, 17, 1, slfile);
     fread(&slfrof.sntype, sizeof(char), 1, slfile);
@@ -194,48 +341,46 @@ static void slider(slvec, slflood)
 
     /* Verify that slide format is compatible with this program. */
 
-    if (STREQ(slfrof.slh, slhi.slh)) {
+    if (STREQ(slfrof.slh, slhi.slh))
         pm_error("this is not an AutoCAD slide file.");
-    }
 
     /* Verify that the number format and file level in the header  are
        compatible.  All slides written by versions of AutoCAD released
        since September of 1987 are compatible with this format.  */
 
-    if ((slfrof.sntype != slhi.sntype) || (slfrof.slevel != slhi.slevel)) {
+    if ((slfrof.sntype != slhi.sntype) || (slfrof.slevel != slhi.slevel))
         pm_error("incompatible slide file format");
-    }
 
     /* Build SDSAR value from long scaled version. */
-
+    
     ldsar = 0L;
-    for (i = 3; i >= 0; i--) {
-    ldsar = (ldsar << 8) | ubfr[i];
-    }
+    for (i = 3; i >= 0; --i)
+        ldsar = (ldsar << 8) | ubfr[i];
     slfrof.sdsar = ((double) ldsar) / 1E7;
-
+    
     /* Examine the byte order test value.   If it's backwards, set the
        byte-reversal flag and correct all of the values we've read  in
-       so far. */
+       so far.
+    */
 
     if (btest != rtest) {
-    sdrawkcab = TRUE;
+        sdrawkcab = TRUE;
 #define rshort(x) x = ((x >> 8) & 0xFF) | (x << 8)
-    rshort(slfrof.sxdots);
-    rshort(slfrof.sydots);
-    rshort(slfrof.shwfill);
+        rshort(slfrof.sxdots);
+        rshort(slfrof.sydots);
+        rshort(slfrof.shwfill);
 #undef rshort
     }
-
+    
     /* Dump the header if we're blithering. */
 
     if (blither || info) {
         pm_message("Slide file type %d, level %d, hwfill type %d.",
-        slfrof.sntype, slfrof.slevel, slfrof.shwfill);
+                   slfrof.sntype, slfrof.slevel, slfrof.shwfill);
         pm_message("Original screen size %dx%d, aspect ratio %.3f.",
-        slfrof.sxdots + 1, slfrof.sydots + 1, slfrof.sdsar);
+                   slfrof.sxdots + 1, slfrof.sydots + 1, slfrof.sdsar);
         pm_message("Byte order is %s.",
-            sdrawkcab ? "being reversed" : "the same");
+                   sdrawkcab ? "being reversed" : "the same");
     }
 
     /* If the display aspect ratio indicates that the  pixels  on  the
@@ -246,405 +391,284 @@ static void slider(slvec, slflood)
        We  always  correct  the aspect ratio by adjusting the width of
        the image.  This guarantees that output from the SHADE command,
        which  is  essentially  scan-line  data written in vector form,
-       will not be corrupted. */
+       will not be corrupted.
+    */
 
     dsar = ((double) slfrof.sxdots) / slfrof.sydots;
     if (fabs(slfrof.sdsar - dsar) > 0.0001) {
-    if (adjust) {
-        ixdots = slfrof.sxdots * (slfrof.sdsar / dsar) + 0.5;
-        iydots = slfrof.sydots;
-        dsar = ((double) ixdots) / iydots;
+        if (adjust) {
+            ixdots = slfrof.sxdots * (slfrof.sdsar / dsar) + 0.5;
+            iydots = slfrof.sydots;
+            dsar = ((double) ixdots) / iydots;
+        } else {
+            pm_message("Warning - pixels on source screen were non-square.  "
+                       "Specifying -adjust will correct image width "
+                       "to compensate.");
+            ixdots = slfrof.sxdots;
+            iydots = slfrof.sydots;
+            dsar = slfrof.sdsar;
+        }
     } else {
-            pm_message("Warning - pixels on source screen were non-square.");
-            pm_message("          Specifying -adjust will correct image width to compensate.");
+        /* Source pixels were square. */
         ixdots = slfrof.sxdots;
         iydots = slfrof.sydots;
         dsar = slfrof.sdsar;
-    }
-    } else {
-    /* Source pixels were square. */
-    ixdots = slfrof.sxdots;
-    iydots = slfrof.sydots;
-    dsar = slfrof.sdsar;
-    adjust = FALSE;           /* Mark no adjustment needed */
+        adjust = FALSE;           /* Mark no adjustment needed */
     }
 
     /* If there's a uniform scale factor specified, apply it. */
 
     if (uscale > 0) {
-    ixdots = (ixdots * uscale) + 0.5;
-    iydots = (iydots * uscale) + 0.5;
+        ixdots = (ixdots * uscale) + 0.5;
+        iydots = (iydots * uscale) + 0.5;
     }
 
     /* If the image is to be stretched  to  a  given  width,  set  the
        output  image  sizes accordingly.  If only a height or width is
        given, scale the other direction proportionally to preserve the
-       aspect ratio. */
+       aspect ratio.
+    */
 
     if (sxsize > 0) {
-    if (sysize > 0) {
-        iydots = sysize - 1;
-    } else {
-        iydots = ((((long) iydots) * (sxsize - 1)) +
-              (iydots / 2)) / ixdots;
-    }
-    ixdots = sxsize - 1;
-    } else if (sysize > 0) {
-    if (sxsize > 0) {
+        if (sysize > 0) {
+            iydots = sysize - 1;
+        } else {
+            iydots = ((((long) iydots) * (sxsize - 1)) +
+                      (iydots / 2)) / ixdots;
+        }
         ixdots = sxsize - 1;
-    } else {
-        ixdots = ((((long) ixdots) * (sysize - 1)) +
-              (ixdots / 2)) / iydots;
-    }
-    iydots = sysize - 1;
+    } else if (sysize > 0) {
+        if (sxsize > 0) {
+            ixdots = sxsize - 1;
+        } else {
+            ixdots = ((((long) ixdots) * (sysize - 1)) +
+                      (ixdots / 2)) / iydots;
+        }
+        iydots = sysize - 1;
     }
-
+    
     if (adjust) {
-    pm_message(
+        pm_message(
             "Resized from %dx%d to %dx%d to correct pixel aspect ratio.",
-        slfrof.sxdots + 1, slfrof.sydots + 1, ixdots + 1, iydots + 1);
+            slfrof.sxdots + 1, slfrof.sydots + 1, ixdots + 1, iydots + 1);
     }
-
+    
     /* Allocate image buffer and clear it to black. */
-
+    
     pixels = ppm_allocarray(pixcols = ixdots + 1, pixrows = iydots + 1);
     PPM_ASSIGN(rgbcolor, 0, 0, 0);
     ppmd_filledrectangle(pixels, pixcols, pixrows, pixmaxval, 0, 0,
                          pixcols, pixrows, PPMD_NULLDRAWPROC,
                          (char *) &rgbcolor);
-
+    
     if ((rescale = slfrof.sxdots != ixdots ||
-    slfrof.sydots != iydots ||
-    slfrof.sdsar != dsar) != 0) {
-
+         slfrof.sydots != iydots ||
+         slfrof.sdsar != dsar) != 0) {
+        
         /* Rescale all coords. so they'll look (more or less)
-       right on this display.  */
-
-    xfac = (ixdots + 1) * 0x10000L;
-    xfac /= (long) (slfrof.sxdots + 1);
-    yfac = (iydots + 1) * 0x10000L;
-    yfac /= (long) (slfrof.sydots + 1);
-    if (dsar < slfrof.sdsar) {
-        yfac = yfac * dsar / slfrof.sdsar;
-       } else {
-        xfac = xfac * slfrof.sdsar / dsar;
-    }
+           right on this display.
+        */
+        
+        xfac = (ixdots + 1) * 0x10000L;
+        xfac /= (long) (slfrof.sxdots + 1);
+        yfac = (iydots + 1) * 0x10000L;
+        yfac /= (long) (slfrof.sydots + 1);
+        if (dsar < slfrof.sdsar) {
+            yfac = yfac * dsar / slfrof.sdsar;
+        } else {
+            xfac = xfac * slfrof.sdsar / dsar;
+        }
     }
 
     poly.npoints = 0;             /* No flood in progress. */
-
+    
     while ((cw = sli()) != 0xFC00) {
-    switch (cw & 0xFF00) {
+        switch (cw & 0xFF00) {
         case 0xFB00:          /*  Short vector compressed  */
-        vec.f.x = lx + extend(cw & 0xFF);
-        vec.f.y = ly + slib();
-        vec.t.x = lx + slib();
-        vec.t.y = ly + slib();
-        lx = vec.f.x;
-        ly = vec.f.y;
-        if (rescale) {
-            vscale(&vec.f.x, &vec.f.y);
-            vscale(&vec.t.x, &vec.t.y);
-        }
-        (*slvec)(&vec, curcolor);/* Draw vector on screen */
-        slx = vec.f.x;        /* Save scaled point */
-        sly = vec.f.y;
-        break;
-
+            vec.f.x = lx + extend(cw & 0xFF);
+            vec.f.y = ly + slib();
+            vec.t.x = lx + slib();
+            vec.t.y = ly + slib();
+            lx = vec.f.x;
+            ly = vec.f.y;
+            if (rescale) {
+                vscale(&vec.f.x, &vec.f.y);
+                vscale(&vec.t.x, &vec.t.y);
+            }
+            (*slvec)(&vec, curcolor);/* Draw vector on screen */
+            slx = vec.f.x;        /* Save scaled point */
+            sly = vec.f.y;
+            break;
+            
         case 0xFC00:          /*  End of file  */
-        break;
-
+            break;
+            
         case 0xFD00:          /*  Flood command  */
-        vec.f.x = sli();
-        vec.f.y = sli();
-        if ((int) vec.f.y < 0) { /* start or end */
-            if (poly.npoints != 0) { /* end?  */
-            if (poly.npoints > 2 && poly.npoints < 11) {
-                (*slflood)(&poly, curcolor);
-            } else {
-                            pm_error("Bad polygon vertex count (%d)",
-                   poly.npoints);
-            }
-            poly.npoints = 0;
-            } else {
-            poly.fill = -vec.f.y;  /* Start */
+            vec.f.x = sli();
+            vec.f.y = sli();
+            if ((int) vec.f.y < 0) { /* start or end */
+                if (poly.npoints != 0) { /* end?  */
+                    if (poly.npoints > 2 && poly.npoints < 11) {
+                        (*slflood)(&poly, curcolor);
+                    } else {
+                        pm_error("Bad polygon vertex count (%d)",
+                                 poly.npoints);
+                    }
+                    poly.npoints = 0;
+                } else {
+                    poly.fill = -vec.f.y;  /* Start */
+                }
+            } else {          /* Polygon vertex */
+                if (poly.npoints < 10) {
+                    if (rescale) {
+                        vscale(&vec.f.x, &vec.f.y);
+                    }
+                    poly.pt[poly.npoints].x = vec.f.x;
+                    poly.pt[poly.npoints].y = vec.f.y;
+                }
+                poly.npoints++;
             }
-        } else {          /* Polygon vertex */
-            if (poly.npoints < 10) {
+            break;
+            
+        case 0xFE00:          /*  Common endpoint compressed  */
+            vec.f.x = lx + extend(cw & 0xFF);
+            vec.f.y = ly + slib();
+            lx = vec.f.x;
+            ly = vec.f.y;
+            vec.t.x = slx;
+            vec.t.y = sly;
             if (rescale) {
                 vscale(&vec.f.x, &vec.f.y);
             }
-            poly.pt[poly.npoints].x = vec.f.x;
-            poly.pt[poly.npoints].y = vec.f.y;
-            }
-            poly.npoints++;
-        }
-        break;
-
-        case 0xFE00:          /*  Common endpoint compressed  */
-        vec.f.x = lx + extend(cw & 0xFF);
-        vec.f.y = ly + slib();
-        lx = vec.f.x;
-        ly = vec.f.y;
-        vec.t.x = slx;
-        vec.t.y = sly;
-        if (rescale) {
-            vscale(&vec.f.x, &vec.f.y);
-        }
-        (*slvec)(&vec, curcolor);/* Draw vector */
-        slx = vec.f.x;        /* Save scaled point */
-        sly = vec.f.y;
-        break;
-
+            (*slvec)(&vec, curcolor);/* Draw vector */
+            slx = vec.f.x;        /* Save scaled point */
+            sly = vec.f.y;
+            break;
+            
         case 0xFF00:          /*  Change color  */
-        curcolor = cw & 0xFF;
-        break;
+            curcolor = cw & 0xFF;
+            break;
 
         default:              /*  Co-ordinates  */
-        lx = vec.f.x = cw;
-        ly = vec.f.y = sli();
-        vec.t.x = sli();
-        vec.t.y = sli();
-        if (rescale) {
-           vscale(&vec.f.x, &vec.f.y);
-           vscale(&vec.t.x, &vec.t.y);
-        }
-        (*slvec)(&vec, curcolor);
-        slx = vec.f.x;        /* Save scaled point */
-        sly = vec.f.y;
-        break;
-    }
-    }
-}
-
-/*  SLIDEFIND  --  Find  a  slide  in  a  library  or,  if  DIRONLY is
-           nonzero, print a directory listing of the  library.
-           If  UCASEN  is nonzero, the requested slide name is
-           converted to upper case. */
-
-static void slidefind(sname, dironly, ucasen)
-  char *sname;
-  int dironly, ucasen;
-{
-    char uname[32];
-    unsigned char libent[36];
-    long pos;
-
-    if (dironly) {
-        pm_message("Slides in library:");
-    } else {
-    int i;
-    char *ip = sname;
-
-    for (i = 0; i < 31; i++) {
-        char ch = *ip++;
-        if (ch == EOS) {
-        break;
-        }
-        if (ucasen && ISLOWER(ch)) {
-        ch = TOUPPER(ch);
-        }
-        uname[i] = ch;
-    }
-    uname[i] = EOS;
-    }
-
-    /* Read slide library header and verify. */
-
-    if ((fread(libent, 32, 1, slfile) != 1) ||
-        (!STREQ((char *)libent, "AutoCAD Slide Library 1.0\015\012\32"))) {
-        pm_error("not an AutoCAD slide library file.");
-    }
-    pos = 32;
-
-    /* Search for a slide with the requested name. */
-
-    while (TRUE) {
-    if ((fread(libent, 36, 1, slfile) != 1) ||
-        (strlen((char *)libent) == 0)) {
-        if (dironly) {
-        return;
-        }
-            pm_error("slide %s not in library.", sname);
-    }
-    pos += 36;
-    if (dironly) {
-            pm_message("  %s", libent);
-    } else if (STREQ((char *)libent, uname)) {
-        long dpos = (((((libent[35] << 8) | libent[34]) << 8) |
-                 libent[33]) << 8) | libent[32];
-        if ((slfile == stdin) || (fseek(slfile, dpos, 0) == -1)) {
-        dpos -= pos;
-
-        while (dpos-- > 0) {
-            (void) getc(slfile);
-        }
+            lx = vec.f.x = cw;
+            ly = vec.f.y = sli();
+            vec.t.x = sli();
+            vec.t.y = sli();
+            if (rescale) {
+                vscale(&vec.f.x, &vec.f.y);
+                vscale(&vec.t.x, &vec.t.y);
+            }
+            (*slvec)(&vec, curcolor);
+            slx = vec.f.x;        /* Save scaled point */
+            sly = vec.f.y;
+            break;
         }
-        break;
-    }
     }
 }
 
-/*  DRAW  --  Draw a vector in the given AutoCAD color.  */
 
-static void draw(vec, color)
-  struct svector *vec;
-  int color;
-{
-    pixel rgbcolor;
-
-    if (blither) {
-        pm_message("Vector (%d, %d) - (%d, %d)  Color %d",
-           vec->f.x, vec->f.y, vec->t.x, vec->t.y, color);
-    }
-    assert(vec->f.x >= 0 && vec->f.x < pixcols);
-    assert(vec->f.y >= 0 && vec->f.y < pixrows);
-    assert(vec->t.x >= 0 && vec->t.x < pixcols);
-    assert(vec->t.y >= 0 && vec->t.y < pixrows);
-    PPM_ASSIGN(rgbcolor,
-           acadcol[color][0], acadcol[color][1], acadcol[color][2]);
-    ppmd_line(pixels, pixcols, pixrows, pixmaxval,
-          vec->f.x, iydots - vec->f.y, vec->t.x, iydots - vec->t.y,
-          PPMD_NULLDRAWPROC,
-          (char *) &rgbcolor);
-}
-
-/*  FLOOD  --  Draw a filled polygon.  */
-
-static void
-flood(struct spolygon * const poly,
-      int               const color) {
-
-    int i;
-    struct fillobj * handle;
-    pixel rgbcolor;
-
-    handle = ppmd_fill_create();
-
-    if (blither) {
-        pm_message("Polygon: %d points, fill type %d, color %d",
-                   poly->npoints, poly->fill, color);
-        for (i = 0; i < poly->npoints; i++) {
-            pm_message("   Point %d:  (%d, %d)", i + 1,
-                       poly->pt[i].x, poly->pt[i].y);
-        }
-    }
-
-    PPM_ASSIGN(rgbcolor,
-               acadcol[color][0], acadcol[color][1], acadcol[color][2]);
-    for (i = 0; i < poly->npoints; i++) {
-        assert(poly->pt[i].x >= 0 && poly->pt[i].x < pixcols);
-        assert(poly->pt[i].y >= 0 && poly->pt[i].y < pixrows);
-        ppmd_line(pixels, pixcols, pixrows, pixmaxval,
-                  poly->pt[i].x, iydots - poly->pt[i].y, 
-                  poly->pt[(i + 1) % poly->npoints].x,
-                  iydots - poly->pt[(i + 1) % poly->npoints].y,
-                  ppmd_fill_drawproc, handle);
-    }
-    ppmd_fill(pixels, pixcols, pixrows, pixmaxval,
-              handle, PPMD_NULLDRAWPROC, (char *) &rgbcolor);
-
-    ppmd_fill_destroy(handle);
-}
 
 /*  Main program. */
 
-int main(argc, argv)
-  int argc;
-  char *argv[];
-{
+int
+main(int    argc,
+     char * argv[]) {
+
     int argn;
     const char * const usage = "[-verbose] [-info] [-adjust] [-scale <s>]\n\
-                 [-dir] [-lib|-Lib <name>]\n\
-                 [-xsize|-width <x>] [-ysize|-height <y>] [sldfile]";
+[-dir] [-lib|-Lib <name>]\n\
+[-xsize|-width <x>] [-ysize|-height <y>] [sldfile]";
     int scalespec = FALSE, widspec = FALSE, hgtspec = FALSE, dironly = FALSE,
-    ucasen;
-    char *slobber = (char *) 0;       /* Slide library item */
+        ucasen;
+    const char * slobber;       /* Slide library item */
 
 
+    slobber = NULL;
+
     ppm_init(&argc, argv);
     argn = 1;
 
     while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
         if (pm_keymatch(argv[argn], "-verbose", 2)) {
-        blither = TRUE;
+            blither = TRUE;
         } else if (pm_keymatch(argv[argn], "-adjust", 2)) {
-        adjust = TRUE;
+            adjust = TRUE;
         } else if (pm_keymatch(argv[argn], "-dir", 2)) {
-        dironly = TRUE;
+            dironly = TRUE;
         } else if (pm_keymatch(argv[argn], "-info", 2)) {
-        info = TRUE;
+            info = TRUE;
         } else if (pm_keymatch(argv[argn], "-lib", 2)) {
-        if (slobber != (char *) 0) {
+            if (slobber)
                 pm_error("already specified a library item");
-        }
             ucasen = argv[argn][1] != 'L';
-        argn++;
-        if (argn == argc) {
-        pm_usage(usage);
-        }
-        slobber = argv[argn];
+            argn++;
+            if (argn == argc) {
+                pm_usage(usage);
+            }
+            slobber = argv[argn];
         } else if (pm_keymatch(argv[argn], "-scale", 2)) {
-        if (scalespec) {
+            if (scalespec) {
                 pm_error("already specified a scale factor");
-        }
-        argn++;
+            }
+            argn++;
             if ((argn == argc) || (sscanf(argv[argn], "%lf", &uscale) != 1))
-        pm_usage(usage);
-        if (uscale <= 0.0) {
+                pm_usage(usage);
+            if (uscale <= 0.0) {
                 pm_error("scale factor must be greater than 0");
-        }
-        scalespec = TRUE;
+            }
+            scalespec = TRUE;
         } else if (pm_keymatch(argv[argn], "-xsize", 2) ||
                    pm_keymatch(argv[argn], "-width", 2)) {
-        if (widspec) {
+            if (widspec) {
                 pm_error("already specified a width/xsize");
-        }
-        argn++;
+            }
+            argn++;
             if ((argn == argc) || (sscanf(argv[argn], "%d", &sxsize) != 1))
-        pm_usage(usage);
-        widspec = TRUE;
+                pm_usage(usage);
+            widspec = TRUE;
         } else if (pm_keymatch(argv[argn], "-ysize", 2) ||
                    pm_keymatch(argv[argn], "-height", 2)) {
-        if (hgtspec) {
+            if (hgtspec) {
                 pm_error("already specified a height/ysize");
+            }
+            argn++;
+            if ((argn == argc) || (sscanf(argv[argn], "%d", &sysize) != 1))
+                pm_usage(usage);
+            hgtspec = TRUE;
+        } else {
+            pm_usage(usage);
         }
         argn++;
-            if ((argn == argc) || (sscanf(argv[argn], "%d", &sysize) != 1))
-        pm_usage(usage);
-        hgtspec = TRUE;
-    } else {
-        pm_usage(usage);
-    }
-    argn++;
     }
 
     /* If a file name is specified, open it.  Otherwise read from
-       standard input. */
+       standard input. 
+    */
 
     if (argn < argc) {
-    slfile = pm_openr(argv[argn]);
-    argn++;
+        slfile = pm_openr(argv[argn]);
+        argn++;
     } else {
-    slfile = stdin;
+        slfile = stdin;
     }
-
+    
     if (argn != argc) {           /* Extra bogus arguments ? */
-    pm_usage(usage);
+        pm_usage(usage);
     }
-
+    
     /* If we're extracting an item from a slide library, position the
-       input stream to the start of the chosen slide. */
-
-    if (dironly || (slobber != (char *) 0)) {
-    slidefind(slobber, dironly, ucasen);
-    }
-
+       input stream to the start of the chosen slide.
+    */
+ 
+    if (dironly || slobber)
+        slidefind(slobber, dironly, ucasen);
+ 
     if (!dironly) {
-    slider(draw, flood);
-    ppm_writeppm(stdout, pixels, pixcols, pixrows, pixmaxval, FALSE);
+        slider(draw, flood);
+        ppm_writeppm(stdout, pixels, pixcols, pixrows, pixmaxval, FALSE);
     }
     pm_close(slfile);
     pm_close(stdout);
-    exit(0);
+    
+    return 0;
 }
diff --git a/converter/ppm/spctoppm.c b/converter/ppm/spctoppm.c
index 3eea7821..d2a48187 100644
--- a/converter/ppm/spctoppm.c
+++ b/converter/ppm/spctoppm.c
@@ -165,15 +165,8 @@ DoBitmap( ifp )
 	sscreen[i] = ( screen[i<<1] << 8 ) + ( 0xff & screen[(i<<1)+1] );
     }
 
-#if __STDC__
 static void
 DoChar( int n, char c )
-#else /*__STDC__*/
-static void
-DoChar( n, c )
-    int n;
-    char c;
-#endif /*__STDC__*/
     {
     int i;
 
diff --git a/doc/HISTORY b/doc/HISTORY
index caa0a0b1..246b92f2 100644
--- a/doc/HISTORY
+++ b/doc/HISTORY
@@ -4,96 +4,99 @@ Netpbm.
 CHANGE HISTORY 
 --------------
 
-06.12.18 BJH  Release 10.36.15
+06.12.31 BJH  Release 10.37.0
 
-              ppmchange: Fix bug with -closeness and not -remainder or
-              vice versa.
-
-              pgmtoppm: Fix garbage output with -map and input maxval
-              != map maxval.
-
-06.12.03 BJH  Release 10.36.14
-
-              pbmtext: Fix crash when there is only one character.
-
-              pnmtopng: fix transparency optimization on PPM input.
-    
-              pnmrotate: fix -background option with PGM/PBM input.
+              add pambackground.  But doesn't find mid-row background yet.
 
-              pamx: fix bug with X depth = 0.
+              pnmcrop, pamtopnm: work on multi-image stream.
+              Thanks Erik Auerswald <auerswal@unix-ag.uni-kl.de>.
 
-              pamx: fix bug: incorrect display of one-plane input image.
+              pnmshear: add -background.  Thanks Erik Auerswald
+              <auerswal@unix-ag.uni-kl.de>.
 
-06.11.27 BJH  Release 10.36.13
+              ppmtogif: replace with pamtogif.  Fix garbage output with
+              -interlace.
 
-              Configure: Fix incorrect .dylib suffix in shared library default.
+              pbmtoxbm: add -name option.
+              Thanks Prophet of the Way <afu@wta.att.ne.jp>.
 
-              libnetpbm: fix bogus results from ppm_parsecolor() of
-              rgb:0/0/0 style color name.
+              pbmtoxbm: Use packed PBM functions for efficiency.
+              Thanks Prophet of the Way <afu@wta.att.ne.jp>.
+              
+              xbmtopbm: Use packed PBM functions for efficiency.
+              Thanks Prophet of the Way <afu@wta.att.ne.jp>.
 
-06.11.18 BJH  Release 10.36.12
+              cmuwmtopbm, mgrtopbm, pbmtocmuwm, pbmtoicon, pbmtomgr:
+              Use packed PBM functions for efficiency.
+              Thanks Prophet of the Way <afu@wta.att.ne.jp>.
 
-              ppmtogif: fix garbage output with non-ppm-raw input;
-              restore to 10.34 version.
+              libnetpbm: add pnm_colorname().
 
-06.11.14 BJH  Release 10.36.11
+              libnetpbm: add pnm_computetuplefreqtable3().  Has ability
+              to limit number of planes of input considered.
 
-              ppmtogif: fix garbage output with -interlace.
+              libpam: better checking of sufficient size of struct pam
+              in pnm_writepaminit().
 
-06.11.13 BJH  Release 10.36.10
+              pnm_readpaminit(): abort instead of crash if width == 0.
 
-              Configure: fix libX11 location default.
+              pnmtopng: fix transparency optimization on PPM input.
+    
+              pnmrotate: fix -background option with PGM/PBM input.
 
-06.11.13 BJH  Release 10.36.09
+              pamx: fix bug with X depth = 0.
 
-              Configure: fix libX11 location default.
+              pamx: fix bug: incorrect display of one-plane input image.
 
-06.11.13 BJH  Release 10.36.08
+              libnetpbm: fix bogus results from ppm_parsecolor() of
+              rgb:0/0/0 style color name.
 
-              Build: fix Darwin build.
+              pbmtoxbm, pbmtox10bm: merge.
+              Thanks Prophet of the Way <afu@wta.att.ne.jp>.
 
-06.11.08 BJH  Release 10.36.07
+              pbmtox10bm: Fix generation of name in XBM file.
+              Thanks Prophet of the Way <afu@wta.att.ne.jp>.
 
-              Build: remove unnecessary limit of 200 characters on
-              argument length in Libopt.
+              pbmtextps: Fix buffer overrun -- typical symptom: extra
+              text generated.
 
-06.10.26 BJH  Release 10.36.06
+              ppmchange: Fix bug with -closeness and not -remainder or
+              vice versa.
 
-              pnm_readpaminit(): Don't crash if width == 0.
+              pgmtoppm: Fix garbage output with -map and input maxval
+              != map maxval.
 
-06.10.22 BJH  Release 10.36.05
+              pbmtext: Fix crash when there is only one character.
 
-              ppmtompeg: fix reading of GOP files.  Thanks Alun Jones.
+              pnmnlfilt: Give proper error message for syntax errors.
 
-06.10.21 BJH  Release 10.36.04
+              ppmtompeg: fix reading of GOPs.  Thanks Alun Jones.
 
               Fix pamcomp: due to use of undefined value, sometimes produces
               plain format.
 
-06.10.18 BJH  Release 10.36.03
-
               Fix pamperspective: read all of input.
 
               Fix libnetpbm pm_system(): don't hang if shell command quits
               before taking all the input.
 
-              Fix redefinitions of functions that Irix compiler can't handle.
-
               Build: Configure does test links to detect broken
               libpng-config --ldflags.
 
-06.10.01 BJH  Release 10.36.02
+              Build: Fix some compile failures with Irix IDO compiler.
 
-              Fix some prototypes that don't literally match definitions
-              so that Irix compiler will accept them.
+              Build: fix Darwin build.
 
-06.09.29 BJH  Release 10.36.01
+              Configure: fix default for X library location.
+
+              Build: remove unnecessary limit of 200 characters on
+              argument length in Libopt.
 
               Build: fix build with separate build directory.
 
               Build: fix merge build with no X11 library.
 
-06.09.21 BJH  Release 10.36.00
+06.09.21 BJH  Release 10.36.0
 
               pbmtonokia: Add plain NPM output capability.  Thanks Paul Bolle
               <pebolle@tiscali.nl>.
@@ -129,7 +132,7 @@ CHANGE HISTORY
               pm_accept_to_pamtuples: fix bug: fill in pam structure.
               Thanks "Christian Schlotter" <schlotter@users.sourceforge.net>.
 
-              Fix selection of MMX_SEE fastpath based on GNU compiler version
+              Fix selection of MMX_SSE fastpath based on GNU compiler version
               number.
 
               Properly clean thinkjettopbm.c with 'make distclean'.
@@ -381,8 +384,6 @@ CHANGE HISTORY
               pamstereogram: Fix crippling bugs.  Thanks Scott Pakin
               <scott@pakin.org>.
 
-              giftopnm: Fix bug with interlaced GIF < 5 rows.
-
               giftopnm: Handle case of a clear code at the end of a block.
 
               ppmtogif: Fix bug with interlaced GIF < 5 rows.
diff --git a/doc/INSTALL b/doc/INSTALL
index c83b725d..ae49073a 100644
--- a/doc/INSTALL
+++ b/doc/INSTALL
@@ -213,6 +213,36 @@ normal build (there's a question for that in the Configure program).
 See below.
 
 
+SEPARATE BUILD TREE
+-------------------
+
+While it's traditional to build a Unix package by adding object files
+to the same tree with the source files, it's actually much cleaner to
+keep your source tree exactly as you got it and put the built files in
+a separate directory, called the build tree.
+
+To do this, just create an empty directory and run 'configure' in it,
+then 'make':
+
+  mkdir netpbmbuild
+  cd netpbmbuild
+  /usr/src/netpbm/configure
+  ...
+  make
+
+But if you plan to work on Netpbm source code, you'll probably find it
+more convenient to build the traditional way, with a single tree for
+source and build.
+
+In the source tree, you can type 'make' in any directory to do the
+default make for that directory, or make FILENAME to make the file of
+that name there.  In the separate build tree, there are special
+facilities to allow you to do a simple make from the _top level
+directory_, but if you want to make a subcomponent or individual part,
+you have to have a -f option and set SRCDIR and BLDDIR on your 'make'
+command.
+
+
 MERGE BUILD
 -----------
 
diff --git a/doc/USERDOC b/doc/USERDOC
index 3cd2b383..9c224288 100644
--- a/doc/USERDOC
+++ b/doc/USERDOC
@@ -21,15 +21,19 @@ INSTALLING A LOCAL COPY OF DOCUMENTATION
 If accessing the manual on the World Wide Web is not convenient for
 you (for example, if you want to access it from a computer that is not
 always connected to the Internet), just make a local copy of the web
-site files using GNU Wget:
+site files.  An obvious way to do that is just to copy the web site
+with GNU Wget:
 
   wget --recursive --relative http://netpbm.sourceforge.net/doc/
 
-The above copies all the HTML files from the web site into your
-current directory, under a subdirectory 'netpbm.sourceforge.net/doc'
-that it creates.  You can browse those files directly with a web
-browser.  If you don't have Wget, get it from
-ftp://ftp.gnu.org/gnu/wget.  It is very useful.
+However, a somewhat cleaner way is to get the files from the
+Subversion repository using the Subversion client program 'svn':
+
+  URL=https://netpbm.svn.sourceforge.net/svnroot/netpbm/userguide
+  svn export $URL
+
+This creates a directory "userguide" in your current directory containing
+all the same files that are on the web site.
 
 
 GETTING COMMAND HELP WITH A "MAN" COMMAND
diff --git a/editor/Makefile b/editor/Makefile
index 18165666..10c6ee7b 100644
--- a/editor/Makefile
+++ b/editor/Makefile
@@ -14,7 +14,7 @@ include $(BUILDDIR)/Makefile.config
 # This package is so big, it's useful even when some parts won't 
 # build.
 
-PORTBINARIES = pamaddnoise pamcomp pamcut \
+PORTBINARIES = pamaddnoise pambackground pamcomp pamcut \
 	       pamdeinterlace pamdice pamditherbw pamedge \
 	       pamenlarge \
 	       pamflip pamfunc pammasksharpen pammixinterlace \
diff --git a/editor/pamaddnoise.c b/editor/pamaddnoise.c
index 9c2d12f7..cf1af815 100644
--- a/editor/pamaddnoise.c
+++ b/editor/pamaddnoise.c
@@ -208,7 +208,7 @@ main(int argc, char * argv[]) {
     int argn;
     const char * inputFilename;
     int noise_type;
-    int seed;
+    unsigned int seed;
     int i;
     const char * const usage = "[-type noise_type] [-lsigma x] [-mgsigma x] "
         "[-sigma1 x] [-sigma2 x] [-lambda x] [-seed n] "
@@ -247,7 +247,7 @@ main(int argc, char * argv[]) {
 
     pnm_init(&argc, argv);
 
-    seed = time(NULL) ^ getpid();
+    seed = pm_randseed();
     noise_type = GAUSSIAN;
 
     argn = 1;
diff --git a/editor/pambackground.c b/editor/pambackground.c
new file mode 100644
index 00000000..92e1fce2
--- /dev/null
+++ b/editor/pambackground.c
@@ -0,0 +1,302 @@
+#include "mallocvar.h"
+#include "nstring.h"
+#include "shhopt.h"
+#include "pam.h"
+
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char * inputFileName;  
+    unsigned int verbose;
+};
+
+
+
+static void
+parseCommandLine(int argc, char ** const argv,
+                 struct cmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optEntry *option_def;
+        /* Instructions to OptParseOptions2 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "verbose",    OPT_FLAG,   NULL, &cmdlineP->verbose,        0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else {
+        cmdlineP->inputFileName = argv[1];
+        if (argc-1 > 1)
+            pm_error("There is at most one argument:  input file name.  "
+                     "You specified %d", argc-1);
+    }
+}        
+
+
+
+static void
+initOutpam(const struct pam * const inpamP,
+           struct pam *       const outpamP) {
+
+    outpamP->file             = stdout;
+    outpamP->format           = PAM_FORMAT;
+    outpamP->plainformat      = 0;
+    outpamP->width            = inpamP->width;
+    outpamP->height           = inpamP->height;
+    outpamP->depth            = 1;
+    outpamP->maxval           = 1;
+    outpamP->bytes_per_sample = pnm_bytespersample(outpamP->maxval);
+    outpamP->len              = PAM_STRUCT_SIZE(bytes_per_sample);
+    outpamP->size             = sizeof(*outpamP);
+}
+
+
+
+static void
+allocateOutputPointerRow(unsigned int const width,
+                         tuple **     const tuplerowP) {
+
+    MALLOCARRAY(*tuplerowP, width);
+
+    if (*tuplerowP == NULL)
+        pm_error("Could not allocate a %u-column tuple pointer array", width);
+}
+
+
+
+static void
+createWhiteTuple(const struct pam * const pamP, 
+                 tuple *            const whiteTupleP) {
+/*----------------------------------------------------------------------------
+   Create a "white" tuple.  By that we mean a tuple all of whose elements
+   are zero.  If it's an RGB, grayscale, or b&w pixel, that means it's black.
+-----------------------------------------------------------------------------*/
+    tuple whiteTuple;
+    unsigned int plane;
+
+    whiteTuple = pnm_allocpamtuple(pamP);
+
+    for (plane = 0; plane < pamP->depth; ++plane)
+        whiteTuple[plane] = pamP->maxval;
+
+    *whiteTupleP = whiteTuple;
+}
+
+
+
+static void
+selectBackground(struct pam * const pamP,
+                 tuple        const ul,
+                 tuple        const ur,
+                 tuple        const lr,
+                 tuple        const ll,
+                 tuple *      const bgColorP) {
+
+    tuple bg;  /* Reference to one of ul, ur, ll, lr */
+
+    if (pnm_tupleequal(pamP, ul, ur)) {
+        if (pnm_tupleequal(pamP, ll, ul))
+            bg = ul;
+        else if (pnm_tupleequal(pamP, lr, ul))
+            bg = ul;
+    } else if (pnm_tupleequal(pamP, ll, lr)) {
+        if (pnm_tupleequal(pamP, ul, ll))
+            bg = ll;
+        else if (pnm_tupleequal(pamP, ur, ll))
+            bg = ll;
+    } else {
+        /* No 3 corners are same color; look for 2 corners */
+        if (pnm_tupleequal(pamP, ul, ur))  /* top edge */
+            bg = ul;
+        else if (pnm_tupleequal(pamP, ul, ll)) /* left edge */
+            bg = ul;
+        else if (pnm_tupleequal(pamP, ur, lr)) /* right edge */
+            bg = ur;
+        else if (pnm_tupleequal(pamP, ll, lr)) /* bottom edge */
+            bg = ll;
+        else {
+            /* No two corners are same color; just use upper left corner */
+            bg = ul;
+        }
+    }
+    
+    *bgColorP = pnm_allocpamtuple(pamP);
+    pnm_assigntuple(pamP, *bgColorP, bg);
+}
+
+
+
+static void
+computeBackground(struct pam * const pamP,
+                  bool         const verbose,
+                  tuple *      const bgColorP) {
+/*----------------------------------------------------------------------------
+   Determine what color is the background color of the image in the
+   file represented by *pamP.
+
+   Expect the file to be positioned to the start of the raster, and leave
+   it positioned arbitrarily.
+-----------------------------------------------------------------------------*/
+    unsigned int row;
+    tuple * tuplerow;
+    tuple ul, ur, ll, lr;
+        /* Color of upper left, upper right, lower left, lower right */
+
+    tuplerow  = pnm_allocpamrow(pamP);
+    ul = pnm_allocpamtuple(pamP);
+    ur = pnm_allocpamtuple(pamP);
+    ll = pnm_allocpamtuple(pamP);
+    lr = pnm_allocpamtuple(pamP);
+
+    pnm_readpamrow(pamP, tuplerow);
+
+    pnm_assigntuple(pamP, ul, tuplerow[0]);
+    pnm_assigntuple(pamP, ur, tuplerow[pamP->width-1]);
+
+    for (row = 1; row < pamP->height; ++row)
+        pnm_readpamrow(pamP, tuplerow);
+
+    pnm_assigntuple(pamP, ll, tuplerow[0]);
+    pnm_assigntuple(pamP, lr, tuplerow[pamP->width-1]);
+
+    selectBackground(pamP, ul, ur, ll, lr, bgColorP);
+
+    if (verbose) {
+        int const hexokTrue = 1;
+        const char * const colorname =
+            pnm_colorname(pamP, *bgColorP, hexokTrue);
+        pm_message("Background color is %s", colorname);
+
+        strfree(colorname);
+    }
+
+    pnm_freepamtuple(lr);
+    pnm_freepamtuple(ll);
+    pnm_freepamtuple(ur);
+    pnm_freepamtuple(ul);
+    pnm_freepamrow(tuplerow);
+}
+
+
+
+static void
+computeOutputRow(struct pam * const inpamP,
+                 tuple *      const inputTuplerow,
+                 tuple        const backgroundColor,
+                 struct pam * const outpamP,
+                 tuple *      const outputTuplerow,
+                 tuple        const foreground,
+                 tuple        const background) {
+
+    unsigned int col;
+    unsigned int firstForegroundCol;
+        // Column number of first column, going from the left, that is
+        // not the background color.
+    unsigned int endForegroundCol;
+        // Column number of the last column, going from the right,
+        // that is the background color.
+
+    col = 0;
+    while (col < inpamP->width &&
+           pnm_tupleequal(inpamP, inputTuplerow[col], backgroundColor))
+        ++col;
+
+    firstForegroundCol = col;
+
+    col = inpamP->width;
+    while (col > firstForegroundCol && 
+           pnm_tupleequal(inpamP, inputTuplerow[col-1], backgroundColor))
+        --col;
+
+    endForegroundCol = col;
+
+    // If the row is all background, 'firstForegroundCol' and
+    // 'endForegroundCol' are both one past the right edge.
+            
+    for (col = 0; col < firstForegroundCol; ++col)
+        outputTuplerow[col] = background;
+
+    for (col = firstForegroundCol; col < endForegroundCol; ++col)
+        outputTuplerow[col] = foreground;
+
+    for (col = endForegroundCol; col < outpamP->width; ++col)
+        outputTuplerow[col] = background;
+}
+
+
+
+int
+main(int argc, char *argv[]) {
+
+    struct cmdlineInfo cmdline;
+    struct pam inpam;
+    struct pam outpam;
+    FILE * ifP;
+    tuple * inputTuplerow;
+    tuple * outputTuplerow;
+        // Not a regular tuple row -- just pointer array
+    unsigned int row;
+    pm_filepos rasterpos;
+    tuple black, white;
+    tuple backgroundColor;
+    
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr_seekable(cmdline.inputFileName);
+
+    pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
+
+    pm_tell2(ifP, &rasterpos, sizeof(rasterpos));
+
+    computeBackground(&inpam, cmdline.verbose, &backgroundColor);
+
+    initOutpam(&inpam, &outpam);
+
+    inputTuplerow  = pnm_allocpamrow(&inpam);
+
+    allocateOutputPointerRow(outpam.width, &outputTuplerow);
+    pnm_createBlackTuple(&outpam, &black);
+    createWhiteTuple(&outpam, &white);
+
+    pnm_writepaminit(&outpam);
+
+    pm_seek2(ifP, &rasterpos, sizeof(rasterpos));
+
+    for (row = 0; row < outpam.height; ++row) {
+        pnm_readpamrow(&inpam, inputTuplerow);
+
+        computeOutputRow(&inpam, inputTuplerow, backgroundColor,
+                         &outpam, outputTuplerow, black, white);
+
+        pnm_writepamrow(&outpam, outputTuplerow);
+    }
+
+    pm_close(ifP);
+
+    pnm_freepamrow(inputTuplerow);
+    free(outputTuplerow);
+    pnm_freepamtuple(backgroundColor);
+    pnm_freepamtuple(white);
+    pnm_freepamtuple(black);
+    
+    return 0;
+}
diff --git a/editor/pamditherbw.c b/editor/pamditherbw.c
index 61c23103..931b475f 100644
--- a/editor/pamditherbw.c
+++ b/editor/pamditherbw.c
@@ -487,7 +487,7 @@ createFsConverter(struct pam * const graypamP,
     /* Initialize Floyd-Steinberg error vectors. */
     MALLOCARRAY_NOFAIL(stateP->thiserr, graypamP->width + 2);
     MALLOCARRAY_NOFAIL(stateP->nexterr, graypamP->width + 2);
-    srand((int)(time(NULL) ^ getpid()));
+    srand(pm_randseed());
 
     {
         /* (random errors in [-1/8 .. 1/8]) */
diff --git a/editor/pammasksharpen.c b/editor/pammasksharpen.c
index 87b928be..009e4962 100644
--- a/editor/pammasksharpen.c
+++ b/editor/pammasksharpen.c
@@ -1,6 +1,6 @@
-#include "pam.h"
-#include "shhopt.h"
 #include "mallocvar.h"
+#include "shhopt.h"
+#include "pam.h"
 
 struct cmdlineInfo {
     /* All the information the user supplied in the command line,
@@ -62,7 +62,6 @@ parseCommandLine(int argc, char ** const argv,
         if (cmdlineP->threshold > 1.0)
             pm_error("-threshold greater than unity doesn't make sense.  "
                      "You specified %f", cmdlineP->threshold);
-        
     } else
         cmdlineP->threshold = 0.0;
 
diff --git a/editor/pamperspective.c b/editor/pamperspective.c
index f5654428..8ce746db 100644
--- a/editor/pamperspective.c
+++ b/editor/pamperspective.c
@@ -190,17 +190,26 @@ typedef struct {
 
 typedef struct {
 
-  int num_rows, last_physical, last_logical;
-  tuple** rows;
-  const struct pam* inpam;
+    unsigned int num_rows;
+    unsigned int last_physical;
+    unsigned int last_logical;
+        /* Row number of the input row most recently read from input
+           file into buffer (i.e. one less than the number of rows we
+           have read from the input)
+        */
+    tuple ** rows;
+    const struct pam * inpamP;
 
 } buffer;
 
 
 
+typedef void interpolateFn(tuple, number, number);
+
 /*
   The following are like MALLOCARRAY_NOFAIL and MALLOCVAR_NOFAIL,
-  but issue an error message instead of aborting.
+  but abort (fail) the program instead of killing the process with an
+  abort signal.
 */
 
 #define MALLOCARRAY_SAFE(handle,length) \
@@ -1080,83 +1089,98 @@ static int clean_y (int const y,  const struct pam *const outpam)
   return MIN(MAX(0, y), outpam->height-1);
 }
 
-static void init_buffer (buffer *const b, const world_data *const world,
-                         const option *const options,
-                         const struct pam *const inpam,
-                         const struct pam *const outpam)
-{
-  int yul, yur, yll, ylr, y_min;
-  int i, num_rows;
-
-  yul = outpixel_to_iny (0,0,world);
-  yur = outpixel_to_iny (outpam->width-1,0,world);
-  yll = outpixel_to_iny (0,outpam->height-1,world);
-  ylr = outpixel_to_iny (outpam->width-1,outpam->height-1,world);
-
-  y_min = MIN (MIN (yul,yur), MIN (yll,ylr));
-  num_rows = MAX (MAX (diff (yul, yur),
-                       diff (yll, ylr)),
-                  MAX (diff (clean_y(yul,outpam), clean_y(y_min,outpam)),
-                       diff (clean_y(yur,outpam), clean_y(y_min,outpam))))
-    + 2;
-  switch (options->enums[3]) {  /* --interpolation */
-  case nearest:
-    break;
-  case linear:
-    num_rows += 1;
-    break;
-  };
-  if (num_rows > inpam->height)
-    num_rows = inpam->height;
-
-  b->num_rows = num_rows;
-  MALLOCARRAY_SAFE (b->rows, num_rows);
-  for (i=0; i<num_rows; i++) {
-    b->rows[i] = pnm_allocpamrow (inpam);
-    pnm_readpamrow (inpam, b->rows[i]);
-  };
-  b->last_physical = num_rows-1;
-  b->last_logical = num_rows-1;
-  b->inpam = inpam;
+static void
+init_buffer(buffer *           const bufferP,
+            const world_data * const worldP,
+            const option *     const optionsP,
+            const struct pam * const inpamP,
+            const struct pam * const outpamP) {
+
+    unsigned int yul, yur, yll, ylr, y_min;
+    unsigned int num_rows;
+
+    yul = outpixel_to_iny(0, 0, worldP);
+    yur = outpixel_to_iny(outpamP->width-1, 0, worldP);
+    yll = outpixel_to_iny(0, outpamP->height-1, worldP);
+    ylr = outpixel_to_iny(outpamP->width-1, outpamP->height-1, worldP);
+    
+    y_min = MIN(MIN(yul, yur), MIN(yll, ylr));
+    num_rows = MAX(MAX(diff(yul, yur),
+                       diff(yll, ylr)),
+                   MAX(diff(clean_y(yul, outpamP), clean_y(y_min, outpamP)),
+                       diff(clean_y(yur, outpamP), clean_y(y_min, outpamP))))
+        + 2;
+    switch (optionsP->enums[3]) {  /* --interpolation */
+    case nearest:
+        break;
+    case linear:
+        num_rows += 1;
+        break;
+    }
+    if (num_rows > inpamP->height)
+        num_rows = inpamP->height;
+
+    MALLOCARRAY_SAFE(bufferP->rows, num_rows);
+    bufferP->num_rows = num_rows;
+    bufferP->last_logical = 0;
+    bufferP->last_physical = 0;
+    {
+        unsigned int row;
+        for (row = 0; row < num_rows; ++row) {
+            bufferP->rows[row] = pnm_allocpamrow(inpamP);
+            pnm_readpamrow(inpamP, bufferP->rows[row]);
+            ++bufferP->last_logical;
+            ++bufferP->last_physical;
+        }
+    }
+    bufferP->inpamP = inpamP;
 }
 
-static tuple* read_buffer (buffer *const b, int const logical_y)
-{
-  int y;
-
-  while (logical_y > b->last_logical) {
-    b->last_physical++;
-    if (b->last_physical == b->num_rows)
-      b->last_physical = 0;
-    pnm_readpamrow (b->inpam, b->rows[b->last_physical]);
-    b->last_logical++;
-  }
 
-  y = logical_y - b->last_logical + b->last_physical;
-  if (y<0)
-    y += b->num_rows;
 
-  return b->rows[y];
+static tuple *
+read_buffer(buffer *     const bufferP,
+            unsigned int const logical_y) {
+
+    unsigned int y;
+    
+    while (logical_y > bufferP->last_logical) {
+        ++bufferP->last_physical;
+        if (bufferP->last_physical == bufferP->num_rows)
+            bufferP->last_physical = 0;
+        pnm_readpamrow(bufferP->inpamP, bufferP->rows[bufferP->last_physical]);
+        ++bufferP->last_logical;
+    }
+    
+    y = logical_y - bufferP->last_logical + bufferP->last_physical;
+    if (y < 0)
+        y += bufferP->num_rows;
+
+    return bufferP->rows[y];
 }
 
-static void free_buffer (buffer *const b)
-{
-  int i;
 
-  /* We have to read through the end of the input image even if we
-     didn't use all the rows, because if the input is a pipe, the
-     guy writing into the pipe may require all the data to go
-     through.
-  */
-  
-  while (b->last_logical < b->inpam->height-1) {
-      pnm_readpamrow(b->inpam, b->rows[0]);
-      ++b->last_logical;
-  }
 
-  for (i=0; i<b->num_rows; i++)
-    pnm_freepamrow (b->rows[i]);
-  free (b->rows);
+static void
+term_buffer(buffer * const bufferP) {
+
+    unsigned int i;
+
+    /* We have to read through the end of the input image even if we
+       didn't use all the rows, because if the input is a pipe, the
+       guy writing into the pipe may require all the data to go
+       through.
+    */
+
+    while (bufferP->last_logical < bufferP->inpamP->height-1) {
+        pnm_readpamrow(bufferP->inpamP, bufferP->rows[0]);
+        ++bufferP->last_logical;
+    }
+
+    for (i = 0; i < bufferP->num_rows; ++i)
+        pnm_freepamrow(bufferP->rows[i]);
+    
+    free(bufferP->rows);
 }
 
 
@@ -1251,92 +1275,98 @@ static void linear_interpolation (tuple const dest,
 
 
 
-int main (int argc, char* argv[])
-{
-  FILE* infp;
-  struct pam inpam;
-  buffer inbuffer;
-  FILE* outfp;
-  struct pam outpam;
-  tuple* outrow;
-  option options;
-  world_data world;
-  int row,col;
-  number xi,yi;
-  void (*interpolate) (tuple, number, number);
+static void
+perspective(struct pam * const outpamP,
+            world_data * const worldP,
+            interpolateFn *    interpolater) {
 
-  /* The usual initializations */
+    tuple * outrow;
+    unsigned int row;
 
-  pnm_init (&argc, argv);
-  set_command_line_defaults (&options);
-  parse_command_line (argc, argv, &options);
-  infp = pm_openr (options.infilename);
-  pnm_readpaminit (infp, &inpam, PAM_STRUCT_SIZE(tuple_type));
+    outrow = pnm_allocpamrow(outpamP);
 
-  /* Our own initializations */
+    for (row = 0; row < outpamP->height; ++row) {
+        unsigned int col;
 
-  init_world (&options, &inpam, &world);
-  determine_world_parallelogram (&world, &options);
-  determine_output_width_and_height (&world, &options);
-  switch (options.enums[1]) {   /* --output_system */
-  case lattice:
-    determine_coefficients_lattice (&world, &options);
-    break;
-  case pixel_s:
-    determine_coefficients_pixel (&world, &options);
-    break;
-  };
+        for (col = 0; col < outpamP->width; ++col) {
+            number xi,yi;
+            outpixel_to_inpixel(col, row, &xi, &yi, worldP);
+            interpolater(outrow[col], xi, yi);
+        }
+        pnm_writepamrow(outpamP, outrow);
+    }
+    pnm_freepamrow(outrow);
+}
 
-  /* Initialize outpam */
-
-  outfp = pm_openw ("-");
-  outpam.size = sizeof (outpam);
-  outpam.len = PAM_STRUCT_SIZE(bytes_per_sample);
-  outpam.file = outfp;
-  outpam.format = inpam.format;
-  outpam.plainformat = inpam.plainformat;
-  outpam.height = options.height;
-  outpam.width = options.width;
-  outpam.depth = inpam.depth;
-  outpam.maxval = inpam.maxval;
-  outpam.bytes_per_sample = inpam.bytes_per_sample;
-  pnm_writepaminit (&outpam);
-
-  /* Initialize the actual calculation */
-
-  init_buffer (&inbuffer, &world, &options, &inpam, &outpam);
-  outrow = pnm_allocpamrow (&outpam);
-  init_interpolation_global_vars (&inbuffer,&inpam,&outpam);
-  switch (options.enums[3]) {   /* --interpolation */
-  case nearest:
-    interpolate = take_nearest;
-    break;
-  case linear:
-    interpolate = linear_interpolation;
-    break;
-  };
 
-  /* Perform the actual calculation */
 
-  for (row=0; row<outpam.height; row++) {
-    for (col=0; col<outpam.width; col++) {
-      outpixel_to_inpixel (col,row,&xi,&yi,&world);
-      interpolate(outrow[col],xi,yi);
-    }
-    pnm_writepamrow (&outpam, outrow);
-  }
+int
+main(int argc, char* argv[]) {
 
-  /* Close everything down nicely */
+    FILE * ifP;
+    struct pam inpam;
+    buffer inbuffer;
+    struct pam outpam;
+    option options;
+    world_data world;
+    interpolateFn * interpolater;
 
-  clean_interpolation_global_vars ();
-  free_buffer (&inbuffer);
-  pnm_freepamrow (outrow);
-  free_option (&options);
-  pm_close (infp);
-  pm_close (outfp);
-  return 0;
-}
+    pnm_init(&argc, argv);
+
+    set_command_line_defaults(&options);
+
+    parse_command_line(argc, argv, &options);
+
+    ifP = pm_openr(options.infilename);
 
+    pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
 
+    /* Our own initializations */
 
+    init_world(&options, &inpam, &world);
+    determine_world_parallelogram(&world, &options);
+    determine_output_width_and_height(&world, &options);
+    switch (options.enums[1]) {   /* --output_system */
+    case lattice:
+        determine_coefficients_lattice(&world, &options);
+        break;
+    case pixel_s:
+        determine_coefficients_pixel(&world, &options);
+        break;
+    };
+
+    outpam.size             = sizeof(outpam);
+    outpam.len              = PAM_STRUCT_SIZE(bytes_per_sample);
+    outpam.file             = stdout;
+    outpam.format           = inpam.format;
+    outpam.plainformat      = FALSE;
+    outpam.height           = options.height;
+    outpam.width            = options.width;
+    outpam.depth            = inpam.depth;
+    outpam.maxval           = inpam.maxval;
+    outpam.bytes_per_sample = inpam.bytes_per_sample;
+    pnm_writepaminit(&outpam);
+
+    /* Initialize the actual calculation */
+
+    init_buffer(&inbuffer, &world, &options, &inpam, &outpam);
+    init_interpolation_global_vars(&inbuffer, &inpam, &outpam);
+    switch (options.enums[3]) {   /* --interpolation */
+    case nearest:
+        interpolater = take_nearest;
+        break;
+    case linear:
+        interpolater = linear_interpolation;
+        break;
+    };
 
+    perspective(&outpam, &world, interpolater);
+
+    clean_interpolation_global_vars();
+    term_buffer(&inbuffer);
+    free_option(&options);
+    pm_close(ifP);
+    pm_close(stdout);
+
+    return 0;
+}
diff --git a/editor/pbmreduce.c b/editor/pbmreduce.c
index 15ec2a1b..f49c8d9a 100644
--- a/editor/pbmreduce.c
+++ b/editor/pbmreduce.c
@@ -91,21 +91,22 @@ main( argc, argv )
     pbm_writepbminit( stdout, newcols, newrows, 0 );
     newbitrow = pbm_allocrow( newcols );
 
-    if ( halftone == QT_FS ) {
+    if (halftone == QT_FS) {
+        unsigned int col;
         /* Initialize Floyd-Steinberg. */
         MALLOCARRAY(thiserr, newcols + 2);
         MALLOCARRAY(nexterr, newcols + 2);
-        if ( thiserr == NULL || nexterr == NULL )
-          pm_error( "out of memory" );
+        if (thiserr == NULL || nexterr == NULL)
+            pm_error("out of memory");
 
-        srand( (int) ( time( 0 ) ^ getpid( ) ) );
-        for ( col = 0; col < newcols + 2; ++col )
-          thiserr[col] = ( rand( ) % SCALE - HALFSCALE ) / 4;
+        srand(pm_randseed());
+        for (col = 0; col < newcols + 2; ++col)
+            thiserr[col] = (rand() % SCALE - HALFSCALE) / 4;
 	    /* (random errors in [-SCALE/8 .. SCALE/8]) */
 	} else {
         /* These variables are meaningless in this case, and the values
            should never be used.
-           */
+        */
         thiserr = NULL;
         nexterr = NULL;
     }
diff --git a/editor/pnmcrop.c b/editor/pnmcrop.c
index 4ef778c3..848fe485 100644
--- a/editor/pnmcrop.c
+++ b/editor/pnmcrop.c
@@ -189,7 +189,7 @@ computeBackground(FILE *         const ifP,
                   xelval         const maxval,
                   int            const format,
                   enum bg_choice const backgroundChoice,
-                  int            const verbose) {
+                  bool           const verbose) {
 /*----------------------------------------------------------------------------
    Determine what color is the background color of the image in file
    *ifP, which is described by 'cols', 'rows', 'maxval', and 'format'.
@@ -549,6 +549,7 @@ main(int argc, char *argv[]) {
         /* The program's regular input file.  Could be a seekable copy of it
            in a temporary file.
         */
+    bool eof;   /* no more images in input stream */
 
     xelval maxval;
     int format;
@@ -567,53 +568,58 @@ main(int argc, char *argv[]) {
 
     ifP = pm_openr_seekable(cmdline.inputFilespec);
 
-    pnm_readpnminit(ifP, &cols, &rows, &maxval, &format);
+    eof = FALSE;
+    while (!eof) {
+        pnm_readpnminit(ifP, &cols, &rows, &maxval, &format);
 
-    pm_tell2(ifP, &rasterpos, sizeof(rasterpos));
+        pm_tell2(ifP, &rasterpos, sizeof(rasterpos));
 
-    background = computeBackground(ifP, cols, rows, maxval, format,
-                                   cmdline.background, cmdline.verbose);
+        background = computeBackground(ifP, cols, rows, maxval, format,
+                                       cmdline.background, cmdline.verbose);
+
+        if (cmdline.borderfile) {
+            findBordersInFile(cmdline.borderfile,
+                              background, cmdline.verbose, &hasBorders,
+                              &oldLeftBorder, &oldRightBorder,
+                              &oldTopBorder,  &oldBottomBorder);
+        } else {
+            pm_seek2(ifP, &rasterpos, sizeof(rasterpos));
+
+            findBordersInImage(ifP, cols, rows, maxval, format, 
+                               background, cmdline.verbose, &hasBorders,
+                               &oldLeftBorder, &oldRightBorder,
+                               &oldTopBorder,  &oldBottomBorder);
+        }
+        if (!hasBorders)
+            pm_error("The image is entirely background; "
+                     "there is nothing to crop.");
+
+        determineNewBorders(cmdline, 
+                            oldLeftBorder, oldRightBorder,
+                            oldTopBorder,  oldBottomBorder,
+                            &newLeftBorder, &newRightBorder,
+                            &newTopBorder,  &newBottomBorder);
+
+        if (cmdline.verbose) 
+            reportCroppingParameters(oldLeftBorder, oldRightBorder,
+                                     oldTopBorder,  oldBottomBorder,
+                                     newLeftBorder, newRightBorder,
+                                     newTopBorder,  newBottomBorder);
 
-    if (cmdline.borderfile) {
-        findBordersInFile(cmdline.borderfile,
-                          background, cmdline.verbose, &hasBorders,
-                          &oldLeftBorder, &oldRightBorder,
-                          &oldTopBorder,  &oldBottomBorder);
-    } else {
         pm_seek2(ifP, &rasterpos, sizeof(rasterpos));
 
-        findBordersInImage(ifP, cols, rows, maxval, format, 
-                           background, cmdline.verbose, &hasBorders,
-                           &oldLeftBorder, &oldRightBorder,
-                           &oldTopBorder,  &oldBottomBorder);
+        writeCropped(ifP, cols, rows, maxval, format,
+                     oldLeftBorder, oldRightBorder,
+                     oldTopBorder,  oldBottomBorder,
+                     newLeftBorder, newRightBorder,
+                     newTopBorder,  newBottomBorder,
+                     background, stdout);
+
+        pnm_nextimage(ifP, &eof);
     }
-    if (!hasBorders)
-        pm_error("The image is entirely background; "
-                 "there is nothing to crop.");
-
-    determineNewBorders(cmdline, 
-                        oldLeftBorder, oldRightBorder,
-                        oldTopBorder,  oldBottomBorder,
-                        &newLeftBorder, &newRightBorder,
-                        &newTopBorder,  &newBottomBorder);
-
-    if (cmdline.verbose) 
-        reportCroppingParameters(oldLeftBorder, oldRightBorder,
-                                 oldTopBorder,  oldBottomBorder,
-                                 newLeftBorder, newRightBorder,
-                                 newTopBorder,  newBottomBorder);
-
-    pm_seek2(ifP, &rasterpos, sizeof(rasterpos));
-
-    writeCropped(ifP, cols, rows, maxval, format,
-                 oldLeftBorder, oldRightBorder,
-                 oldTopBorder,  oldBottomBorder,
-                 newLeftBorder, newRightBorder,
-                 newTopBorder,  newBottomBorder,
-                 background, stdout);
 
     pm_close(stdout);
     pm_close(ifP);
-    
+
     return 0;
 }
diff --git a/editor/pnmflip b/editor/pnmflip
index 6149aaa2..44d95b45 100755
--- a/editor/pnmflip
+++ b/editor/pnmflip
@@ -57,6 +57,7 @@ foreach (@ARGV) {
         if (defined($infile)) {
             print(STDERR
                   "You may specify at most one non-option parameter.\n");
+            exit(10);
         } else {
             $infile = $_;
         }
diff --git a/editor/pnmnlfilt.c b/editor/pnmnlfilt.c
index 20705f82..1f8daac0 100644
--- a/editor/pnmnlfilt.c
+++ b/editor/pnmnlfilt.c
@@ -52,6 +52,63 @@
 #include "pm_c_util.h"
 #include "pnm.h"
 
+struct cmdlineInfo {
+    const char * inputFileName;
+    double alpha;
+    double radius;
+};
+
+
+static void 
+parseCommandLine(int argc, 
+                 char ** argv, 
+                 struct cmdlineInfo  * const cmdlineP) {
+
+    if (argc-1 < 2)
+        pm_error("You must specify at least two arguments: alpha and radius.  "
+                 "You specified %u", argc-1);
+
+    if (sscanf(argv[1], "%lf", &cmdlineP->alpha) != 1)
+        pm_error("Invalid alpha (1st) argument '%s'.  "
+                 "Must be a decimal number",
+                 argv[1]);
+
+    if (sscanf( argv[2], "%lf", &cmdlineP->radius ) != 1)
+        pm_error("Invalid radius (2nd) argument '%s'.  "
+                 "Must be a decimal number", 
+                 argv[2]);
+    
+    if ((cmdlineP->alpha > -0.1 && cmdlineP->alpha < 0.0) ||
+        (cmdlineP->alpha > 0.5 && cmdlineP->alpha < 1.0))
+        pm_error( "Alpha must be in range 0.0 <= alpha <= 0.5 "
+                  "for alpha trimmed mean.  "
+                  "You specified %f", cmdlineP->alpha);
+    if (cmdlineP->alpha > 2.0)
+        pm_error("Alpha must be in range 1.0 <= cmdlineP->alpha <= 2.0 "
+                  "for optimal estimation.  You specified %f",
+                 cmdlineP->alpha);
+
+    if (cmdlineP->alpha < -0.9 ||
+        (cmdlineP->alpha > -0.1 && cmdlineP->alpha < 0.0))
+        pm_error( "Alpha must be in range -0.9 <= alpha <= -0.1 "
+                  "for edge enhancement.  You specified %f",
+                  cmdlineP->alpha);
+
+    if (cmdlineP->radius < 1.0/3 || cmdlineP->radius > 1.0)
+        pm_error("Radius must be in range 1/3 <= radius <= 1. "
+                 "You specified %f", cmdlineP->radius);
+
+    if (argc-1 < 3)
+        cmdlineP->inputFileName = "-";
+    else
+        cmdlineP->inputFileName = argv[3];
+
+    if (argc-1 > 3)
+        pm_error("Too many arguments: %u.  The most allowed are 3: alpha, "
+                 "radius, and file name", argc-1);
+}
+
+
 /* MXIVAL is the maximum input sample value we can handle.
    It is limited by our willingness to allocate storage in various arrays
    that are indexed by sample values.
@@ -756,7 +813,7 @@ atfilt5(int *p) {
 
 
 static void 
-do_one_frame(FILE *ifp) {
+do_one_frame(FILE * const ifP) {
 
     pnm_writepnminit( stdout, cols, rows, omaxval, oformat, 0 );
     
@@ -770,12 +827,12 @@ do_one_frame(FILE *ifp) {
 
             if (row == 0) {
                 irow0 = irow1;
-                pnm_readpnmrow( ifp, irow1, cols, maxval, format );
+                pnm_readpnmrow( ifP, irow1, cols, maxval, format );
             }
             if (row == (rows-1))
                 irow2 = irow1;
             else
-                pnm_readpnmrow( ifp, irow2, cols, maxval, format );
+                pnm_readpnmrow( ifP, irow2, cols, maxval, format );
 
             for (col = cols-1,po= col>0?1:0,no=0,
                      ip0=irow0,ip1=irow1,ip2=irow2,op=orow;
@@ -846,7 +903,7 @@ do_one_frame(FILE *ifp) {
 
             if (row == 0) {
                 irow0 = irow1;
-                pnm_readpnmrow( ifp, irow1, cols, maxval, format );
+                pnm_readpnmrow( ifP, irow1, cols, maxval, format );
                 if ( promote )
                     pnm_promoteformatrow( irow1, cols, maxval, 
                                           format, maxval, oformat );
@@ -854,7 +911,7 @@ do_one_frame(FILE *ifp) {
             if (row == (rows-1))
                 irow2 = irow1;
             else {
-                pnm_readpnmrow( ifp, irow2, cols, maxval, format );
+                pnm_readpnmrow( ifP, irow2, cols, maxval, format );
                 if ( promote )
                     pnm_promoteformatrow( irow2, cols, maxval, 
                                           format, maxval, oformat );
@@ -932,44 +989,18 @@ int (*atfuncs[6]) (int *) = {atfilt0,atfilt1,atfilt2,atfilt3,atfilt4,atfilt5};
 int
 main(int argc, char *argv[]) {
 
-    FILE * ifp;
+    FILE * ifP;
+    struct cmdlineInfo cmdline;
 	bool eof;  /* We've hit the end of the input stream */
     unsigned int imageSeq;  /* Sequence number of image, starting from 0 */
 
-    const char* const usage = "alpha radius pnmfile\n"
-        "0.0 <= alpha <= 0.5 for alpha trimmed mean -or- \n"
-        "1.0 <= alpha <= 2.0 for optimal estimation -or- \n"
-        "-0.1 >= alpha >= -0.9 for edge enhancement\n"
-        "0.3333 <= radius <= 1.0 specify effective radius\n";
+    pnm_init(&argc, argv);
 
-    pnm_init( &argc, argv );
+    parseCommandLine(argc, argv, &cmdline);
 
-    if ( argc < 3 || argc > 4 )
-        pm_usage( usage );
+    ifP = pm_openr(cmdline.inputFileName);
 
-    if ( sscanf( argv[1], "%lf", &alpha ) != 1 )
-        pm_usage( usage );
-    if ( sscanf( argv[2], "%lf", &radius ) != 1 )
-        pm_usage( usage );
-        
-    if ((alpha > -0.1 && alpha < 0.0) || (alpha > 0.5 && alpha < 1.0))
-        pm_error( "Alpha must be in range 0.0 <= alpha <= 0.5 "
-                  "for alpha trimmed mean" );
-    if (alpha > 2.0)
-        pm_error( "Alpha must be in range 1.0 <= alpha <= 2.0 "
-                  "for optimal estimation" );
-    if (alpha < -0.9 || (alpha > -0.1 && alpha < 0.0))
-        pm_error( "Alpha must be in range -0.9 <= alpha <= -0.1 "
-                  "for edge enhancement" );
-    if (radius < 0.333 || radius > 1.0)
-        pm_error( "Radius must be in range 0.333333333 <= radius <= 1.0" );
-
-    if ( argc == 4 )
-        ifp = pm_openr( argv[3] );
-    else
-        ifp = stdin;
-        
-    pnm_readpnminit( ifp, &cols, &rows, &maxval, &format );
+    pnm_readpnminit(ifP, &cols, &rows, &maxval, &format);
         
     if (maxval > MXIVAL) 
         pm_error("The maxval of the input image (%d) is too large.\n"
@@ -983,9 +1014,9 @@ main(int argc, char *argv[]) {
     atfunc = atfuncs[atfilt_setup(alpha, radius,
                                   (double)omaxval/(double)maxval)];
 
-    if ( oformat < PGM_TYPE ) {
+    if (oformat < PGM_TYPE) {
         oformat = RPGM_FORMAT;
-        pm_message( "promoting file to PGM" );
+        pm_message("promoting file to PGM");
     }
 
     orow = pnm_allocrow(cols);
@@ -999,8 +1030,12 @@ main(int argc, char *argv[]) {
     eof = FALSE;  /* We're already in the middle of the first image */
     imageSeq = 0;
     while (!eof) {
-        do_one_frame(ifp);
-        pm_nextimage(ifp, &eof);
+        /* Set the ugly global variables, until we can fix this */
+        alpha = cmdline.alpha;
+        radius = cmdline.radius;
+
+        do_one_frame(ifP);
+        pm_nextimage(ifP, &eof);
         if (!eof) {
             /* Read and validate header of next image */
             int imageCols, imageRows;
@@ -1008,7 +1043,7 @@ main(int argc, char *argv[]) {
             int imageFormat;
 
             ++imageSeq;
-            pnm_readpnminit(ifp, &imageCols, &imageRows, 
+            pnm_readpnminit(ifP, &imageCols, &imageRows, 
                             &imageMaxval, &imageFormat);
             verifySame(imageSeq,
                        imageCols, imageRows, imageMaxval, imageFormat,
@@ -1020,9 +1055,7 @@ main(int argc, char *argv[]) {
     pnm_freerow(irow1);
     pnm_freerow(irow2);
     pnm_freerow(orow);
-    pm_close(ifp);
+    pm_close(ifP);
 
     return 0;
 }
-
-
diff --git a/editor/pnmremap.c b/editor/pnmremap.c
index 2102fe63..e9466fe5 100644
--- a/editor/pnmremap.c
+++ b/editor/pnmremap.c
@@ -299,7 +299,7 @@ initFserr(struct pam *   const pamP,
                      "for Plane %u, size %u", plane, fserrSize);
     }
 
-    srand((int)(time(0) ^ getpid()));
+    srand(pm_randseed());
 
     {
         int col;
diff --git a/editor/pnmrotate.c b/editor/pnmrotate.c
index d3f92342..a8cf62b0 100644
--- a/editor/pnmrotate.c
+++ b/editor/pnmrotate.c
@@ -15,9 +15,10 @@
 #include <math.h>
 #include <assert.h>
 
-#include "pnm.h"
-#include "shhopt.h"
 #include "mallocvar.h"
+#include "shhopt.h"
+#include "ppm.h"
+#include "pnm.h"
 
 #define SCALE 4096
 #define HALFSCALE 2048
@@ -159,27 +160,6 @@ computeNewFormat(bool     const antialias,
 
 
 
-static bool
-isWhite(xel    const color,
-        xelval const maxval) {
-
-    return (PPM_GETR(color) == maxval &&
-            PPM_GETG(color) == maxval &&
-            PPM_GETB(color) == maxval);
-}
-
-
-
-static bool
-isBlack(xel const color) {
-
-    return (PPM_GETR(color) == 0 &&
-            PPM_GETG(color) == 0 &&
-            PPM_GETB(color) == 0);
-}
-
-
-
 static xel
 backgroundColor(const char * const backgroundColorName,
                 xel *        const topRow,
@@ -190,24 +170,7 @@ backgroundColor(const char * const backgroundColorName,
     xel retval;
 
     if (backgroundColorName) {
-        retval = ppm_parsecolor(backgroundColorName, maxval);
-
-        switch(PNM_FORMAT_TYPE(format)) {
-        case PGM_TYPE:
-            if (!PPM_ISGRAY(retval))
-                pm_error("Image is PGM (grayscale), "
-                         "but you specified a non-gray "
-                         "background color '%s'", backgroundColorName);
-
-            break;
-        case PBM_TYPE:
-            if (!isWhite(retval, maxval) && !isBlack(retval))
-                pm_error("Image is PBM (black and white), "
-                         "but you specified '%s', which is neither black "
-                         "nor white, as background color", 
-                         backgroundColorName);
-            break;
-        }
+        retval = pnm_parsecolorxel(backgroundColorName, maxval, format);
     } else 
         retval = pnm_backgroundxelrow(topRow, cols, maxval, format);
 
diff --git a/editor/pnmshear.c b/editor/pnmshear.c
index 1b2d36a8..9fd788a5 100644
--- a/editor/pnmshear.c
+++ b/editor/pnmshear.c
@@ -12,9 +12,11 @@
 
 #define _XOPEN_SOURCE   /* get M_PI in math.h */
 
+#include <assert.h>
 #include <math.h>
 #include <string.h>
 
+#include "ppm.h"
 #include "pnm.h"
 #include "shhopt.h"
 
@@ -28,26 +30,34 @@ struct cmdline_info {
     const char *       input_filespec;  /* Filespec of input file */
     double       angle;           /* requested shear angle, in radians */
     unsigned int noantialias;     /* -noantialias option */
+    const char * background;      /* NULL if none */
 };
 
 
 
 static void
-parse_command_line(int argc, char ** argv,
-                   struct cmdline_info *cmdlineP) {
+parseCommandLine(int argc, char ** argv,
+                 struct cmdline_info *cmdlineP) {
 
     optStruct3 opt;
     unsigned int option_def_index = 0;
     optEntry *option_def = malloc(100*sizeof(optEntry));
 
+    unsigned int backgroundSpec;
+
     OPTENT3(0, "noantialias",      OPT_FLAG,  NULL, &cmdlineP->noantialias, 0);
+    OPTENT3(0, "background",       OPT_STRING, &cmdlineP->background,
+            &backgroundSpec, 0);
     
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;
     opt.allowNegNum = TRUE;
 
     optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
-    
+
+    if (!backgroundSpec)
+        cmdlineP->background = NULL;
+
     if (argc-1 < 1)
         pm_error("Need an argument:  the shear angle.\n");
     else {
@@ -69,9 +79,14 @@ parse_command_line(int argc, char ** argv,
 }
 
 
+
 static void
-makeNewXel(xel * const outputXelP, xel const curXel, xel const prevXel,
-           double const fracnew0, double const omfracnew0, int const format) {
+makeNewXel(xel *  const outputXelP,
+           xel    const curXel,
+           xel    const prevXel,
+           double const fracnew0,
+           double const omfracnew0,
+           int    const format) {
 /*----------------------------------------------------------------------------
    Create an output xel as *outputXel, which is part curXel and part
    prevXel, the part given by the fractions omfracnew0 and fracnew0,
@@ -81,35 +96,40 @@ makeNewXel(xel * const outputXelP, xel const curXel, xel const prevXel,
    The format of the pixel is 'format'.
 -----------------------------------------------------------------------------*/
 
-    switch ( PNM_FORMAT_TYPE(format) ) {
+    switch (PNM_FORMAT_TYPE(format)) {
     case PPM_TYPE:
-        PPM_ASSIGN( *outputXelP,
-                    ( fracnew0 * PPM_GETR(prevXel) 
-                      + omfracnew0 * PPM_GETR(curXel) 
-                      + HALFSCALE ) / SCALE,
-                    ( fracnew0 * PPM_GETG(prevXel) 
-                      + omfracnew0 * PPM_GETG(curXel) 
-                      + HALFSCALE ) / SCALE,
-                    ( fracnew0 * PPM_GETB(prevXel) 
-                      + omfracnew0 * PPM_GETB(curXel) 
-                      + HALFSCALE ) / SCALE );
+        PPM_ASSIGN(*outputXelP,
+                   (fracnew0 * PPM_GETR(prevXel) 
+                    + omfracnew0 * PPM_GETR(curXel) 
+                    + HALFSCALE) / SCALE,
+                   (fracnew0 * PPM_GETG(prevXel) 
+                    + omfracnew0 * PPM_GETG(curXel) 
+                    + HALFSCALE) / SCALE,
+                   (fracnew0 * PPM_GETB(prevXel) 
+                    + omfracnew0 * PPM_GETB(curXel) 
+                    + HALFSCALE) / SCALE );
         break;
         
     default:
-        PNM_ASSIGN1( *outputXelP,
-                     ( fracnew0 * PNM_GET1(prevXel) 
-                       + omfracnew0 * PNM_GET1(curXel) 
-                       + HALFSCALE ) / SCALE );
+        PNM_ASSIGN1(*outputXelP,
+                    (fracnew0 * PNM_GET1(prevXel) 
+                     + omfracnew0 * PNM_GET1(curXel) 
+                     + HALFSCALE) / SCALE );
         break;
     }
 }
 
 
+
 static void
-shear_row(xel * const xelrow, int const cols, 
-          xel * const newxelrow, int const newcols, 
-          double const shearCols,
-          int const format, xel const bgxel, bool const antialias) {
+shearRow(xel *        const xelrow,
+         unsigned int const cols, 
+         xel *        const newxelrow,
+         unsigned int const newcols, 
+         double       const shearCols,
+         int          const format,
+         xel          const bgxel,
+         bool         const antialias) {
 /*----------------------------------------------------------------------------
    Shear the row 'xelrow' by 'shearCols' columns, and return the result as
    'newxelrow'.  They are 'cols' and 'newcols' columns wide, respectively.
@@ -122,47 +142,68 @@ shear_row(xel * const xelrow, int const cols,
    The format of the input xels (which implies something about the
    output xels too) is 'format'.
 -----------------------------------------------------------------------------*/
-    int const intShearCols = (int) shearCols;
+    unsigned int const intShearCols = (unsigned int) shearCols;
+
+    assert(shearCols >= 0.0);
         
-    if ( antialias ) {
-        const long fracnew0 = ( shearCols - intShearCols ) * SCALE;
+    if (antialias) {
+        const long fracnew0 = (shearCols - intShearCols) * SCALE;
         const long omfracnew0 = SCALE - fracnew0;
 
-        int col;
+        unsigned int col;
         xel prevXel;
             
-        for ( col = 0; col < newcols; ++col )
+        for (col = 0; col < newcols; ++col)
             newxelrow[col] = bgxel;
 
         prevXel = bgxel;
-        for ( col = 0; col < cols; ++col){
+        for (col = 0; col < cols; ++col) {
             makeNewXel(&newxelrow[intShearCols + col],
                        xelrow[col], prevXel, fracnew0, omfracnew0,
                        format);
             prevXel = xelrow[col];
         }
-        if ( fracnew0 > 0 ) 
+        if (fracnew0 > 0) 
             /* Need to add a column for what's left over */
             makeNewXel(&newxelrow[intShearCols + cols],
                        bgxel, prevXel, fracnew0, omfracnew0, format);
     } else {
-        int col;
-        for ( col = 0; col < intShearCols; ++col )
+        unsigned int col;
+        for (col = 0; col < intShearCols; ++col)
             newxelrow[col] = bgxel;
-        for ( col = 0; col < cols; ++col )
+        for (col = 0; col < cols; ++col)
             newxelrow[intShearCols+col] = xelrow[col];
-        for ( col = intShearCols + cols; col < newcols; ++col )
+        for (col = intShearCols + cols; col < newcols; ++col)
             newxelrow[col] = bgxel;
     }
 }
 
 
+static xel
+backgroundColor(const char * const backgroundColorName,
+                xel *        const topRow,
+                int          const cols,
+                xelval       const maxval,
+                int          const format) {
+
+    xel retval;
+
+    if (backgroundColorName) {
+        retval = pnm_parsecolorxel(backgroundColorName, maxval, format);
+    } else 
+        retval = pnm_backgroundxelrow(topRow, cols, maxval, format);
+
+    return retval;
+}
+
+
 
 int
 main(int argc, char * argv[]) {
-    FILE* ifp;
-    xel* xelrow;
-    xel* newxelrow;
+
+    FILE * ifP;
+    xel * xelrow;
+    xel * newxelrow;
     xel bgxel;
     int rows, cols, format; 
     int newformat, newcols; 
@@ -172,56 +213,54 @@ main(int argc, char * argv[]) {
 
     struct cmdline_info cmdline;
 
-    pnm_init( &argc, argv );
+    pnm_init(&argc, argv);
 
-    parse_command_line( argc, argv, &cmdline );
+    parseCommandLine(argc, argv, &cmdline);
 
-    ifp = pm_openr( cmdline.input_filespec );
+    ifP = pm_openr(cmdline.input_filespec);
 
-    pnm_readpnminit( ifp, &cols, &rows, &maxval, &format );
-    xelrow = pnm_allocrow( cols );
+    pnm_readpnminit(ifP, &cols, &rows, &maxval, &format);
+    xelrow = pnm_allocrow(cols);
 
     /* Promote PBM files to PGM. */
-    if ( !cmdline.noantialias && PNM_FORMAT_TYPE(format) == PBM_TYPE ) {
+    if (!cmdline.noantialias && PNM_FORMAT_TYPE(format) == PBM_TYPE) {
         newformat = PGM_TYPE;
         newmaxval = PGM_MAXMAXVAL;
-        pm_message( "promoting from PBM to PGM - "
-                    "use -noantialias to avoid this" );
+        pm_message("promoting from PBM to PGM - "
+                   "use -noantialias to avoid this");
     } else {
         newformat = format;
         newmaxval = maxval;
     }
 
-    shearfac = tan( cmdline.angle );
-    if ( shearfac < 0.0 )
-        shearfac = -shearfac;
+    shearfac = fabs(tan(cmdline.angle));
 
     newcols = rows * shearfac + cols + 0.999999;
 
-    pnm_writepnminit( stdout, newcols, rows, newmaxval, newformat, 0 );
-    newxelrow = pnm_allocrow( newcols );
-
-    bgxel = pnm_backgroundxelrow( xelrow, cols, newmaxval, format );
+    pnm_writepnminit(stdout, newcols, rows, newmaxval, newformat, 0);
+    newxelrow = pnm_allocrow(newcols);
+    
+    bgxel = backgroundColor(cmdline.background, xelrow, cols, newmaxval,
+                            format);
 
-    for ( row = 0; row < rows; ++row ) {
+    for (row = 0; row < rows; ++row) {
         double shearCols;
 
-        pnm_readpnmrow( ifp, xelrow, cols, newmaxval, format );
+        pnm_readpnmrow(ifP, xelrow, cols, newmaxval, format);
 
-        if ( cmdline.angle > 0.0 )
+        if (cmdline.angle > 0.0)
             shearCols = row * shearfac;
         else
-            shearCols = ( rows - row ) * shearfac;
+            shearCols = (rows - row) * shearfac;
 
-        shear_row(xelrow, cols, newxelrow, newcols, 
+        shearRow(xelrow, cols, newxelrow, newcols, 
                   shearCols, format, bgxel, !cmdline.noantialias);
 
-        pnm_writepnmrow( stdout, newxelrow, newcols, newmaxval, newformat, 0 );
+        pnm_writepnmrow(stdout, newxelrow, newcols, newmaxval, newformat, 0);
     }
+    
+    pm_close(ifP);
+    pm_close(stdout);
 
-    pm_close( ifp );
-    pm_close( stdout );
-
-    exit( 0 );
+    return 0;
 }
-
diff --git a/editor/ppmchange.c b/editor/ppmchange.c
index 6d3839bd..1b1aa3ca 100644
--- a/editor/ppmchange.c
+++ b/editor/ppmchange.c
@@ -144,22 +144,22 @@ changeRow(const pixel * const inrow,
    The input row is 'inrow'.  The output is returned as 'outrow', in
    storage which must be already allocated.  Both are 'cols' columns wide.
 -----------------------------------------------------------------------------*/
-    int col;
+    unsigned int col;
 
     for (col = 0; col < cols; ++col) {
-        int i;
-        int have_match; /* logical: It's a color user said to change */
+        unsigned int i;
+        bool haveMatch; /* logical: It's a color user said to change */
         pixel newcolor;  
         /* Color to which we must change current pixel.  Undefined unless
-           'have_match' is true.
+           'haveMatch' is true.
         */
 
-        have_match = FALSE;  /* haven't found a match yet */
-        for (i = 0; i < ncolors && !have_match; ++i) {
-            have_match = colormatch(inrow[col], colorfrom[i], closeness);
+        haveMatch = FALSE;  /* haven't found a match yet */
+        for (i = 0; i < ncolors && !haveMatch; ++i) {
+            haveMatch = colormatch(inrow[col], colorfrom[i], closeness);
             newcolor = colorto[i];
         }
-        if (have_match)
+        if (haveMatch)
             outrow[col] = newcolor;
         else if (remainder_specified)
             outrow[col] = remainder_color;
diff --git a/editor/ppmshift.c b/editor/ppmshift.c
index 1f8a599b..a765daa5 100644
--- a/editor/ppmshift.c
+++ b/editor/ppmshift.c
@@ -11,127 +11,122 @@
 
 #include "ppm.h"
 
-/* global variables */
-#ifdef AMIGA
-static char *version = "$VER: ppmshift 1.1 (16.11.93)"; /* Amiga version identification */
-#endif
-
 /**************************/
 /* start of main function */
 /**************************/
-int main(argc, argv)
-int argc;
-char *argv[];
-{
-	FILE* ifp;
-	time_t timenow;
-	int argn, rows, cols, format, i = 0, j = 0;
-	pixel *srcrow, *destrow;
-	pixel *pP = NULL, *pP2 = NULL;
-	pixval maxval;
-	int shift, nowshift;
-	const char * const usage = "shift [ppmfile]\n        shift: maximum number of pixels to shift a line by\n";
-
-	/* parse in 'default' parameters */
-	ppm_init(&argc, argv);
-
-	argn = 1;
-
-	/* parse in shift number */
-	if (argn == argc)
-		pm_usage(usage);
-	if (sscanf(argv[argn], "%d", &shift) != 1)
-		pm_usage(usage);
-	if (shift < 0)
-		pm_error("shift factor must be 0 or more");
-	++argn;
-
-	/* parse in filename (if present, stdin otherwise) */
-	if (argn != argc)
-	{
-		ifp = pm_openr(argv[argn]);
-		++argn;
-	}
-	else
-		ifp = stdin;
-
-	if (argn != argc)
-		pm_usage(usage);
-
-	/* read first data from file */
-	ppm_readppminit(ifp, &cols, &rows, &maxval, &format);
-
-	if (shift > cols)
+int
+main(int    argc,
+     char * argv[]) {
+
+    FILE * ifP;
+    unsigned int row;
+    int argn, rows, cols, format;
+    pixel * srcrow;
+    pixel * destrow;
+    pixval maxval;
+    int shift, nowshift;
+    int shiftArg;
+
+    const char * const usage = "shift [ppmfile]\n        shift: maximum number of pixels to shift a line by\n";
+
+    /* parse in 'default' parameters */
+    ppm_init(&argc, argv);
+
+    argn = 1;
+
+    /* parse in shift number */
+    if (argn == argc)
+        pm_usage(usage);
+    if (sscanf(argv[argn], "%d", &shiftArg) != 1)
+        pm_usage(usage);
+    if (shiftArg < 0)
+        pm_error("shift factor must be 0 or more");
+    ++argn;
+
+    /* parse in filename (if present, stdin otherwise) */
+    if (argn != argc)
     {
-		shift = cols;
-        pm_message("shift amount is larger than picture width - reset to %d", shift);
+        ifP = pm_openr(argv[argn]);
+        ++argn;
     }
+    else
+        ifP = stdin;
+
+    if (argn != argc)
+        pm_usage(usage);
+
+    /* read first data from file */
+    ppm_readppminit(ifP, &cols, &rows, &maxval, &format);
+
+    if (shiftArg > cols) {
+        shift = cols;
+        pm_message("shift amount is larger than picture width - reset to %d",
+                   shift);
+    } else
+        shift = shiftArg;
 
-	/* no error checking required here, ppmlib does it all for us */
-	srcrow = ppm_allocrow(cols);
+    srcrow = ppm_allocrow(cols);
 
-	/* allocate a row of pixel data for the new pixels */
-	destrow = ppm_allocrow(cols);
+    destrow = ppm_allocrow(cols);
 
-	ppm_writeppminit(stdout, cols, rows, maxval, 0);
+    ppm_writeppminit(stdout, cols, rows, maxval, 0);
 
-	/* get time of day to feed the random number generator */
-	timenow = time(NULL);
-	srand(timenow);
+    srand(pm_randseed());
 
-	/** now do the shifting **/
-	/* the range by which a line is shifted lays in the range from */
-	/* -shift/2 .. +shift/2 pixels; however, within this range it is */
+    /** now do the shifting **/
+    /* the range by which a line is shifted lays in the range from */
+    /* -shift/2 .. +shift/2 pixels; however, within this range it is */
     /* randomly chosen */
-	for (i = 0; i < rows; i++)
-	{
-		if (shift != 0)
-			nowshift = (rand() % (shift+1)) - ((shift+1) / 2);
-		else
-			nowshift = 0;
-
-		ppm_readppmrow(ifp, srcrow, cols, maxval, format);
-
-		pP = srcrow;
-		pP2 = destrow;
-
-		/* if the shift value is less than zero, we take the original pixel line and */
-		/* copy it into the destination line translated to the left by x pixels. The */
-        /* empty pixels on the right end of the destination line are filled up with  */
-		/* the pixel that is the right-most in the original pixel line.              */
-		if (nowshift < 0)
-		{
-			pP+= abs(nowshift);
-			for (j = 0; j < cols; j++)
-			{
-				PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP));
-				pP2++;
-                if (j < (cols+nowshift)-1)
-					pP++;
-			}
-		}
-		/* if the shift value is 0 or positive, the first <nowshift> pixels of the */
-		/* destination line are filled with the first pixel from the source line,  */
-		/* and the rest of the source line is copied to the dest line              */
-		else
-		{
-			for (j = 0; j < cols; j++)
-			{
-				PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP));
-				pP2++;
-                if (j >= nowshift)
-					pP++;
-			}
-		}
-
-		/* write out one line of graphic data */
-		ppm_writeppmrow(stdout, destrow, cols, maxval, 0);
-	}
-
-	pm_close(ifp);
-	ppm_freerow(srcrow);
-	ppm_freerow(destrow);
-
-	exit(0);
-}
+    for (row = 0; row < rows; ++row) {
+        pixel * pP;
+        pixel * pP2;
+
+        if (shift != 0)
+            nowshift = (rand() % (shift+1)) - ((shift+1) / 2);
+        else
+            nowshift = 0;
+
+        ppm_readppmrow(ifP, srcrow, cols, maxval, format);
+
+        pP  = &srcrow[0];
+        pP2 = &destrow[0];
+
+        /* if the shift value is less than zero, we take the original
+           pixel line and copy it into the destination line translated
+           to the left by x pixels. The empty pixels on the right end
+           of the destination line are filled up with the pixel that
+           is the right-most in the original pixel line.
+        */
+        if (nowshift < 0) {
+            unsigned int col;
+            pP += abs(nowshift);
+            for (col = 0; col < cols; ++col) {
+                PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP));
+                ++pP2;
+                if (col < (cols + nowshift) - 1)
+                    ++pP;
+            }
+        } else {
+            unsigned int col;
+            /* The shift value is 0 or positive, so fill the first
+               <nowshift> pixels of the destination line with the
+               first pixel from the source line, and copy the rest of
+               the source line to the dest line
+            */
+            for (col = 0; col < cols; ++col) {
+                PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP));
+                ++pP2;
+                if (col >= nowshift)
+                    ++pP;
+            }
+        }
+
+        ppm_writeppmrow(stdout, destrow, cols, maxval, 0);
+    }
 
+    pm_close(ifP);
+    ppm_freerow(srcrow);
+    ppm_freerow(destrow);
+
+    return 0;
+}
diff --git a/editor/ppmspread.c b/editor/ppmspread.c
index 569d1266..6753f4fe 100644
--- a/editor/ppmspread.c
+++ b/editor/ppmspread.c
@@ -9,119 +9,109 @@
 /*********************************************************************/
 
 #include <string.h>
+
 #include "ppm.h"
 
-/* global variables */
-#ifdef AMIGA
-static char *version = "$VER: ppmspread 1.1 (16.11.93)"; /* Amiga version identification */
-#endif
-
-/**************************/
-/* start of main function */
-/**************************/
-int main(argc, argv)
-int argc;
-char *argv[];
-{
-	FILE* ifp;
-	int argn, rows, cols, i, j;
-	int xdis, ydis, xnew, ynew;
-	pixel **destarray, **srcarray;
-	pixel *pP, *pP2;
-	pixval maxval;
-	pixval r1, g1, b1;
-	int amount;
-	time_t timenow;
-	const char * const usage = "amount [ppmfile]\n        amount: # of pixels to displace a pixel by at most\n";
-
-	/* parse in 'default' parameters */
-	ppm_init(&argc, argv);
-
-	argn = 1;
-
-	/* parse in amount & seed */
-	if (argn == argc)
-		pm_usage(usage);
-	if (sscanf(argv[argn], "%d", &amount) != 1)
-		pm_usage(usage);
-	if (amount < 0)
-		pm_error("amount should be a positive number");
-	++argn;
-
-	/* parse in filename (if present, stdin otherwise) */
-	if (argn != argc)
-	{
-		ifp = pm_openr(argv[argn]);
-		++argn;
-	}
-	else
-		ifp = stdin;
-
-	if (argn != argc)
-		pm_usage(usage);
-
-	/* read entire picture into buffer */
-	srcarray = ppm_readppm(ifp, &cols, &rows, &maxval);
-
-	/* allocate an entire picture buffer for dest picture */
-	destarray = ppm_allocarray(cols, rows);
-
-	/* clear out the buffer */
-	for (i=0; i < rows; i++)
-		memset(destarray[i], 0, cols * sizeof(pixel));
-
-	/* set seed for random number generator */
-	/* get time of day to feed the random number generator */
-	timenow = time(NULL);
-	srand(timenow);
-
-	/* start displacing pixels */
-	for (i = 0; i < rows; i++)
-	{
-		pP = srcarray[i];
-
-		for (j = 0; j < cols; j++)
-		{
-			xdis = (rand() % (amount+1)) - ((amount+1) / 2);
-			ydis = (rand() % (amount+1)) - ((amount+1) / 2);
-
-			xnew = j + xdis;
-			ynew = i + ydis;
-
-			/* only set the displaced pixel if it's within the bounds of the image */
-			if (xnew >= 0 && xnew < cols && ynew >= 0 && ynew < rows)
-			{
-				/* displacing a pixel is accomplished by swapping it with another */
-				/* pixel in its vicinity - so, first store other pixel's RGB      */
-                pP2 = srcarray[ynew] + xnew;
-				r1 = PPM_GETR(*pP2);
-				g1 = PPM_GETG(*pP2);
-				b1 = PPM_GETB(*pP2);
-				/* set second pixel to new value */
-				pP2 = destarray[ynew] + xnew;
-				PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP));
-
-				/* now, set first pixel to (old) value of second */
-				pP2 = destarray[i] + j;
-				PPM_ASSIGN(*pP2, r1, g1, b1);
-			}
-			else
-			{
-                /* displaced pixel is out of bounds; leave the old pixel there */
-                pP2 = destarray[i] + j;
-				PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP));
-			}
-			pP++;
-		}
-	}
-
-	/* write out entire dest picture in one go */
-	ppm_writeppm(stdout, destarray, cols, rows, maxval, 0);
-
-	pm_close(ifp);
-	ppm_freearray(srcarray, rows);
-	ppm_freearray(destarray, rows);
-
-	exit(0);
-}
 
+
+int
+main(int    argc,
+     char * argv[]) {
+
+    FILE * ifP;
+    int argn, rows, cols;
+    unsigned int row;
+    pixel ** destarray, ** srcarray;
+    pixel * pP;
+    pixel * pP2;
+    pixval maxval;
+    pixval r1, g1, b1;
+    int amount;
+    const char * const usage = "amount [ppmfile]\n        amount: # of pixels to displace a pixel by at most\n";
+
+    /* parse in 'default' parameters */
+    ppm_init(&argc, argv);
+
+    argn = 1;
+
+    /* parse in amount & seed */
+    if (argn == argc)
+        pm_usage(usage);
+    if (sscanf(argv[argn], "%d", &amount) != 1)
+        pm_usage(usage);
+    if (amount < 0)
+        pm_error("amount should be a positive number");
+    ++argn;
+
+    /* parse in filename (if present, stdin otherwise) */
+    if (argn != argc)
+    {
+        ifP = pm_openr(argv[argn]);
+        ++argn;
+    }
+    else
+        ifP = stdin;
+
+    if (argn != argc)
+        pm_usage(usage);
+
+    srcarray = ppm_readppm(ifP, &cols, &rows, &maxval);
+
+    destarray = ppm_allocarray(cols, rows);
+
+    /* clear out the buffer */
+    for (row = 0; row < rows; ++row)
+        memset(destarray[row], 0, cols * sizeof(pixel));
+
+    srand(pm_randseed());
+
+    /* start displacing pixels */
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        pP = &srcarray[row][0];
+
+        for (col = 0; col < cols; ++col) {
+            int const xdis = (rand() % (amount+1)) - ((amount+1) / 2);
+            int const ydis = (rand() % (amount+1)) - ((amount+1) / 2);
+
+            int const xnew = col + xdis;
+            int const ynew = row + ydis;
+
+            /* only set the displaced pixel if it's within the bounds
+               of the image
+            */
+            if (xnew >= 0 && xnew < cols && ynew >= 0 && ynew < rows) {
+                /* displacing a pixel is accomplished by swapping it
+                   with another pixel in its vicinity - so, first
+                   store other pixel's RGB
+                */
+                pP2 = &srcarray[ynew][xnew];
+                r1 = PPM_GETR(*pP2);
+                g1 = PPM_GETG(*pP2);
+                b1 = PPM_GETB(*pP2);
+                /* set second pixel to new value */
+                pP2 = &destarray[ynew][xnew];
+                PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP));
+                
+                /* now, set first pixel to (old) value of second */
+                pP2 = &destarray[row][col];
+                PPM_ASSIGN(*pP2, r1, g1, b1);
+            } else {
+                /* displaced pixel is out of bounds; leave the old
+                   pixel there
+                */
+                pP2 = &destarray[row][col];
+                PPM_ASSIGN(*pP2, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP));
+            }
+            ++pP;
+        }
+    }
+
+    ppm_writeppm(stdout, destarray, cols, rows, maxval, 0);
+
+    pm_close(ifP);
+    ppm_freearray(srcarray, rows);
+    ppm_freearray(destarray, rows);
+
+    return 0;
+}
diff --git a/generator/pbmtextps.c b/generator/pbmtextps.c
index ef8ae008..f4fa8b14 100644
--- a/generator/pbmtextps.c
+++ b/generator/pbmtextps.c
@@ -17,13 +17,16 @@
  */
 #define _XOPEN_SOURCE   /* Make sure popen() is in stdio.h */
 #define _BSD_SOURCE     /* Make sure stdrup() is in string.h */
+#include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include "pbm.h"
+
+#include "mallocvar.h"
 #include "nstring.h"
 #include "shhopt.h"
+#include "pbm.h"
 
 
 #define BUFFER_SIZE 2048
@@ -58,21 +61,51 @@ struct cmdlineInfo {
 
 
 static void
+buildTextFromArgs(int           const argc,
+                  char **       const argv,
+                  const char ** const textP) {
+
+    char * text;
+    unsigned int totalTextSize;
+    unsigned int i;
+
+    text = strdup("");
+    totalTextSize = 1;
+
+    for (i = 1; i < argc; ++i) {
+        if (i > 1) {
+            totalTextSize += 1;
+            text = realloc(text, totalTextSize);
+            if (text == NULL)
+                pm_error("out of memory");
+            strcat(text, " ");
+        } 
+        totalTextSize += strlen(argv[i]);
+        text = realloc(text, totalTextSize);
+        if (text == NULL)
+            pm_error("out of memory");
+        strcat(text, argv[i]);
+    }
+    *textP = text;
+}
+
+
+
+static void
 parseCommandLine(int argc, char ** argv,
                  struct cmdlineInfo *cmdlineP) {
 /*---------------------------------------------------------------------------
   Note that the file spec array we return is stored in the storage that
   was passed to us as the argv array.
 ---------------------------------------------------------------------------*/
-    optEntry *option_def = malloc(100*sizeof(optEntry));
+    optEntry * option_def;
     /* Instructions to OptParseOptions2 on how to parse our options.
    */
     optStruct3 opt;
 
     unsigned int option_def_index;
-    int i;
-    char * text;
-    int totaltextsize = 0;
+
+    MALLOCARRAY(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENTRY */
     OPTENT3(0, "resolution", OPT_INT,    &cmdlineP->res,            NULL,  0);
@@ -93,23 +126,7 @@ parseCommandLine(int argc, char ** argv,
 
     optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
 
-    text = NULL;
-
-    for (i = 1; i < argc; i++) {
-        if (i > 1) {
-            totaltextsize += 1;
-            text = realloc(text, totaltextsize);
-            if (text == NULL)
-                pm_error("out of memory");
-            strcat(text, " ");
-        } 
-        totaltextsize += strlen(argv[i]);
-        text = realloc(text, totaltextsize);
-        if (text == NULL)
-            pm_error("out of memory");
-        strcat(text, argv[i]);
-    }
-    cmdlineP->text = text;
+    buildTextFromArgs(argc, argv, &cmdlineP->text);
 }
 
 
@@ -233,7 +250,7 @@ static void
 writeProgram(const char *       const psFname,
              struct cmdlineInfo const cmdline) {
 
-    const char *ps;
+    const char * ps;
     FILE * psfile;
 
     psfile = fopen(psFname, "w");
diff --git a/generator/pbmupc.c b/generator/pbmupc.c
index 5f694a00..6ef75654 100644
--- a/generator/pbmupc.c
+++ b/generator/pbmupc.c
@@ -433,17 +433,8 @@ putdigit( d, bits, row0, col0 )
 	    bits[row0 + row][col0 + col] = digits[d][row][col];
     }
 
-#if __STDC__
 static int
 addlines( int d, bit** bits, int row0, int col0, int height, bit color )
-#else /*__STDC__*/
-static int
-addlines( d, bits, row0, col0, height, color )
-    int d;
-    bit** bits;
-    int row0, col0, height;
-    bit color;
-#endif /*__STDC__*/
     {
     switch ( d )
 	{
@@ -524,16 +515,8 @@ addlines( d, bits, row0, col0, height, color )
     return col0;
     }
 
-#if __STDC__
 static int
 rect( bit** bits, int row0, int col0, int height, int width, bit color )
-#else /*__STDC__*/
-static int
-rect( bits, row0, col0, height, width, color )
-    bit** bits;
-    int row0, col0, height, width;
-    bit color;
-#endif /*__STDC__*/
     {
     int row, col;
 
diff --git a/generator/pgmcrater.c b/generator/pgmcrater.c
index 1833e604..ec592381 100644
--- a/generator/pgmcrater.c
+++ b/generator/pgmcrater.c
@@ -106,11 +106,10 @@ static int modulo(int t, int n)
 
 static void initseed()
 {
-    int i;
+    unsigned int i;
 
-    i = time(NULL) * 0xF37C;
-    srand(i);
-    for (i = 0; i < 7; i++) 
+    srand(pm_randseed());
+    for (i = 0; i < 7; ++i) 
         V rand();
 }
 
diff --git a/generator/pgmnoise.c b/generator/pgmnoise.c
index 3929759b..643f260f 100644
--- a/generator/pgmnoise.c
+++ b/generator/pgmnoise.c
@@ -11,67 +11,56 @@
 
 #include "pgm.h"
 
-/* global variables */
-#ifdef AMIGA
-static char *version = "$VER: pgmnoise 1.1 (16.11.93)"; /* Amiga version identification */
-#endif
-
-/**************************/
-/* start of main function */
-/**************************/
-int main(argc, argv)
-int argc;
-char *argv[];
-{
-	int argn, rows, cols, i, j;
-	gray *destrow;
-	const char * const usage = "width height\n        width and height are picture dimensions in pixels\n";
-	time_t timenow;
-
-	/* parse in 'default' parameters */
-	pgm_init(&argc, argv);
-
-	argn = 1;
-
-	/* parse in dim factor */
-	if (argn == argc)
-		pm_usage(usage);
-	if (sscanf(argv[argn], "%d", &cols) != 1)
-		pm_usage(usage);
-	argn++;
-	if (argn == argc)
-		pm_usage(usage);
-	if (sscanf(argv[argn], "%d", &rows) != 1)
-		pm_usage(usage);
-
-	if (cols <= 0 || rows <= 0)
-		pm_error("picture dimensions should be positive numbers");
-	++argn;
-
-	if (argn != argc)
-		pm_usage(usage);
-
-	/* no error checking required here, ppmlib does it all for us */
-	destrow = pgm_allocrow(cols);
-
-	pgm_writepgminit(stdout, cols, rows, PGM_MAXMAXVAL, 0);
-
-	/* get time of day to feed the random number generator */
-	timenow = time(NULL);
-	srand(timenow);
-
-	/* create the (gray) noise */
-	for (i = 0; i < rows; i++)
-	{
-		for (j = 0; j < cols; j++)
-			destrow[j] = rand() % PGM_MAXMAXVAL;
-
-		/* write out one line of graphic data */
-		pgm_writepgmrow(stdout, destrow, cols, PGM_MAXMAXVAL, 0);
-	}
-
-	pgm_freerow(destrow);
-
-	exit(0);
-}
 
+int main(int    argc,
+         char * argv[]) {
+
+    int argn, rows, cols;
+    unsigned int row;
+    gray * destrow;
+
+    const char * const usage = "width height\n        width and height are picture dimensions in pixels\n";
+
+    /* parse in 'default' parameters */
+    pgm_init(&argc, argv);
+
+    argn = 1;
+
+    /* parse in dim factor */
+    if (argn == argc)
+        pm_usage(usage);
+    if (sscanf(argv[argn], "%d", &cols) != 1)
+        pm_usage(usage);
+    argn++;
+    if (argn == argc)
+        pm_usage(usage);
+    if (sscanf(argv[argn], "%d", &rows) != 1)
+        pm_usage(usage);
+
+    if (cols <= 0 || rows <= 0)
+        pm_error("picture dimensions should be positive numbers");
+    ++argn;
+
+    if (argn != argc)
+        pm_usage(usage);
+
+    destrow = pgm_allocrow(cols);
+
+    pgm_writepgminit(stdout, cols, rows, PGM_MAXMAXVAL, 0);
+
+    srand(pm_randseed());
+
+    /* create the (gray) noise */
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        for (col = 0; col < cols; ++col)
+            destrow[col] = rand() % PGM_MAXMAXVAL;
+
+        pgm_writepgmrow(stdout, destrow, cols, PGM_MAXMAXVAL, 0);
+    }
+
+    pgm_freerow(destrow);
+
+    return 0;
+}
diff --git a/generator/ppmforge.c b/generator/ppmforge.c
index 64b1ad79..80e35822 100644
--- a/generator/ppmforge.c
+++ b/generator/ppmforge.c
@@ -282,10 +282,9 @@ static unsigned int
 initseed(void) {
     /*  Generate initial random seed.  */
 
-    int i;
+    unsigned int i;
 
-    i = time(NULL) ^ 0xF37C;
-    srand(i);
+    srand(pm_randseed());
     for (i = 0; i < 7; ++i)
         rand();
     return rand();
diff --git a/generator/ppmpat.c b/generator/ppmpat.c
index 343100d5..6034b2db 100644
--- a/generator/ppmpat.c
+++ b/generator/ppmpat.c
@@ -218,14 +218,8 @@ random_color(pixval const maxval) {
 
 #define DARK_THRESH 0.25
 
-#if __STDC__
 static pixel
 random_bright_color( pixval maxval )
-#else /*__STDC__*/
-static pixel
-random_bright_color( maxval )
-    pixval maxval;
-#endif /*__STDC__*/
     {
     pixel p;
 
@@ -238,14 +232,8 @@ random_bright_color( maxval )
     return p;
     }
 
-#if __STDC__
 static pixel
 random_dark_color( pixval maxval )
-#else /*__STDC__*/
-static pixel
-random_dark_color( maxval )
-    pixval maxval;
-#endif /*__STDC__*/
     {
     pixel p;
 
@@ -313,16 +301,8 @@ gingham2( pixel** pixels, int cols, int rows, pixval maxval )
         average_drawproc, &forecolor );
     }
 
-#if __STDC__
 static void
 gingham3( pixel** pixels, int cols, int rows, pixval maxval )
-#else /*__STDC__*/
-static void
-gingham3( pixels, cols, rows, maxval )
-    pixel** pixels;
-    int cols, rows;
-    pixval maxval;
-#endif /*__STDC__*/
     {
     int colso4, rowso4;
     pixel backcolor, fore1color, fore2color;
@@ -362,16 +342,8 @@ gingham3( pixels, cols, rows, maxval )
         average_drawproc, &fore1color );
     }
 
-#if __STDC__
 static void
 madras( pixel** pixels, int cols, int rows, pixval maxval )
-#else /*__STDC__*/
-static void
-madras( pixels, cols, rows, maxval )
-    pixel** pixels;
-    int cols, rows;
-    pixval maxval;
-#endif /*__STDC__*/
     {
     int cols2, rows2, cols3, rows3, cols12, rows12, cols6a, rows6a, cols6b,
     rows6b;
@@ -493,16 +465,8 @@ madras( pixels, cols, rows, maxval )
         cols, rows3, average_drawproc, &fore2color );
     }
 
-#if __STDC__
 static void
 tartan( pixel** pixels, int cols, int rows, pixval maxval )
-#else /*__STDC__*/
-static void
-tartan( pixels, cols, rows, maxval )
-    pixel** pixels;
-    int cols, rows;
-    pixval maxval;
-#endif /*__STDC__*/
     {
     int cols1, rows1, cols3, rows3, cols10, rows10, cols5a, rows5a, cols5b,
     rows5b;
@@ -579,16 +543,8 @@ tartan( pixels, cols, rows, maxval )
 
 #define MAXPOLES 500
 
-#if __STDC__
 static void
 poles( pixel** pixels, int cols, int rows, pixval maxval )
-#else /*__STDC__*/
-static void
-poles( pixels, cols, rows, maxval )
-    pixel** pixels;
-    int cols, rows;
-    pixval maxval;
-#endif /*__STDC__*/
     {
     int poles, i, xs[MAXPOLES], ys[MAXPOLES], col, row;
     pixel colors[MAXPOLES];
@@ -730,16 +686,8 @@ sq_assign_colors(int     const circlecount,
 }
 
 
-#if __STDC__
 static void
 squig( pixel** pixels, int cols, int rows, pixval maxval )
-#else /*__STDC__*/
-static void
-squig( pixels, cols, rows, maxval )
-    pixel** pixels;
-    int cols, rows;
-    pixval maxval;
-#endif /*__STDC__*/
     {
     pixel color;
     int i, j, xc[SQ_POINTS], yc[SQ_POINTS], x0, y0, x1, y1, x2, y2, x3, y3;
@@ -1006,7 +954,7 @@ main(int argc, char ** argv) {
     if ( argn != argc )
         pm_usage( usage);
 
-    srand( (int) ( time( 0 ) ^ getpid( ) ) );
+    srand(pm_randseed());
     pixels = ppm_allocarray( cols, rows );
 
     switch ( pattern )
diff --git a/lib/Makefile b/lib/Makefile
index 704b838a..0f333c2b 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -79,8 +79,8 @@ extra_staticlib: $(EXTRA_STATICLIB)
 #----------------------------------------------------------------------------
 
 $(LIBOBJECTS): %.o: %.c importinc
-# Note that the user may have configured -I options into CFLAGS.
-	$(CC) -c $(INCLUDES) -DNDEBUG $(CFLAGS) $(CFLAGS_SHLIB) \
+# Note that the user may have configured -I options into CPPFLAGS/CFLAGS.
+	$(CC) -c $(INCLUDES) -DNDEBUG $(CPPFLAGS) $(CFLAGS) $(CFLAGS_SHLIB) \
 	  $(CFLAGS_PERSONAL) $(CADD) -o $@ $<
 
 MAJ = $(NETPBM_MAJOR_RELEASE)
diff --git a/lib/libpam.c b/lib/libpam.c
index 60d446d9..fb4dd742 100644
--- a/lib/libpam.c
+++ b/lib/libpam.c
@@ -86,24 +86,32 @@ validateComputableSize(struct pam * const pamP) {
    Another common operation is adding 1 or 2 to the highest row, column,
    or plane number in the image, so we make sure that's possible.
 -----------------------------------------------------------------------------*/
-    unsigned int const depth = allocationDepth(pamP);
-
-    if (depth > INT_MAX/sizeof(sample))
-        pm_error("image depth (%u) too large to be processed", depth);
-    else if (pamP->width > 0 && depth * sizeof(sample) > INT_MAX/pamP->width)
-        pm_error("image width and depth (%u, %u) too large "
-                 "to be processed.", pamP->width, depth);
-    else if (pamP->width * (depth * sizeof(sample)) >
-             INT_MAX - depth * sizeof(tuple *))
-        pm_error("image width and depth (%u, %u) too large "
-                 "to be processed.", pamP->width, depth);
-    
-    if (depth > INT_MAX - 2)
-        pm_error("image depth (%u) too large to be processed", depth);
-    if (pamP->width > INT_MAX - 2)
-        pm_error("image width (%u) too large to be processed", pamP->width);
-    if (pamP->height > INT_MAX - 2)
-        pm_error("image height (%u) too large to be processed", pamP->height);
+    if (pamP->width == 0)
+        pm_error("Width is zero.  Image must be at least one pixel wide");
+    else if (pamP->height == 0)
+        pm_error("Height is zero.  Image must be at least one pixel high");
+    else {
+        unsigned int const depth = allocationDepth(pamP);
+
+        if (depth > INT_MAX/sizeof(sample))
+            pm_error("image depth (%u) too large to be processed", depth);
+        else if (depth * sizeof(sample) > INT_MAX/pamP->width)
+            pm_error("image width and depth (%u, %u) too large "
+                     "to be processed.", pamP->width, depth);
+        else if (pamP->width * (depth * sizeof(sample)) >
+                 INT_MAX - depth * sizeof(tuple *))
+            pm_error("image width and depth (%u, %u) too large "
+                     "to be processed.", pamP->width, depth);
+        
+        if (depth > INT_MAX - 2)
+            pm_error("image depth (%u) too large to be processed", depth);
+        if (pamP->width > INT_MAX - 2)
+            pm_error("image width (%u) too large to be processed",
+                     pamP->width);
+        if (pamP->height > INT_MAX - 2)
+            pm_error("image height (%u) too large to be processed",
+                     pamP->height);
+    }
 }
 
 
@@ -862,13 +870,17 @@ pnm_writepaminit(struct pam * const pamP) {
                  "(%d bytes, according to its 'len' element).",
                  pamP->size, pamP->len);
 
-    if (pamP->len < PAM_STRUCT_SIZE(bytes_per_sample))
+    if (pamP->size < PAM_STRUCT_SIZE(bytes_per_sample))
         pm_error("pam object passed to pnm_writepaminit() is too small.  "
                  "It must be large\n"
                  "enough to hold at least up through the "
                  "'bytes_per_sample' member, but according\n"
-                 "to its 'len' member, it is only %d bytes long.", 
-                 pamP->len);
+                 "to its 'size' member, it is only %d bytes long.", 
+                 pamP->size);
+    if (pamP->len < PAM_STRUCT_SIZE(maxval))
+        pm_error("pam object must contain members at least through 'maxval', "
+                 "but according to the 'len' member, it is only %u bytes "
+                 "long.", pamP->len);
 
     if (pamP->maxval > PAM_OVERALL_MAXVAL)
         pm_error("maxval (%lu) passed to pnm_writepaminit() "
@@ -879,6 +891,8 @@ pnm_writepaminit(struct pam * const pamP) {
     else
         tupleType = pamP->tuple_type;
 
+    if (pamP->len < PAM_STRUCT_SIZE(bytes_per_sample))
+        pamP->len = PAM_STRUCT_SIZE(bytes_per_sample);
     pamP->bytes_per_sample = pnm_bytespersample(pamP->maxval);
     
     switch (PAM_FORMAT_TYPE(pamP->format)) {
diff --git a/lib/libpamcolor.c b/lib/libpamcolor.c
index e11415ca..ef8546b3 100644
--- a/lib/libpamcolor.c
+++ b/lib/libpamcolor.c
@@ -11,6 +11,10 @@
 #define _FILE_OFFSET_BITS 64
 #define _LARGE_FILES  
 
+#define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+
+#include <string.h>
 #include <limits.h>
 
 #include "pm_c_util.h"
@@ -44,6 +48,34 @@ pnm_parsecolor(const char * const colorname,
 
 
 
+const char *
+pnm_colorname(struct pam * const pamP,
+              tuple        const color,
+              int          const hexok) {
+
+    const char * retval;
+    pixel colorp;
+    char * colorname;
+
+    if (pamP->depth < 3)
+        PPM_ASSIGN(colorp, color[0], color[0], color[0]);
+    else 
+        PPM_ASSIGN(colorp,
+                   color[PAM_RED_PLANE],
+                   color[PAM_GRN_PLANE],
+                   color[PAM_BLU_PLANE]);
+
+    colorname = ppm_colorname(&colorp, pamP->maxval, hexok);
+
+    retval = strdup(colorname);
+    if (retval == NULL)
+        pm_error("Couldn't get memory for color name string");
+
+    return retval;
+}
+
+
+
 double pnm_lumin_factor[3] = {PPM_LUMINR, PPM_LUMING, PPM_LUMINB};
 
 void
diff --git a/lib/libpammap.c b/lib/libpammap.c
index 98c7f798..781f6f88 100644
--- a/lib/libpammap.c
+++ b/lib/libpammap.c
@@ -252,6 +252,7 @@ static void
 computehashrecoverable(struct pam *   const pamP,
                        tuple **       const tupleArray, 
                        unsigned int   const maxsize, 
+                       unsigned int   const newDepth,
                        sample         const newMaxval,
                        unsigned int * const sizeP,
                        tuplehash *    const tuplefreqhashP,
@@ -268,13 +269,16 @@ computehashrecoverable(struct pam *   const pamP,
 
     freqPam = *pamP;
     freqPam.maxval = newMaxval;
+    freqPam.depth = newDepth;
+
+    assert(freqPam.depth <= pamP->depth);
 
     *tuplefreqhashP = pnm_createtuplehash();
     *sizeP = 0;   /* initial value */
     
     *rowbufferP = pnm_allocpamrow(pamP);
     
-    *colorP = pnm_allocpamtuple(&freqPam);
+    *colorP = pnm_allocpamtuple(pamP);
     
     full = FALSE;  /* initial value */
     
@@ -313,6 +317,7 @@ static tuplehash
 computetuplefreqhash(struct pam *   const pamP,
                      tuple **       const tupleArray, 
                      unsigned int   const maxsize, 
+                     unsigned int   const newDepth,
                      sample         const newMaxval,
                      unsigned int * const sizeP) {
 /*----------------------------------------------------------------------------
@@ -335,6 +340,10 @@ computetuplefreqhash(struct pam *   const pamP,
   However, if the number of unique tuple values is greater than 'maxsize', 
   return a null return value and *sizeP undefined.
 
+  The tuple values that index the hash have depth 'newDepth'.  We look at
+  only the first 'newDepth' planes of the input.  Caler must ensure that
+  the input has at least that many planes.
+
   The tuple values that index the hash are scaled to a new maxval of
   'newMaxval'.  E.g.  if the input has maxval 100 and 'newMaxval' is
   50, and a particular tuple has sample value 50, it would be counted
@@ -366,8 +375,8 @@ computetuplefreqhash(struct pam *   const pamP,
         pm_longjmp();
     } else {
         pm_setjmpbufsave(&jmpbuf, &origJmpbufP);
-        computehashrecoverable(pamP, tupleArray, maxsize, newMaxval, sizeP,
-                               &tuplefreqhash, &rowbuffer, &color);
+        computehashrecoverable(pamP, tupleArray, maxsize, newDepth, newMaxval,
+                               sizeP, &tuplefreqhash, &rowbuffer, &color);
         pm_setjmpbuf(origJmpbufP);
     }
     return tuplefreqhash;
@@ -383,7 +392,8 @@ pnm_computetuplefreqhash(struct pam *   const pamP,
 /*----------------------------------------------------------------------------
    Compute the tuple frequency hash for the tuple array tupleArray[][].
 -----------------------------------------------------------------------------*/
-    return computetuplefreqhash(pamP, tupleArray, maxsize, pamP->maxval, 
+    return computetuplefreqhash(pamP, tupleArray, maxsize,
+                                pamP->depth, pamP->maxval, 
                                 sizeP);
 }
 
@@ -544,9 +554,10 @@ pnm_computetupletablehash(struct pam * const pamP,
 
 
 tupletable
-pnm_computetuplefreqtable2(struct pam *   const pamP,
+pnm_computetuplefreqtable3(struct pam *   const pamP,
                            tuple **       const tupleArray,
                            unsigned int   const maxsize,
+                           unsigned int   const newDepth,
                            sample         const newMaxval,
                            unsigned int * const countP) {
 /*----------------------------------------------------------------------------
@@ -573,6 +584,9 @@ pnm_computetuplefreqtable2(struct pam *   const pamP,
    Return the number of unique tuple values in tupleArray[][] as
    *countP.
 
+   The tuples in the table have depth 'newDepth'.  We look at
+   only the first 'newDepth' planes of the input.  If the input doesn't
+   have that many planes, we throw an error.
 
    Scale the tuple values to a new maxval of 'newMaxval' before
    processing them.  E.g. if the input has maxval 100 and 'newMaxval'
@@ -584,8 +598,13 @@ pnm_computetuplefreqtable2(struct pam *   const pamP,
     tupletable tuplefreqtable;
     unsigned int uniqueCount;
 
+    if (newDepth > pamP->depth)
+        pm_error("pnm_computetuplefreqtable3 called with 'newDepth' "
+                 "argument (%u) greater than input depth (%u)",
+                 newDepth, pamP->depth);
+
     tuplefreqhash = computetuplefreqhash(pamP, tupleArray, maxsize, 
-                                         newMaxval, &uniqueCount);
+                                         newDepth, newMaxval, &uniqueCount);
     if (tuplefreqhash == NULL)
         tuplefreqtable = NULL;
     else {
@@ -604,6 +623,20 @@ pnm_computetuplefreqtable2(struct pam *   const pamP,
 
 
 tupletable
+pnm_computetuplefreqtable2(struct pam *   const pamP,
+                           tuple **       const tupleArray,
+                           unsigned int   const maxsize,
+                           sample         const newMaxval,
+                           unsigned int * const countP) {
+
+    return
+        pnm_computetuplefreqtable3(pamP, tupleArray, maxsize,
+                                   pamP->depth, newMaxval, countP);
+}
+
+
+
+tupletable
 pnm_computetuplefreqtable(struct pam *   const pamP,
                           tuple **       const tupleArray,
                           unsigned int   const maxsize,
diff --git a/lib/libpgm1.c b/lib/libpgm1.c
index 5b17910a..f5d89f9c 100644
--- a/lib/libpgm1.c
+++ b/lib/libpgm1.c
@@ -381,6 +381,5 @@ pgm_check(FILE *               const file,
         pm_filepos const need_raster_size = rows * bytes_per_row;
         
         pm_check(file, check_type, need_raster_size, retval_p);
-        
     }
 }
diff --git a/lib/libpm.c b/lib/libpm.c
index df59e6c4..f36b7a50 100644
--- a/lib/libpm.c
+++ b/lib/libpm.c
@@ -35,7 +35,9 @@
 #define _LARGE_FILE_API
     /* This makes the the x64() functions available on AIX */
 
+#include <unistd.h>
 #include <stdio.h>
+#include <fcntl.h>
 #include <stdarg.h>
 #include <string.h>
 #include <errno.h>
@@ -43,6 +45,7 @@
 #ifdef __DJGPP__
   #include <io.h>
 #endif
+#include <time.h>
 
 #include "pm_c_util.h"
 #include "version.h"
@@ -782,6 +785,15 @@ pm_arg0toprogname(const char arg0[]) {
 
 
 
+unsigned int
+pm_randseed(void) {
+
+    return time(NULL) ^ getpid();
+
+}
+
+
+
 /* File open/close that handles "-" as stdin/stdout and checks errors. */
 
 FILE*
@@ -986,7 +998,7 @@ pm_make_tmpfile(FILE **       const filePP,
     const char * dirseparator;
     const char * error;
 
-    fnamelen = strlen (pm_progname) + 10; /* "/" + "_XXXXXX\0" */
+    fnamelen = strlen(pm_progname) + 10; /* "/" + "_XXXXXX\0" */
 
     tmpdir = tmpDir();
 
diff --git a/lib/libpnm3.c b/lib/libpnm3.c
index f10a7fca..4df8041c 100644
--- a/lib/libpnm3.c
+++ b/lib/libpnm3.c
@@ -21,16 +21,8 @@
 #include "pbm.h"
 #include "libpbm.h"
 
-#if __STDC__
 xel
 pnm_backgroundxel( xel** xels, int cols, int rows, xelval maxval, int format )
-#else /*__STDC__*/
-xel
-pnm_backgroundxel( xels, cols, rows, maxval, format )
-    xel** xels;
-    int cols, rows, format;
-    xelval maxval;
-#endif /*__STDC__*/
     {
     xel bgxel, ul, ur, ll, lr;
 
@@ -93,16 +85,8 @@ pnm_backgroundxel( xels, cols, rows, maxval, format )
     return bgxel;
     }
 
-#if __STDC__
 xel
 pnm_backgroundxelrow( xel* xelrow, int cols, xelval maxval, int format )
-#else /*__STDC__*/
-xel
-pnm_backgroundxelrow( xelrow, cols, maxval, format )
-    xel* xelrow;
-    int cols, format;
-    xelval maxval;
-#endif /*__STDC__*/
     {
     xel bgxel, l, r;
 
@@ -158,71 +142,57 @@ pnm_backgroundxelrow( xelrow, cols, maxval, format )
     return bgxel;
     }
 
-#if __STDC__
-xel
-pnm_whitexel( xelval maxval, int format )
-#else /*__STDC__*/
+
+
 xel
-pnm_whitexel( maxval, format )
-    xelval maxval;
-    int format;
-#endif /*__STDC__*/
-    {
-    xel x;
+pnm_whitexel(xelval const maxval,
+             int    const format) {
 
-    switch ( PNM_FORMAT_TYPE(format) )
-    {
+    xel retval;
+
+    switch (PNM_FORMAT_TYPE(format)) {
     case PPM_TYPE:
-    PPM_ASSIGN( x, maxval, maxval, maxval );
-    break;
+        PPM_ASSIGN(retval, maxval, maxval, maxval);
+        break;
 
     case PGM_TYPE:
-    PNM_ASSIGN1( x, maxval );
-    break;
-
     case PBM_TYPE:
-    PNM_ASSIGN1( x, maxval );
-    break;
+        PNM_ASSIGN1(retval, maxval);
+        break;
 
     default:
-    pm_error( "Invalid format passed to pnm_whitexel()");
+        pm_error("Invalid format %d passed to pnm_whitexel()", format);
     }
 
-    return x;
-    }
+    return retval;
+}
+
+
 
-#if __STDC__
-xel
-pnm_blackxel( xelval maxval, int format )
-#else /*__STDC__*/
 xel
-pnm_blackxel( maxval, format )
-    xelval maxval;
-    int format;
-#endif /*__STDC__*/
-    {
-    xel x;
+pnm_blackxel(xelval const maxval,
+             int    const format) {
 
-    switch ( PNM_FORMAT_TYPE(format) )
-    {
+    xel retval;
+
+    switch (PNM_FORMAT_TYPE(format)) {
     case PPM_TYPE:
-    PPM_ASSIGN( x, 0, 0, 0 );
-    break;
+        PPM_ASSIGN(retval, 0, 0, 0);
+        break;
 
     case PGM_TYPE:
-    PNM_ASSIGN1( x, (xelval) 0 );
-    break;
-
     case PBM_TYPE:
-    PNM_ASSIGN1( x, (xelval) 0 );
-    break;
+        PNM_ASSIGN1(retval, 0);
+        break;
 
     default:
-    pm_error( "Invalid format passed to pnm_blackxel(): %d", format);
+        pm_error("Invalid format %d passed to pnm_blackxel()", format);
     }
+    
+    return retval;
+}
+
 
-    return x;
-    }
 
 void
 pnm_invertxel(xel*   const xP, 
@@ -252,16 +222,8 @@ pnm_invertxel(xel*   const xP,
 
 
 
-#if __STDC__
 void
 pnm_promoteformat( xel** xels, int cols, int rows, xelval maxval, int format, xelval newmaxval, int newformat )
-#else /*__STDC__*/
-void
-pnm_promoteformat( xels, cols, rows, maxval, format, newmaxval, newformat )
-    xel** xels;
-    xelval maxval, newmaxval;
-    int cols, rows, format, newformat;
-#endif /*__STDC__*/
     {
     int row;
 
@@ -270,16 +232,8 @@ pnm_promoteformat( xels, cols, rows, maxval, format, newmaxval, newformat )
         xels[row], cols, maxval, format, newmaxval, newformat );
     }
 
-#if __STDC__
 void
 pnm_promoteformatrow( xel* xelrow, int cols, xelval maxval, int format, xelval newmaxval, int newformat )
-#else /*__STDC__*/
-void
-pnm_promoteformatrow( xelrow, cols, maxval, format, newmaxval, newformat )
-    xel* xelrow;
-    xelval maxval, newmaxval;
-    int cols, format, newformat;
-#endif /*__STDC__*/
     {
     register int col;
     register xel* xP;
@@ -409,3 +363,45 @@ pnm_xeltopixel(xel const inputxel,
 
     return outputpixel;
 }
+
+
+
+xel
+pnm_parsecolorxel(const char * const colorName,
+                  xelval       const maxval,
+                  int          const format) {
+
+    pixel const bgColor = ppm_parsecolor(colorName, maxval);
+
+    xel retval;
+
+    switch(PNM_FORMAT_TYPE(format)) {
+    case PPM_TYPE:
+        PNM_ASSIGN(retval,
+                   PPM_GETR(bgColor), PPM_GETG(bgColor), PPM_GETB(bgColor));
+        break;
+    case PGM_TYPE:
+        if (PPM_ISGRAY(bgColor))
+            PNM_ASSIGN1(retval, PPM_GETB(bgColor));
+        else
+            pm_error("Non-gray color '%s' specified for a "
+                     "grayscale (PGM) image",
+                     colorName);
+                   break;
+    case PBM_TYPE:
+        if (PPM_EQUAL(bgColor, ppm_whitepixel(maxval)))
+            PNM_ASSIGN1(retval, maxval);
+        else if (PPM_EQUAL(bgColor, ppm_blackpixel()))
+            PNM_ASSIGN1(retval, 0);
+        else
+            pm_error ("Color '%s', which is neither black nor white, "
+                      "specified for a black and white (PBM) image",
+                      colorName);
+        break;
+    default:
+        pm_error("Invalid format code %d passed to pnm_parsecolorxel()",
+                 format);
+    }
+    
+    return retval;
+}
diff --git a/lib/libppmcmap.c b/lib/libppmcmap.c
index c1243cb6..954488d7 100644
--- a/lib/libppmcmap.c
+++ b/lib/libppmcmap.c
@@ -774,15 +774,7 @@ ppm_findclosestcolor(const pixel * const colormap,
 
 
 void
-#if __STDC__
 ppm_colorrowtomapfile(FILE *ofp, pixel *colormap, int ncolors, pixval maxval)
-#else
-ppm_colorrowtomapfile(ofp, colormap, ncolors, maxval)
-    FILE *ofp;
-    pixel *colormap;
-    int ncolors;
-    pixval maxval;
-#endif
 {
     int i;
 
diff --git a/lib/libppmcolor.c b/lib/libppmcolor.c
index 06b6776c..7e324185 100644
--- a/lib/libppmcolor.c
+++ b/lib/libppmcolor.c
@@ -145,8 +145,8 @@ parseHexDigits(const char *   const string,
     unsigned int digitCount;
     pixval n;
     
-    digitCount = 0;
-    n = 0;
+    digitCount = 0;  /* initial value */
+    n = 0;           /* initial value */
     while (string[digitCount] != delim) {
         char const digit = string[digitCount];
         if (digit == '\0')
@@ -399,13 +399,13 @@ ppm_parsecolor(const char * const colorname,
 
 
 
-char*
-ppm_colorname(const pixel* const colorP, 
-              pixval       const maxval, 
-              int          const hexok)   {
+char *
+ppm_colorname(const pixel * const colorP, 
+              pixval        const maxval, 
+              int           const hexok)   {
 
     int r, g, b;
-    FILE* f;
+    FILE * f;
     static char colorname[200];
 
     if (maxval == 255) {
@@ -445,8 +445,7 @@ ppm_colorname(const pixel* const colorP,
        hex specifier, so return that.
     */
     sprintf(colorname, "#%02x%02x%02x", r, g, b);
-    return colorname;
-}
+    return colorname;}
 
 
 
diff --git a/lib/libppmd.c b/lib/libppmd.c
index ac8b6dee..a6ff0059 100644
--- a/lib/libppmd.c
+++ b/lib/libppmd.c
@@ -941,12 +941,7 @@ static int extleft, exttop, extright, extbottom;  /* To accumulate extents */
 /*  ISIN  --  Return sine of an angle in integral degrees.  The
           value returned is 65536 times the sine.  */
 
-#if __STDC__
 static long isin(int deg)
-#else
-    static long isin(deg)
-    int deg;
-#endif
 {
     /* Domain reduce to 0 to 360 degrees. */
 
@@ -971,12 +966,7 @@ static long isin(int deg)
 /*  ICOS  --  Return cosine of an angle in integral degrees.  The
           value returned is 65536 times the cosine.  */
 
-#if __STDC__
 static long icos(int deg)
-#else
-    static long icos(deg)
-    int deg;
-#endif
 {
     return isin(deg + 90);
 }  
diff --git a/lib/libppmfloyd.c b/lib/libppmfloyd.c
index 071c3c36..ec6256ff 100644
--- a/lib/libppmfloyd.c
+++ b/lib/libppmfloyd.c
@@ -85,35 +85,36 @@ allocateFi(int const cols) {
 
 
 ppm_fs_info *
-ppm_fs_init(int cols, pixval maxval, int flags) {
+ppm_fs_init(unsigned int const cols,
+            pixval       const maxval,
+            unsigned int const flags) {
 
-    ppm_fs_info *fi;
+    ppm_fs_info * fiP;
     
-    fi = allocateFi(cols);
+    fiP = allocateFi(cols);
 
-    fi->lefttoright = 1;
-    fi->cols = cols;
-    fi->maxval = maxval;
-    fi->flags = flags;
-    
-    if( flags & FS_RANDOMINIT ) {
+    fiP->lefttoright = 1;
+    fiP->cols        = cols;
+    fiP->maxval      = maxval;
+    fiP->flags       = flags;
+
+    if (flags & FS_RANDOMINIT) {
         unsigned int i;
-        srand((int)(time(0) ^ getpid()));
-        for( i = 0; i < cols +2; i++ ) {
+        srand(pm_randseed());
+        for (i = 0; i < cols +2; ++i) {
             /* random errors in [-1..+1] */
-            fi->thisrederr[i]   = rand() % 32 - 16;
-            fi->thisgreenerr[i] = rand() % 32 - 16;
-            fi->thisblueerr[i]  = rand() % 32 - 16;
+            fiP->thisrederr[i]   = rand() % 32 - 16;
+            fiP->thisgreenerr[i] = rand() % 32 - 16;
+            fiP->thisblueerr[i]  = rand() % 32 - 16;
         }
-    }
-    else {
+    } else {
         unsigned int i;
 
-        for( i = 0; i < cols + 2; i++ )
-            fi->thisrederr[i] = fi->thisgreenerr[i] = 
-                fi->thisblueerr[i] = 0;
+        for (i = 0; i < cols + 2; ++i)
+            fiP->thisrederr[i] = fiP->thisgreenerr[i] = 
+                fiP->thisblueerr[i] = 0;
     }
-    return fi;
+    return fiP;
 }
 
 
diff --git a/lib/libsystem.c b/lib/libsystem.c
index 560f0a9c..59e05a5f 100644
--- a/lib/libsystem.c
+++ b/lib/libsystem.c
@@ -84,21 +84,21 @@ createPipeFeeder(void          pipeFeederRtn(int, void *),
    other end of the pipe as *fdP.
 -----------------------------------------------------------------------------*/
     int pipeToFeed[2];
-    pid_t feederPid;
+    pid_t rc;
 
     pipe(pipeToFeed);
-    feederPid = fork();
-    if (feederPid < 0) {
+    rc = fork();
+    if (rc < 0) {
         pm_error("fork() of stdin feeder failed.  errno=%d (%s)", 
                  errno, strerror(errno));
-    } else if (feederPid == 0) {
+    } else if (rc == 0) {
         /* This is the child -- the stdin feeder process */
         close(pipeToFeed[0]);
         (*pipeFeederRtn)(pipeToFeed[1], feederParm);
         exit(0);
-    }
-    else {
+    } else {
         /* This is the parent */
+        pid_t const feederPid = rc;
         close(pipeToFeed[1]);
         *fdP = pipeToFeed[0];
         *pidP = feederPid;
@@ -120,15 +120,15 @@ spawnProcessor(const char * const shellCommand,
    from which Caller can suck the shell's Standard Output.
 -----------------------------------------------------------------------------*/
     int stdoutpipe[2];
-    pid_t processorpid;
+    pid_t rc;
         
     pipe(stdoutpipe);
 
-    processorpid = fork();
-    if (processorpid < 0) {
+    rc = fork();
+    if (rc < 0) {
         pm_error("fork() of processor process failed.  errno=%d (%s)\n", 
                  errno, strerror(errno));
-    } else if (processorpid == 0) {
+    } else if (rc == 0) {
         /* The second child */
         close(stdoutpipe[0]);
 
@@ -139,6 +139,7 @@ spawnProcessor(const char * const shellCommand,
         pm_error("INTERNAL ERROR: execProgram() returns.");
     } else {
         /* The parent */
+        pid_t const processorpid = rc;
         close(stdoutpipe[1]);
         *stdoutFdP = stdoutpipe[0];
         *pidP = processorpid;
@@ -212,11 +213,11 @@ pm_system(void stdinFeeder(int, void *),
 
        If 'stdoutFeeder' is non-NULL, we create a child process to run
        the shell and create a pipe between the shell's Standard Output
-       and this process, and then this process runs 'stdoutAccepter'
-       to read the data from that pipe.
+       and the current process, and then the current process runs
+       'stdoutAccepter' to read the data from that pipe.
        
-       But if 'stdoutFeeder' is NULL, we just run the shell in this
-       process.
+       But if 'stdoutFeeder' is NULL, we just run the shell in the
+       current process.
 
        So there can be 1, 2, or 3 processes involved depending on 
        parameters.
diff --git a/lib/pam.h b/lib/pam.h
index 97d5b3cb..e66b831d 100644
--- a/lib/pam.h
+++ b/lib/pam.h
@@ -23,16 +23,16 @@ typedef unsigned long sample;
     */
 
 struct pam {
-/* This structure describes an open PAM image file.  It consists
-   entirely of information that belongs in the header of a PAM image
-   and filesystem information.  It does not contain any state
-   information about the processing of that image.  
-
-   This is not considered to be an opaque object.  The user of Netbpm
-   libraries is free to access and set any of these fields whenever
-   appropriate.  The structure exists to make coding of function calls
-   easy.
-*/
+    /* This structure describes an open PAM image file.  It consists
+       entirely of information that belongs in the header of a PAM image
+       and filesystem information.  It does not contain any state
+       information about the processing of that image.  
+       
+       This is not considered to be an opaque object.  The user of Netbpm
+       libraries is free to access and set any of these fields whenever
+       appropriate.  The structure exists to make coding of function calls
+       easy.
+    */
 
     /* 'size' and 'len' are necessary in order to provide forward and
        backward compatibility between library functions and calling programs
@@ -44,7 +44,9 @@ struct pam {
         /* The length, in bytes, of the information in this structure.
            The information starts in the first byte and is contiguous.  
            This cannot be greater than 'size'
-           */
+
+           Use PAM_STRUCT_SIZE() to compute or interpret a value for this.
+        */
     FILE * file;
     int format;
         /* The format code of the raw image.  This is PAM_FORMAT
@@ -52,7 +54,7 @@ struct pam {
            image.  Then it's PBM_FORMAT, RPBM_FORMAT, etc.
            */
     unsigned int plainformat;
-        /* Logical: On output, use the plain version of the format type
+        /* Logical: On output, use plain version of the format type
            indicated by 'format'.  Otherwise, use the raw version.
            (i.e., on output, the plainness information in 'format' is
            irrelevant).  Input functions set this to FALSE, for the
@@ -102,7 +104,7 @@ struct pam {
 
            On output, NULL means no comments.
 
-           On input, libnetpbm mallocs storage for the comments and placed
+           On input, libnetpbm mallocs storage for the comments and places
            the pointer at *comment_p.  Caller must free it.  NULL means
            libnetpbm does not return comments and does not allocate any
            storage.
@@ -452,6 +454,11 @@ tuple
 pnm_parsecolor(const char * const colorname,
                sample       const maxval);
 
+const char *
+pnm_colorname(struct pam * const pamP,
+              tuple        const color,
+              int          const hexok);
+
 extern double 
 pnm_lumin_factor[3];
 
diff --git a/lib/pammap.h b/lib/pammap.h
index fa054deb..f11b1d7a 100644
--- a/lib/pammap.h
+++ b/lib/pammap.h
@@ -96,6 +96,14 @@ pnm_computetuplefreqtable2(struct pam *   const pamP,
                            sample         const newMaxval,
                            unsigned int * const sizeP);
 
+tupletable
+pnm_computetuplefreqtable3(struct pam *   const pamP,
+                           tuple **       const tupleArray,
+                           unsigned int   const maxsize,
+                           unsigned int   const newDepth,
+                           sample         const newMaxval,
+                           unsigned int * const countP);
+
 tuplehash
 pnm_computetuplefreqhash(struct pam *   const pamP,
                          tuple **       const tupleArray,
diff --git a/lib/pm.h b/lib/pm.h
index 3850943c..8265c9ea 100644
--- a/lib/pm.h
+++ b/lib/pm.h
@@ -348,6 +348,9 @@ pm_check(FILE *               const file,
 char *
 pm_arg0toprogname(const char arg0[]);
 
+unsigned int
+pm_randseed(void);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/pnm.h b/lib/pnm.h
index ed6983f4..94d4ff85 100644
--- a/lib/pnm.h
+++ b/lib/pnm.h
@@ -100,13 +100,13 @@ pnm_writepnm(FILE * const fileP,
              int    const forceplain);
 
 xel 
-pnm_backgroundxel (xel** xels, int cols, int rows, xelval maxval, int format);
+pnm_backgroundxel(xel** xels, int cols, int rows, xelval maxval, int format);
 
 xel 
-pnm_backgroundxelrow (xel* xelrow, int cols, xelval maxval, int format);
+pnm_backgroundxelrow(xel* xelrow, int cols, xelval maxval, int format);
 
 xel 
-pnm_whitexel (xelval maxval, int format);
+pnm_whitexel(xelval maxval, int format);
 
 xel 
 pnm_blackxel(xelval maxval, int format);
@@ -127,6 +127,11 @@ pixel
 pnm_xeltopixel(xel const inputxel,
                int const format);
 
+xel
+pnm_parsecolorxel(const char * const colorName,
+                  xelval       const maxval,
+                  int          const format);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/ppm.h b/lib/ppm.h
index 622d3e09..7f7d6446 100644
--- a/lib/ppm.h
+++ b/lib/ppm.h
@@ -58,7 +58,22 @@ typedef struct {
   ((f) == PPM_FORMAT || (f) == RPPM_FORMAT ? PPM_TYPE : PGM_FORMAT_TYPE(f))
 
 
-/* Declarations of routines. */
+static __inline__ pixel
+ppm_whitepixel(pixval maxval) {
+
+    pixel retval;
+    PPM_ASSIGN(retval, maxval, maxval, maxval);
+
+    return retval;
+}
+
+static __inline__ pixel
+ppm_blackpixel(void) {
+
+    pixel const retval = {0, 0, 0};
+
+    return retval;
+}
 
 void ppm_init(int * argcP, char* argv[]);
 
diff --git a/lib/ppmdraw.h b/lib/ppmdraw.h
index 6a379573..a3c4f831 100644
--- a/lib/ppmdraw.h
+++ b/lib/ppmdraw.h
@@ -59,7 +59,7 @@ typedef struct {
 
 
 
-typedef void ppmd_drawproc(pixel ** const, int const, int const, pixval const, int const, int const, const void *const);
+typedef void ppmd_drawproc(pixel **, int, int, pixval, int, int, const void *);
 
 ppmd_drawproc ppmd_point_drawproc;
 
@@ -265,17 +265,17 @@ ppmd_fill(pixel **         const pixels,
 /* Text drawing routines. */
 
 void
-ppmd_text(pixel**      const pixels, 
-          int          const cols, 
-          int          const rows, 
-          pixval       const maxval, 
-          int          const xpos, 
-          int          const ypos, 
-          int          const height, 
-          int          const angle, 
-          const char * const sArg, 
-	  ppmd_drawproc,
-    const void*  const clientdata);
+ppmd_text(pixel**       const pixels, 
+          int           const cols, 
+          int           const rows, 
+          pixval        const maxval, 
+          int           const xpos, 
+          int           const ypos, 
+          int           const height, 
+          int           const angle, 
+          const char *  const sArg, 
+          ppmd_drawproc       drawProc,
+          const void *  const clientdata);
 /* Draws the null-terminated string 's' left justified at the point
    ('x', 'y').  The text will be 'height' pixels high and will be aligned on a
    baseline inclined 'angle' degrees with the X axis.  The supplied
diff --git a/lib/ppmfloyd.h b/lib/ppmfloyd.h
index e16ad651..264fc0b6 100644
--- a/lib/ppmfloyd.h
+++ b/lib/ppmfloyd.h
@@ -15,17 +15,17 @@ struct ppm_fs_info {
     /* thisXerr and nextXerr are dynamically allocated arrays each of whose
        dimension is the width of the image plus 2
        */
-    long *thisrederr;
-    long *thisgreenerr;
-    long *thisblueerr;
-    long *nextrederr;
-    long *nextgreenerr;
-    long *nextblueerr;
+    long * thisrederr;
+    long * thisgreenerr;
+    long * thisblueerr;
+    long * nextrederr;
+    long * nextgreenerr;
+    long * nextblueerr;
     int lefttoright;
     int cols;
     pixval maxval;
     int flags;
-    pixel *pixrow;
+    pixel * pixrow;
     int col_end;
     pixval red, green, blue;
 };
@@ -37,7 +37,9 @@ typedef struct ppm_fs_info ppm_fs_info;
 #define FS_ALTERNATE  0x02
 
 ppm_fs_info *
-ppm_fs_init(int cols, pixval maxval, int flags);
+ppm_fs_init(unsigned int const cols,
+            pixval       const maxval,
+            unsigned int const flags);
 
 void
 ppm_fs_free(ppm_fs_info *fi);
diff --git a/lib/util/Makefile b/lib/util/Makefile
index ffa1db5b..d770555f 100644
--- a/lib/util/Makefile
+++ b/lib/util/Makefile
@@ -20,7 +20,7 @@ include $(SRCDIR)/Makefile.common
 INCLUDES = -I $(BUILDDIR) -I $(SRCDIR)/$(SUBDIR)/..
 
 $(UTILOBJECTS):%.o:%.c importinc
-	$(CC) -c $(INCLUDES) -DNDEBUG $(CFLAGS) $(CFLAGS_SHLIB) \
+	$(CC) -c $(INCLUDES) -DNDEBUG $(CPPFLAGS) $(CFLAGS) $(CFLAGS_SHLIB) \
 	  $(CFLAGS_PERSONAL) $(CADD) -o $@ $<
 
 testnstring: test.c nstring.h nstring.o
diff --git a/lib/util/wordaccess.h b/lib/util/wordaccess.h
index 28963aee..08034361 100644
--- a/lib/util/wordaccess.h
+++ b/lib/util/wordaccess.h
@@ -37,6 +37,9 @@
 
    We also assume that a char is 8 bits.
 */
+
+#include "pm_config.h"
+
 #if (!defined(WORDACCESS_GENERIC) \
      && defined(__GNUC__) && defined(__GLIBC__) \
      && (__GNUC__ * 100 + __GNUC_MINOR__ >= 304) )
diff --git a/lib/util/wordaccess_64_le.h b/lib/util/wordaccess_64_le.h
index 2343b6d4..83bbf2bf 100644
--- a/lib/util/wordaccess_64_le.h
+++ b/lib/util/wordaccess_64_le.h
@@ -15,6 +15,8 @@
 */
 
 #include <byteswap.h>  /* See note above on bswap_64 */
+
+#include "pm.h"
  
 typedef uint64_t wordint;
 typedef unsigned char wordintBytes[sizeof(wordint)];
diff --git a/lib/util/wordaccess_gcc3_le.h b/lib/util/wordaccess_gcc3_le.h
index 7db218db..798566af 100644
--- a/lib/util/wordaccess_gcc3_le.h
+++ b/lib/util/wordaccess_gcc3_le.h
@@ -15,6 +15,8 @@ typedef unsigned char wordintBytes[sizeof(wordint)];
 #include <sys/types.h>
 #include <netinet/in.h>
 
+#include "pm.h"
+
 /*
   Here we use the more widely used functions htonl and ntohl instead of
   bswap_32.  This makes possible the handling of weird byte ordering
diff --git a/other/pamx/Makefile2 b/other/pamx/Makefile2
deleted file mode 100644
index f69e103f..00000000
--- a/other/pamx/Makefile2
+++ /dev/null
@@ -1,51 +0,0 @@
-# C compiler to use, including special flags.
-CC=gcc
-
-WARNINGS = -Wall -Wmissing-declarations -Wundef -Wimplicit -Wwrite-strings \
-	-Winline \
-	-Wstrict-prototypes -Wmissing-prototypes \
-	-Werror
-
-CFLAGS = $(WARNINGS) -fno-common -g
-INCLUDES = -I /home/bryanh/netpbm/other/importinc
-
-# X11 include and library information.
-X11_LIB_DIR=-L/subsysx/X11R6/lib
-X11_LIB_NAME=-lX11
-NETPBMLIB = /home/bryanh/netpbm/lib/libnetpbm.so
-
-LIBS=$(X11_LIB_DIR) $(X11_LIB_NAME) -lm
-
-default: pamx
-
-# files for the image library
-IMAGE_SRCS= image.c
-IMAGE_OBJS= ${IMAGE_SRCS:.c=.o}
-
-# files for the image processing library
-PROCESS_HDRS=
-# no image processing.
-PROCESS_SRCS= fill.c
-PROCESS_OBJS= ${PROCESS_SRCS:.c=.o}
-
-X_SRCS= send.c window.c pamx.c
-X_OBJS= ${X_SRCS:.c=.o}
-
-OBJS= $(IMAGE_OBJS) $(PROCESS_OBJS) $(X_OBJS) $(NETPBMLIB)
-
-.c.o: $*.c
-	$(CC) -c $(CFLAGS) $(INCLUDES) $*.c $(CADD)
-
-pamx: $(OBJS) $(OPTIONAL_LIBS)
-	$(CC) -o $@ $(OBJS) $(OPTIONAL_LIBS) $(LIBS)
-
-clean::
-	rm -f *.o pamx
-
-dep:
-	$(CC) -MM -MG $(INCLUDES) *.c >Makefile.depend
-
-include Makefile.depend
-
-Makefile.depend:
-	>$@
diff --git a/other/pamx/image.c b/other/pamx/image.c
index 892a9768..0e719438 100644
--- a/other/pamx/image.c
+++ b/other/pamx/image.c
@@ -237,95 +237,3 @@ freeImage(Image * const imageP) {
 
     free(imageP);
 }
-
-
-
-
-static void
-fillRow1(struct pam *     const pamP,
-         tuple *          const tuplerow,
-         unsigned char ** const pP) {
-
-    unsigned int col;
-    
-    for (col = 0; col < pamP->width; ++col) {
-        unsigned int plane;
-        for (plane = 0; plane < pamP->depth; ++plane)
-            *(*pP)++ =
-                pnm_scalesample(tuplerow[col][0], pamP->maxval, 255);
-    }
-}
-
-
-
-static void
-fillRow3(struct pam *     const pamP,
-         tuple *          const tuplerow,
-         unsigned char ** const pP) {
-
-    unsigned int col;
-    
-    for (col = 0; col < pamP->width; ++col) {
-        unsigned int plane;
-        for (plane = 0; plane < pamP->depth; ++plane)
-            *(*pP)++ =
-                pnm_scalesample(tuplerow[col][plane], pamP->maxval, 255);
-    }
-}
-
-
-
-Image *
-pbmLoad(const char * const fullname,
-        const char * const name,
-        bool         const verbose) {
-
-    FILE * ifP;
-    struct pam pam;
-    Image * imageP;
-    unsigned int row;
-    const char * filename;
-    tuple * tuplerow;
-    unsigned char * p;
-    enum {DEPTH_1, DEPTH_3} depth;
-
-    if (STREQ(fullname, "stdin"))
-        filename = "-";
-    else
-        filename = fullname;
-
-    ifP = pm_openr(filename);
-
-    pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
-
-    if (strncmp(pam.tuple_type, "RGB", 3) == 0) {
-        depth = DEPTH_3;
-        if (pam.depth < 3)
-            pm_error("Invalid depth %u for RGB tuple type.", pam.depth);
-    } else
-        depth = DEPTH_1;
-
-    imageP = newTrueImage(pam.width, pam.height);
-
-    p = &imageP->data[0];  /* initial value */
-
-    tuplerow = pnm_allocpamrow(&pam);
-
-    for (row = 0; row < pam.height; ++row) {
-        pnm_readpamrow(&pam, tuplerow);
-        
-        switch (depth) {
-        case DEPTH_3:
-            fillRow3(&pam, tuplerow, &p);
-            break;
-        case DEPTH_1:
-            fillRow1(&pam, tuplerow, &p);
-            break;
-        }
-    }
-    pnm_freepamrow(tuplerow);
-    
-    pm_close(ifP);
-
-    return imageP;
-}
diff --git a/other/pamx/image.h b/other/pamx/image.h
index 9c9689ac..32a48c5a 100644
--- a/other/pamx/image.h
+++ b/other/pamx/image.h
@@ -82,9 +82,4 @@ colorIntensity(unsigned int const red,
             BlueIntensity[blu / 256]);
 }
 
-Image *
-pbmLoad(const char * const fullname,
-        const char * const name,
-        bool         const verbose);
-
 #endif
diff --git a/other/pamx/pamx.c b/other/pamx/pamx.c
index 17980643..c6503d5e 100644
--- a/other/pamx/pamx.c
+++ b/other/pamx/pamx.c
@@ -175,35 +175,32 @@ errorHandler(Display *     const disp,
 
 
 
-static void
-fillRow1(struct pam *     const pamP,
-         tuple *          const tuplerow,
-         unsigned char ** const pP) {
-
-    unsigned int col;
-    
-    for (col = 0; col < pamP->width; ++col) {
-        unsigned int plane;
-        for (plane = 0; plane < 3; ++plane)
-            *(*pP)++ =
-                pnm_scalesample(tuplerow[col][0], pamP->maxval, 255);
-    }
-}
-
-
+enum usableDepth {DEPTH_1, DEPTH_3};
 
 static void
-fillRow3(struct pam *     const pamP,
-         tuple *          const tuplerow,
-         unsigned char ** const pP) {
+fillRow(struct pam *     const pamP,
+        tuple *          const tuplerow,
+        enum usableDepth const depth,
+        unsigned char ** const pP) {
+/*----------------------------------------------------------------------------
+   Add one row to the 24-bit truecolor image data at *pP, and advance
+   *pP just past that row.
 
+   Use either the first plane or the first 3 planes of tuplerow[]
+   for its contents, according to 'depth'.
+-----------------------------------------------------------------------------*/
     unsigned int col;
     
     for (col = 0; col < pamP->width; ++col) {
+        /* Truecolor image data has 3 bytes per pixel, one each for
+           red, green, and blue.
+        */
         unsigned int plane;
-        for (plane = 0; plane < pamP->depth; ++plane)
+        for (plane = 0; plane < 3; ++plane) {
+            unsigned int const tuplePlane = depth == DEPTH_3 ? plane : 0;
             *(*pP)++ =
-                pnm_scalesample(tuplerow[col][plane], pamP->maxval, 255);
+                pnm_scalesample(tuplerow[col][tuplePlane], pamP->maxval, 255);
+        }
     }
 }
 
@@ -218,7 +215,7 @@ loadPamImage(FILE *   const ifP,
     unsigned int row;
     tuple * tuplerow;
     unsigned char * p;
-    enum {DEPTH_1, DEPTH_3} depth;
+    enum usableDepth depth;
 
     pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
 
@@ -238,12 +235,17 @@ loadPamImage(FILE *   const ifP,
     for (row = 0; row < pam.height; ++row) {
         pnm_readpamrow(&pam, tuplerow);
         
+        /* This semantically wasteful code allows a dumb compiler
+           optimizer to recognize that the depth is constant and
+           therefore not generate code that checks the depth every
+           time it processes a sample.
+        */
         switch (depth) {
         case DEPTH_3:
-            fillRow3(&pam, tuplerow, &p);
+            fillRow(&pam, tuplerow, DEPTH_3, &p);
             break;
         case DEPTH_1:
-            fillRow1(&pam, tuplerow, &p);
+            fillRow(&pam, tuplerow, DEPTH_1, &p);
             break;
         }
     }
diff --git a/other/ppmsvgalib.c b/other/ppmsvgalib.c
index 67cc2b1a..f607d047 100644
--- a/other/ppmsvgalib.c
+++ b/other/ppmsvgalib.c
@@ -249,7 +249,7 @@ main(int argc, char *argv[]) {
     int format;
     int rc;
 
-    ppm_init( &argc, argv );
+    ppm_init(&argc, argv);
 
     rc = vga_init();         /* Initialize. */
     if (rc < 0)
diff --git a/pm_config.in.h b/pm_config.in.h
index 1956f5d3..25551815 100644
--- a/pm_config.in.h
+++ b/pm_config.in.h
@@ -119,33 +119,6 @@ extern int rand();
 typedef uint32_t uint32n;
 typedef int32_t int32n;
 
-#include <fcntl.h>
-#include <time.h>
-#include <stdlib.h>
-#include <unistd.h>
-/* 
-   Before Netpbm 9.0, atoi() and exit() were declared for everybody
-   except MSDOS and Amiga, and time() and write() were declared for
-   everybody except MSDOS, Amiga, and __osf__.  fcntl.h, time.h, and
-   stlib.h were included for MSDOS and Amiga, and unistd.h was included
-   for everyone except VMS, MSDOS, and Amiga.  With the netbsd patches,
-   atoi(), exit(), time(), and write() were not declared for __NetBSD__.
-
-   We're hoping that all current systems have the standard header
-   files, and will reinstate some of these explicit declarations if we
-   hear otherwise.  
-
-   If it turns out to be this easy, we should just move these inclusions
-   to the source files that actually need them.
-   
-   -Bryan 2000.04.13
-
-extern int atoi();
-extern void exit();
-extern long time();
-extern int write(); 
-*/
-
 /* CONFIGURE: On most BSD systems, malloc() gets declared in stdlib.h, on
 ** system V, it gets declared in malloc.h. On some systems, malloc.h
 ** doesn't declare these, so we have to do it here. On other systems,
@@ -263,6 +236,8 @@ extern int write();
 # endif
 #endif
 
+#include <unistd.h>  /* Get _LFS_LARGEFILE defined */
+#include <sys/types.h>
 /* In GNU, _LFS_LARGEFILE means the "off_t" functions (ftello, etc.) are
    available.  In AIX, _AIXVERSION_430 means it's AIX Version 4.3.0 or
    better, which seems to mean the "off_t" functions are available.
diff --git a/urt/Makefile b/urt/Makefile
index 04dd2913..930cae6c 100644
--- a/urt/Makefile
+++ b/urt/Makefile
@@ -24,7 +24,8 @@ librle.a: $(LIBOBJECTS)
 
 # Rule for objects.
 $(LIBOBJECTS): %.o: %.c importinc
-	$(CC) -c $(CFLAGS) -I importinc -o $@ $< $(CFLAGS_PERSONAL) $(CADD)
+	$(CC) -c $(CPPFLAGS) $(CFLAGS) -I importinc -o $@ \
+	  $< $(CFLAGS_PERSONAL) $(CADD)
 
 BINARIES =
 SCRIPTS =